Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Count Expressions #4530

Merged
merged 17 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion exist-core/src/main/antlr/org/exist/xquery/parser/XQuery.g
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ options {
return buf.toString();
}

public Exception getLastException() {
return (Exception) exceptions.get(exceptions.size() - 1);
}

public String getXQDoc() {
return lexer.getXQDoc();
}
Expand Down Expand Up @@ -802,14 +806,21 @@ initialClause throws XPathException

intermediateClause throws XPathException
:
( initialClause | whereClause | groupByClause | orderByClause )
( initialClause | whereClause | groupByClause | orderByClause | countClause )
;

whereClause throws XPathException
:
"where"^ exprSingle
;

countClause throws XPathException
{ String varName; }
:
"count"^ DOLLAR! varName=varName!
{ #countClause = #(#countClause, #[VARIABLE_BINDING, varName]); }
;

forClause throws XPathException
:
"for"^ inVarBinding ( COMMA! inVarBinding )*
Expand Down Expand Up @@ -2223,6 +2234,8 @@ reservedKeywords returns [String name]
|
"array" { name = "array"; }
|
"count" { name = "count"; }
|
"copy-namespaces" { name = "copy-namespaces"; }
|
"empty-sequence" { name = "empty-sequence"; }
Expand Down
86 changes: 64 additions & 22 deletions exist-core/src/main/antlr/org/exist/xquery/parser/XQueryTree.g
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ options {

private static class ForLetClause {
XQueryAST ast;
String varName;
QName varName;
SequenceType sequenceType= null;
String posVar= null;
QName posVar = null;
Expression inputSequence;
Expression action;
FLWORClause.ClauseType type = FLWORClause.ClauseType.FOR;
Expand Down Expand Up @@ -1398,7 +1398,11 @@ throws PermissionDeniedException, EXistException, XPathException
)?
step=expr[inputSequence]
{
clause.varName= someVarName.getText();
try {
clause.varName = QName.parse(staticContext, someVarName.getText(), null);
} catch (final IllegalQNameException iqe) {
throw new XPathException(someVarName.getLine(), someVarName.getColumn(), ErrorCodes.XPST0081, "No namespace defined for prefix " + someVarName.getText());
}
clause.inputSequence= inputSequence;
clauses.add(clause);
}
Expand Down Expand Up @@ -1449,7 +1453,11 @@ throws PermissionDeniedException, EXistException, XPathException
)?
step=expr[inputSequence]
{
clause.varName= everyVarName.getText();
try {
clause.varName = QName.parse(staticContext, everyVarName.getText(), null);
} catch (final IllegalQNameException iqe) {
throw new XPathException(everyVarName.getLine(), everyVarName.getColumn(), ErrorCodes.XPST0081, "No namespace defined for prefix " + everyVarName.getText());
}
clause.inputSequence= inputSequence;
clauses.add(clause);
}
Expand Down Expand Up @@ -1585,11 +1593,21 @@ throws PermissionDeniedException, EXistException, XPathException
)?
(
posVar:POSITIONAL_VAR
{ clause.posVar= posVar.getText(); }
{
try {
clause.posVar = QName.parse(staticContext, posVar.getText(), null);
} catch (final IllegalQNameException iqe) {
throw new XPathException(posVar.getLine(), posVar.getColumn(), ErrorCodes.XPST0081, "No namespace defined for prefix " + posVar.getText());
}
}
)?
step=expr [inputSequence]
{
clause.varName= varName.getText();
try {
clause.varName = QName.parse(staticContext, varName.getText(), null);
} catch (final IllegalQNameException iqe) {
throw new XPathException(varName.getLine(), varName.getColumn(), ErrorCodes.XPST0081, "No namespace defined for prefix " + varName.getText());
}
clause.inputSequence= inputSequence;
clauses.add(clause);
}
Expand Down Expand Up @@ -1618,7 +1636,11 @@ throws PermissionDeniedException, EXistException, XPathException
)?
step=expr [inputSequence]
{
clause.varName= letVarName.getText();
try {
clause.varName = QName.parse(staticContext, letVarName.getText(), null);
} catch (final IllegalQNameException iqe) {
throw new XPathException(letVarName.getLine(), letVarName.getColumn(), ErrorCodes.XPST0081, "No namespace defined for prefix " + letVarName.getText());
}
clause.inputSequence= inputSequence;
clauses.add(clause);
}
Expand Down Expand Up @@ -1752,29 +1774,49 @@ throws PermissionDeniedException, EXistException, XPathException
clauses.add(clause);
}
)
)+
step=expr [(PathExpr) action]
{
|
#(
co:"count"
countVarName:VARIABLE_BINDING
{
ForLetClause clause = new ForLetClause();
clause.ast = co;
try {
clause.varName = QName.parse(staticContext, countVarName.getText(), null);
} catch (final IllegalQNameException iqe) {
throw new XPathException(countVarName.getLine(), countVarName.getColumn(), ErrorCodes.XPST0081, "No namespace defined for prefix " + countVarName.getText());
}
clause.type = FLWORClause.ClauseType.COUNT;
clause.inputSequence = null;
clauses.add(clause);
}
)
)+
step=expr [(PathExpr) action]
{
for (int i= clauses.size() - 1; i >= 0; i--) {
ForLetClause clause= (ForLetClause) clauses.get(i);
FLWORClause expr;
switch (clause.type) {
case LET:
expr= new LetExpr(context);
expr = new LetExpr(context);
expr.setASTNode(expr_AST_in);
break;
case GROUPBY:
expr = new GroupByClause(context);
break;
case ORDERBY:
expr = new OrderByClause(context, clause.orderSpecs);
break;
case WHERE:
expr = new WhereClause(context, new DebuggableExpression(clause.inputSequence));
break;
default:
expr= new ForExpr(context, clause.allowEmpty);
break;
expr = new GroupByClause(context);
break;
case ORDERBY:
expr = new OrderByClause(context, clause.orderSpecs);
break;
case WHERE:
expr = new WhereClause(context, new DebuggableExpression(clause.inputSequence));
break;
case COUNT:
expr = new CountClause(context, clause.varName);
break;
default:
expr = new ForExpr(context, clause.allowEmpty);
break;
}
expr.setASTNode(clause.ast);
if (clause.type == FLWORClause.ClauseType.FOR || clause.type == FLWORClause.ClauseType.LET) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,10 @@ public AbstractFLWORClause(XQueryContext context) {
}

@Override
public LocalVariable createVariable(final String name) throws XPathException {
try {
final LocalVariable var = new LocalVariable(QName.parse(context, name, null));
firstVar = var;
return var;
} catch (final IllegalQNameException e) {
throw new XPathException(this, ErrorCodes.XPST0081, "No namespace defined for prefix " + name);
}
public LocalVariable createVariable(final QName name) throws XPathException {
final LocalVariable var = new LocalVariable(name);
firstVar = var;
return var;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ public void visitOrderByClause(final OrderByClause orderBy) {
// Nothing to do
}

@Override
public void visitCountClause(final CountClause count) {
// Nothing to do
}

@Override
public void visitGroupByClause(final GroupByClause groupBy) {
// Nothing to do
Expand Down
81 changes: 39 additions & 42 deletions exist-core/src/main/java/org/exist/xquery/BindingExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.dom.QName;
import org.exist.dom.persistent.*;
import org.exist.numbering.NodeId;
import org.exist.storage.UpdateListener;
import org.exist.xquery.value.*;

/**
* Abstract superclass for the variable binding expressions "for" and "let".
* Abstract superclass for the variable binding expressions "for", "let", and "count".
*
* @author <a href="mailto:wolfgang@exist-db.org">Wolfgang Meier</a>
*/
Expand All @@ -41,22 +42,20 @@
protected final static SequenceType POSITIONAL_VAR_TYPE =
new SequenceType(Type.INTEGER, Cardinality.EXACTLY_ONE);

protected String varName;
protected QName varName;
protected SequenceType sequenceType = null;
protected Expression inputSequence;

private ExprUpdateListener listener;


public BindingExpression(XQueryContext context) {
public BindingExpression(final XQueryContext context) {
super(context);
}

public void setVariable(String qname) {
varName = qname;
public void setVariable(final QName varName) {
this.varName = varName;
}

public String getVariable() {
public QName getVariable() {
return this.varName;
}

Expand All @@ -77,52 +76,45 @@
return this.inputSequence;
}

/* (non-Javadoc)
* @see org.exist.xquery.Expression#analyze(org.exist.xquery.Expression, int)
*/
public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
@Override
public void analyze(final AnalyzeContextInfo contextInfo) throws XPathException {
unordered = (contextInfo.getFlags() & UNORDERED) > 0;
}

@Override
public Sequence postEval(Sequence seq) throws XPathException {
if (returnExpr instanceof FLWORClause) {
seq = ((FLWORClause)returnExpr).postEval(seq);
if (returnExpr instanceof FLWORClause flworClause) {
seq = flworClause.postEval(seq);

Check warning on line 87 in exist-core/src/main/java/org/exist/xquery/BindingExpression.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

exist-core/src/main/java/org/exist/xquery/BindingExpression.java#L87

Avoid reassigning parameters such as 'seq'
}
return super.postEval(seq);
}

/* (non-Javadoc)
* @see org.exist.xquery.Expression#preselect(org.exist.dom.persistent.DocumentSet, org.exist.xquery.StaticContext)
*/
public DocumentSet preselect(DocumentSet in_docs) throws XPathException {
return in_docs;
public DocumentSet preselect(final DocumentSet docs) throws XPathException {
return docs;
}

/* (non-Javadoc)
* @see org.exist.xquery.AbstractExpression#resetState()
*/
public void resetState(boolean postOptimization) {
@Override
public void resetState(final boolean postOptimization) {
super.resetState(postOptimization);
inputSequence.resetState(postOptimization);
returnExpr.resetState(postOptimization);
}

public final static void setContext(int contextId, Sequence seq) throws XPathException {
public static void setContext(final int contextId, final Sequence seq) throws XPathException {
if (seq instanceof VirtualNodeSet) {
((VirtualNodeSet)seq).setInPredicate(true);
((VirtualNodeSet)seq).setSelfIsContext();
} else {
Item next;
for (final SequenceIterator i = seq.unorderedIterator(); i.hasNext();) {
next = i.nextItem();
if (next instanceof NodeProxy)
{((NodeProxy) next).addContextNode(contextId, (NodeProxy) next);}
for (final SequenceIterator i = seq.unorderedIterator(); i.hasNext(); ) {
final Item next = i.nextItem();
if (next instanceof NodeProxy) {
((NodeProxy) next).addContextNode(contextId, (NodeProxy) next);
}
}
}
}

public final static void clearContext(int contextId, Sequence seq) throws XPathException {
public final static void clearContext(final int contextId, final Sequence seq) throws XPathException {
if (seq != null && !(seq instanceof VirtualNodeSet)) {
seq.clearContext(contextId);
}
Expand All @@ -132,27 +124,29 @@
if (listener == null) {
listener = new ExprUpdateListener(sequence);
context.registerUpdateListener(listener);
} else
{listener.setSequence(sequence);}
} else {
listener.setSequence(sequence);
}
}

private class ExprUpdateListener implements UpdateListener {
private Sequence sequence;

public ExprUpdateListener(Sequence sequence) {
public ExprUpdateListener(final Sequence sequence) {
this.sequence = sequence;
}

public void setSequence(Sequence sequence) {
public void setSequence(final Sequence sequence) {
this.sequence = sequence;
}

@Override
public void documentUpdated(DocumentImpl document, int event) {
public void documentUpdated(final DocumentImpl document, final int event) {
// no-op
}

@Override
public void nodeMoved(NodeId oldNodeId, NodeHandle newNode) {
public void nodeMoved(final NodeId oldNodeId, final NodeHandle newNode) {
sequence.nodeMoved(oldNodeId, newNode);
}

Expand All @@ -163,6 +157,7 @@

@Override
public void debug() {
// no-op
}
}

Expand All @@ -178,11 +173,12 @@
/* RewritableExpression API */

@Override
public void replace(Expression oldExpr, Expression newExpr) {
if (inputSequence == oldExpr)
{inputSequence = newExpr;}
else if (returnExpr == oldExpr)
{returnExpr = newExpr;}
public void replace(final Expression oldExpr, final Expression newExpr) {
if (inputSequence == oldExpr) {
inputSequence = newExpr;
} else if (returnExpr == oldExpr) {
returnExpr = newExpr;
}
}

@Override
Expand All @@ -196,7 +192,8 @@
}

@Override
public void remove(Expression oldExpr) throws XPathException {
public void remove(final Expression oldExpr) throws XPathException {
// no-op
}

/* END RewritableExpression API */
Expand Down
Loading
Loading