diff --git a/exist-core/src/main/java/org/exist/xquery/ContextItemExpression.java b/exist-core/src/main/java/org/exist/xquery/ContextItemExpression.java
index a59819efe7e..b3f4fceef90 100644
--- a/exist-core/src/main/java/org/exist/xquery/ContextItemExpression.java
+++ b/exist-core/src/main/java/org/exist/xquery/ContextItemExpression.java
@@ -29,8 +29,6 @@
public class ContextItemExpression extends LocationStep {
- private int returnType = Type.ITEM;
-
public ContextItemExpression(final XQueryContext context) {
// TODO: create class AnyItemTest (one private implementation found in saxon)
super(context, Constants.SELF_AXIS, new AnyNodeTest());
@@ -40,7 +38,7 @@ public ContextItemExpression(final XQueryContext context) {
public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
contextInfo.addFlag(DOT_TEST);
// set return type to static type to allow for index use in optimization step
- returnType = contextInfo.getStaticType();
+ staticReturnType = contextInfo.getStaticType();
super.analyze(contextInfo);
}
@@ -69,7 +67,8 @@ public Sequence eval(final Sequence contextSequence, final Item contextItem) thr
@Override
public int returnsType() {
- return returnType;
+ // "." will have the same type as the parent expression
+ return staticReturnType;
}
@Override
diff --git a/exist-core/src/main/java/org/exist/xquery/LocationStep.java b/exist-core/src/main/java/org/exist/xquery/LocationStep.java
index a2c840e6cdf..8511a953f61 100644
--- a/exist-core/src/main/java/org/exist/xquery/LocationStep.java
+++ b/exist-core/src/main/java/org/exist/xquery/LocationStep.java
@@ -41,7 +41,7 @@
/**
* Processes all location path steps (like descendant::*, ancestor::XXX).
- *
+ *
* The results of the first evaluation of the expression are cached for the
* lifetime of the object and only reloaded if the context sequence (as passed
* to the {@link #eval(Sequence, Item)} method) has changed.
@@ -63,7 +63,7 @@ public class LocationStep extends Step {
//private int parentDeps = Dependency.UNKNOWN_DEPENDENCY;
private boolean preloadedData = false;
protected boolean optimized = false;
-// private boolean inUpdate = false;
+ //private boolean inUpdate = false;
private boolean useDirectChildSelect = false;
private boolean applyPredicate = true;
@@ -84,36 +84,36 @@ public LocationStep(final XQueryContext context, final int axis) {
* Creates a new instance.
*
* @param context the XQuery context
- * @param axis the axis of the location step
- * @param test a node test on the axis
+ * @param axis the axis of the location step
+ * @param test a node test on the axis
*/
- public LocationStep(final XQueryContext context, final int axis, final NodeTest test) {
+ public LocationStep(final XQueryContext context, final int axis, final NodeTest test) {
super(context, axis, test);
}
@Override
public int getDependencies() {
- int deps = Dependency.CONTEXT_SET;
+ int dependencies = Dependency.CONTEXT_SET;
// self axis has an obvious dependency on the context item
// likewise we depend on the context item if this is a single path step (outside a predicate)
- if (!this.inPredicate &&
- (this.axis == Constants.SELF_AXIS ||
+ if (!inPredicate &&
+ (axis == Constants.SELF_AXIS ||
(parent != null && parent.getSubExpressionCount() > 0 && parent.getSubExpression(0) == this))) {
- deps = deps | Dependency.CONTEXT_ITEM;
+ dependencies = dependencies | Dependency.CONTEXT_ITEM;
}
// TODO : normally, we should call this one...
// int deps = super.getDependencies(); ???
- for (final Predicate pred : predicates) {
- deps |= pred.getDependencies();
+ for (final Predicate predicate : predicates) {
+ dependencies |= predicate.getDependencies();
}
// TODO : should we remove the CONTEXT_ITEM dependency returned by the
// predicates ? See the comment above.
// consider nested predicates however...
- return deps;
+ return dependencies;
}
/**
@@ -147,10 +147,10 @@ private boolean hasPreloadedData() {
* @param nodes a NodeSet
value
*/
public void setPreloadedData(final DocumentSet docs, final NodeSet nodes) {
- this.preloadedData = true;
- this.currentDocs = docs;
- this.currentSet = nodes;
- this.optimized = true;
+ preloadedData = true;
+ currentDocs = docs;
+ currentSet = nodes;
+ optimized = true;
}
/**
@@ -165,12 +165,9 @@ private Sequence applyPredicate(Sequence outerSequence, final Sequence contextSe
if (contextSequence == null) {
return Sequence.EMPTY_SEQUENCE;
}
- if (predicates.size() == 0
- || !applyPredicate
- || (!(contextSequence instanceof VirtualNodeSet) && contextSequence
- .isEmpty()))
- // Nothing to apply
- {
+ if (predicates.size() == 0 || !applyPredicate || (
+ !(contextSequence instanceof VirtualNodeSet) && contextSequence.isEmpty())) {
+ // Nothing to apply
return contextSequence;
}
Sequence result;
@@ -183,9 +180,8 @@ private Sequence applyPredicate(Sequence outerSequence, final Sequence contextSe
//
// If the predicate is known to return a node set, no special treatment
// is required.
- if (abbreviatedStep
- && (pred.getExecutionMode() != Predicate.ExecutionMode.NODE || !contextSequence
- .isPersistentSet())) {
+ if (abbreviatedStep && (
+ pred.getExecutionMode() != Predicate.ExecutionMode.NODE || !contextSequence.isPersistentSet())) {
result = new ValueSequence();
((ValueSequence) result).keepUnOrdered(unordered);
if (contextSequence.isPersistentSet()) {
@@ -222,9 +218,9 @@ private Sequence processPredicate(Sequence outerSequence, final Sequence context
for (final Iterator i = predicates.iterator(); i.hasNext()
&& (result instanceof VirtualNodeSet || !result.isEmpty()); ) {
// TODO : log and/or profile ?
- final Predicate pred = i.next();
- pred.setContextDocSet(getContextDocSet());
- result = pred.evalPredicate(outerSequence, result, axis);
+ final Predicate predicate = i.next();
+ predicate.setContextDocSet(getContextDocSet());
+ result = predicate.evalPredicate(outerSequence, result, axis);
// subsequent predicates operate on the result of the previous one
outerSequence = null;
context.setContextSequencePosition(0, null);
@@ -234,7 +230,7 @@ private Sequence processPredicate(Sequence outerSequence, final Sequence context
@Override
public void analyze(final AnalyzeContextInfo contextInfo) throws XPathException {
- this.parent = contextInfo.getParent();
+ parent = contextInfo.getParent();
unordered = (contextInfo.getFlags() & UNORDERED) > 0;
@@ -248,58 +244,82 @@ public void analyze(final AnalyzeContextInfo contextInfo) throws XPathException
if ((contextInfo.getFlags() & USE_TREE_TRAVERSAL) > 0) {
useDirectChildSelect = true;
}
+
// Mark ".", which is expanded as self::node() by the parser
// even though it may *also* be relevant with atomic sequences
- if (this.axis == Constants.SELF_AXIS
- && this.test.getType() == Type.NODE) {
+ // JL: may be unnecessary since ContextItemExpression will add the DOT_TEST flag by itself
+ // JL: literal self::node() might still need this
+ if (axis == Constants.SELF_AXIS && test.getType() == Type.NODE) {
contextInfo.addFlag(DOT_TEST);
}
- //Change axis from descendant-or-self to descendant for '//'
- if (this.axis == Constants.DESCENDANT_SELF_AXIS && isAbbreviated()) {
- this.axis = Constants.DESCENDANT_AXIS;
+ // Change axis from descendant-or-self to descendant for '//'
+ if (axis == Constants.DESCENDANT_SELF_AXIS && isAbbreviated()) {
+ axis = Constants.DESCENDANT_AXIS;
}
+ final Expression contextStep;
+ final LocationStep cStep;
+ final NodeTest stepTest;
+ final NodeTest contextStepTest;
+
// static analysis for empty-sequence
switch (axis) {
case Constants.SELF_AXIS:
- if (getTest().getType() != Type.NODE) {
- final Expression contextStep = contextInfo.getContextStep();
- if (contextStep instanceof LocationStep) {
- final LocationStep cStep = (LocationStep) contextStep;
-
- // WM: the following checks will only work on simple filters like //a[self::b], so we
- // have to make sure they are not applied to more complex expression types
- if (parent.getSubExpressionCount() == 1 && !Type.subTypeOf(getTest().getType(), cStep.getTest().getType())) {
- throw new XPathException(this,
- ErrorCodes.XPST0005, "Got nothing from self::" + getTest() + ", because parent node kind " + Type.getTypeName(cStep.getTest().getType()));
- }
+ if (getTest().getType() == Type.NODE) {
+ break;
+ }
- if (parent.getSubExpressionCount() == 1 && !(cStep.getTest().isWildcardTest() || getTest().isWildcardTest()) && !cStep.getTest().equals(getTest())) {
- throw new XPathException(this,
- ErrorCodes.XPST0005, "Self::" + getTest() + " called on set of nodes which do not contain any nodes of this name.");
- }
- }
+ // WM: the following checks will only work on simple filters like //a[self::b], so we
+ // have to make sure they are not applied to more complex expression types
+ if (parent.getSubExpressionCount() > 1) {
+ break;
+ }
+
+ contextStep = contextInfo.getContextStep();
+ if (!(contextStep instanceof LocationStep)) {
+ break;
+ }
+
+ cStep = (LocationStep) contextStep;
+ stepTest = getTest();
+ contextStepTest = cStep.getTest();
+
+ if (!Type.subTypeOf(stepTest.getType(), contextStepTest.getType())) {
+ // return empty sequence
+ contextInfo.setStaticType(Type.EMPTY);
+ staticReturnType = Type.EMPTY;
+ break;
+ }
+
+ if (!stepTest.isWildcardTest() &&
+ !contextStepTest.isWildcardTest() &&
+ !contextStepTest.equals(stepTest)) {
+ // return empty sequence
+ contextInfo.setStaticType(Type.EMPTY);
+ staticReturnType = Type.EMPTY;
}
break;
-// case Constants.DESCENDANT_AXIS:
+// case Constants.DESCENDANT_AXIS:
case Constants.DESCENDANT_SELF_AXIS:
- final Expression contextStep = contextInfo.getContextStep();
- if (contextStep instanceof LocationStep) {
- final LocationStep cStep = (LocationStep) contextStep;
-
- if ((
- cStep.getTest().getType() == Type.ATTRIBUTE ||
- cStep.getTest().getType() == Type.TEXT
- )
- && cStep.getTest() != getTest()) {
- throw new XPathException(this,
- ErrorCodes.XPST0005, "Descendant-or-self::" + getTest() + " from an attribute gets nothing.");
- }
+ contextStep = contextInfo.getContextStep();
+ if (!(contextStep instanceof LocationStep)) {
+ break;
+ }
+
+ cStep = (LocationStep) contextStep;
+ stepTest = getTest();
+ contextStepTest = cStep.getTest();
+
+ if ((contextStepTest.getType() == Type.ATTRIBUTE || contextStepTest.getType() == Type.TEXT) &&
+ !contextStepTest.equals(stepTest)) {
+ // return empty sequence
+ contextInfo.setStaticType(Type.EMPTY);
+ staticReturnType = Type.EMPTY;
}
break;
-// case Constants.PARENT_AXIS:
-// case Constants.ATTRIBUTE_AXIS:
+// case Constants.PARENT_AXIS:
+// case Constants.ATTRIBUTE_AXIS:
default:
}
@@ -363,7 +383,6 @@ public Sequence eval(Sequence contextSequence, final Item contextItem)
try {
switch (axis) {
-
case Constants.DESCENDANT_AXIS:
case Constants.DESCENDANT_SELF_AXIS:
result = getDescendants(context, contextSequence);
@@ -464,16 +483,15 @@ private boolean needsComputation() {
if (nodeTestType == null) {
nodeTestType = test.getType();
}
- if (nodeTestType != Type.NODE
- && nodeTestType != Type.ELEMENT
- && nodeTestType != Type.PROCESSING_INSTRUCTION) {
+ if (nodeTestType != Type.NODE &&
+ nodeTestType != Type.ELEMENT &&
+ nodeTestType != Type.PROCESSING_INSTRUCTION) {
if (context.getProfiler().isEnabled()) {
context.getProfiler().message(this, Profiler.OPTIMIZATIONS,
"OPTIMIZATION", "avoid useless computations");
}
return false;
}
-
}
return true;
}
@@ -534,7 +552,7 @@ private Sequence getSelf(final XQueryContext context, final Sequence contextSequ
} else {
final NewArrayNodeSet results = new NewArrayNodeSet();
for (final NodeProxy p : contextSet) {
- if(test.matches(p)) {
+ if (test.matches(p)) {
results.add(p);
}
}
@@ -579,10 +597,8 @@ protected Sequence getAttributes(final XQueryContext context, final Sequence con
if (hasPreloadedData()) {
final DocumentSet docs = getDocumentSet(contextSet);
synchronized (context) {
- if (currentSet == null
- || currentDocs == null
- || (!optimized && !(docs == currentDocs || docs
- .equalDocs(currentDocs)))) {
+ if (currentSet == null || currentDocs == null || (
+ !optimized && !(docs.equals(currentDocs) || docs.equalDocs(currentDocs)))) {
final StructuralIndex index = context.getBroker().getStructuralIndex();
if (context.getProfiler().isEnabled()) {
context.getProfiler().message(
@@ -669,10 +685,8 @@ private Sequence getChildren(final XQueryContext context, final Sequence context
synchronized (context) {
// TODO : understand why this one is different from the other
// ones
- if (currentSet == null
- || currentDocs == null
- || (!optimized && !(docs == currentDocs || docs
- .equalDocs(currentDocs)))) {
+ if (currentSet == null || currentDocs == null || (
+ !optimized && !(docs.equals(currentDocs) || docs.equalDocs(currentDocs)))) {
final StructuralIndex index = context.getBroker().getStructuralIndex();
if (context.getProfiler().isEnabled()) {
context.getProfiler().message(
@@ -713,15 +727,14 @@ private Sequence getChildren(final XQueryContext context, final Sequence context
private Sequence getDescendants(final XQueryContext context, final Sequence contextSequence) throws XPathException {
if (!contextSequence.isPersistentSet()) {
final MemoryNodeSet nodes = contextSequence.toMemNodeSet();
- return nodes.getDescendants(axis == Constants.DESCENDANT_SELF_AXIS,
- test);
+ return nodes.getDescendants(axis == Constants.DESCENDANT_SELF_AXIS, test);
}
final NodeSet contextSet = contextSequence.toNodeSet();
// TODO : understand this. I guess comments should be treated in a
// similar way ? -pb
- if ((!hasPreloadedData() && test.isWildcardTest())
- || test.getType() == Type.PROCESSING_INSTRUCTION) {
+ if ((!hasPreloadedData() && test.isWildcardTest()) ||
+ test.getType() == Type.PROCESSING_INSTRUCTION) {
// test is one out of *, text(), node() including
// processing-instruction(targetname)
final VirtualNodeSet vset = new VirtualNodeSet(context.getBroker(), axis, test, contextId, contextSet);
@@ -730,12 +743,9 @@ private Sequence getDescendants(final XQueryContext context, final Sequence cont
} else if (hasPreloadedData()) {
final DocumentSet docs = getDocumentSet(contextSet);
synchronized (context) {
- // TODO : understand why this one is different from the other
- // ones
- if (currentSet == null
- || currentDocs == null
- || (!optimized && !(docs == currentDocs || docs
- .equalDocs(currentDocs)))) {
+ // TODO : understand why this one is different from the other ones
+ if (currentSet == null || currentDocs == null || (
+ !optimized && !(docs.equals(currentDocs) || docs.equalDocs(currentDocs)))) {
final StructuralIndex index = context.getBroker().getStructuralIndex();
if (context.getProfiler().isEnabled()) {
context.getProfiler().message(
@@ -752,11 +762,11 @@ private Sequence getDescendants(final XQueryContext context, final Sequence cont
switch (axis) {
case Constants.DESCENDANT_SELF_AXIS:
- return currentSet.selectAncestorDescendant(contextSet, NodeSet.DESCENDANT, true, contextId,
- true);
+ return currentSet.selectAncestorDescendant(
+ contextSet, NodeSet.DESCENDANT, true, contextId, true);
case Constants.DESCENDANT_AXIS:
- return currentSet.selectAncestorDescendant(contextSet, NodeSet.DESCENDANT, false, contextId,
- true);
+ return currentSet.selectAncestorDescendant(
+ contextSet, NodeSet.DESCENDANT, false, contextId, true);
default:
throw new IllegalArgumentException("Unsupported axis specified");
}
@@ -810,8 +820,7 @@ protected Sequence getSiblings(final XQueryContext context, final Sequence conte
}
final NodeSet contextSet = contextSequence.toNodeSet();
- // TODO : understand this. I guess comments should be treated in a
- // similar way ? -pb
+ // TODO : understand this. I guess comments should be treated in a similar way ? -pb
if (test.getType() == Type.PROCESSING_INSTRUCTION) {
final VirtualNodeSet vset = new VirtualNodeSet(context.getBroker(), axis,
test, contextId, contextSet);
@@ -888,11 +897,9 @@ protected Sequence getSiblings(final XQueryContext context, final Sequence conte
/**
* Get the preceding or following axis nodes
*
- * @param context the xquery context
+ * @param context the xquery context
* @param contextSequence the context sequence
- *
* @return the nodes from the preceding or following axis
- *
* @throws XPathException if an error occurs
*/
private Sequence getPrecedingOrFollowing(final XQueryContext context, final Sequence contextSequence)
@@ -1012,11 +1019,9 @@ private int computeLimit() throws XPathException {
/**
* Get the ancestor axis nodes
*
- * @param context the xquery context
+ * @param context the xquery context
* @param contextSequence the context sequence
- *
* @return the ancestor nodes
- *
* @throws XPathException if an error occurs
*/
protected Sequence getAncestors(final XQueryContext context, final Sequence contextSequence) throws XPathException {
@@ -1116,11 +1121,9 @@ protected Sequence getAncestors(final XQueryContext context, final Sequence cont
/**
* Get the parent axis nodes
*
- * @param context the xquery context
+ * @param context the xquery context
* @param contextSequence the context sequence
- *
* @return the parent nodes
- *
* @throws XPathException if an error occurs
*/
protected Sequence getParents(final XQueryContext context, final Sequence contextSequence) throws XPathException {
@@ -1142,7 +1145,8 @@ protected Sequence getParents(final XQueryContext context, final Sequence contex
} else if (hasPreloadedData()) {
final DocumentSet docs = getDocumentSet(contextSet);
synchronized (context) {
- if (currentSet == null || currentDocs == null || (!optimized && !(docs == currentDocs || docs.equalDocs(currentDocs)))) {
+ if (currentSet == null || currentDocs == null || (
+ !optimized && !(docs.equals(currentDocs) || docs.equalDocs(currentDocs)))) {
final StructuralIndex index = context.getBroker().getStructuralIndex();
if (context.getProfiler().isEnabled()) {
context.getProfiler().message(
@@ -1289,7 +1293,7 @@ private class FollowingSiblingFilter extends AbstractFilterBase {
boolean sibling = false;
FollowingSiblingFilter(final NodeTest test, final NodeProxy start, final NodeSet result,
- final int contextId, final int limit) {
+ final int contextId, final int limit) {
super(test, result, contextId, limit);
this.start = start;
this.level = start.getNodeId().getTreeLevel();
@@ -1341,7 +1345,7 @@ private class PrecedingSiblingFilter extends AbstractFilterBase {
final NodeProxy referenceNode;
PrecedingSiblingFilter(final NodeTest test, final NodeProxy start, final NodeProxy referenceNode,
- final NodeSet result, final int contextId) {
+ final NodeSet result, final int contextId) {
super(test, result, contextId, -1);
this.level = start.getNodeId().getTreeLevel();
this.referenceNode = referenceNode;
@@ -1389,7 +1393,7 @@ private class FollowingFilter extends AbstractFilterBase {
boolean isAfter = false;
FollowingFilter(final NodeTest test, final NodeProxy root, final NodeProxy referenceNode, final NodeSet result,
- final int contextId, final int limit) {
+ final int contextId, final int limit) {
super(test, result, contextId, limit);
this.root = root;
this.referenceNode = referenceNode;
@@ -1438,7 +1442,7 @@ private class PrecedingFilter extends AbstractFilterBase {
final NodeProxy referenceNode;
PrecedingFilter(final NodeTest test, final NodeProxy root, final NodeProxy referenceNode, final NodeSet result,
- final int contextId) {
+ final int contextId) {
super(test, result, contextId, -1);
this.root = root;
this.referenceNode = referenceNode;
diff --git a/exist-core/src/main/java/org/exist/xquery/Step.java b/exist-core/src/main/java/org/exist/xquery/Step.java
index bafa3bbcc95..dea3fad4167 100644
--- a/exist-core/src/main/java/org/exist/xquery/Step.java
+++ b/exist-core/src/main/java/org/exist/xquery/Step.java
@@ -35,7 +35,7 @@ public abstract class Step extends AbstractExpression {
protected final static Logger LOG = LogManager.getLogger(Step.class);
- protected int axis = Constants.UNKNOWN_AXIS;
+ protected int axis;
protected boolean abbreviatedStep = false;
@@ -47,18 +47,18 @@ public abstract class Step extends AbstractExpression {
protected int staticReturnType = Type.ITEM;
- public Step( XQueryContext context, int axis ) {
+ public Step(XQueryContext context, int axis) {
super(context);
this.axis = axis;
}
- public Step( XQueryContext context, int axis, NodeTest test ) {
- this( context, axis );
+ public Step(XQueryContext context, int axis, NodeTest test) {
+ this(context, axis);
this.test = test;
}
- public void addPredicate( Expression expr ) {
- predicates.add( (Predicate) expr );
+ public void addPredicate(Expression expr) {
+ predicates.add((Predicate) expr);
}
public void insertPredicate(Expression previous, Expression predicate) {
@@ -78,30 +78,36 @@ public List getPredicates() {
return predicates;
}
- /* (non-Javadoc)
- * @see org.exist.xquery.Expression#analyze(org.exist.xquery.AnalyzeContextInfo)
- */
+ @Override
public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
- if (test != null && test.getName() != null &&
- test.getName().getPrefix() != null &&
- (!test.getName().getPrefix().isEmpty()) && context.getInScopePrefixes() != null &&
- context.getURIForPrefix(test.getName().getPrefix()) == null)
- {throw new XPathException(this, ErrorCodes.XPST0081, "undeclared prefix '"
- + test.getName().getPrefix() + "'");}
+ if (
+ test != null &&
+ test.getName() != null &&
+ test.getName().getPrefix() != null &&
+ !test.getName().getPrefix().isEmpty() &&
+ context.getInScopePrefixes() != null &&
+ context.getURIForPrefix(test.getName().getPrefix()) == null) {
+ throw new XPathException(this, ErrorCodes.XPST0081,
+ "undeclared prefix '" + test.getName().getPrefix() + "'");
+ }
+
inPredicate = (contextInfo.getFlags() & IN_PREDICATE) > 0;
this.contextId = contextInfo.getContextId();
+
if (predicates.size() > 0) {
final AnalyzeContextInfo newContext = new AnalyzeContextInfo(contextInfo);
newContext.setStaticType(this.axis == Constants.SELF_AXIS ? contextInfo.getStaticType() : Type.NODE);
newContext.setParent(this);
newContext.setContextStep(this);
- for (final Predicate pred : predicates) {
- pred.analyze(newContext);
+
+ for (final Predicate predicate : predicates) {
+ predicate.analyze(newContext);
}
}
// if we are on the self axis, remember the static return type given in the context
- if (this.axis == Constants.SELF_AXIS)
- {staticReturnType = contextInfo.getStaticType();}
+ if (this.axis == Constants.SELF_AXIS) {
+ staticReturnType = contextInfo.getStaticType();
+ }
}
/**
@@ -109,37 +115,35 @@ public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
* If yes, set a flag on the {@link LocationStep}
*
* @param inPredicate true if in a predicate, false otherwise
- *
* @return true if the first filter is a positional predicate
*/
protected boolean checkPositionalFilters(final boolean inPredicate) {
- if (!inPredicate && this.hasPredicates()) {
- final List preds = this.getPredicates();
- final Predicate predicate = preds.get(0);
- final Expression predExpr = predicate.getFirst();
- // only apply optimization if the static return type is a single number
- // and there are no dependencies on the context item
- if (Type.subTypeOfUnion(predExpr.returnsType(), Type.NUMBER) &&
- !Dependency.dependsOn(predExpr, Dependency.CONTEXT_POSITION)) {
- return true;
- }
+ if (inPredicate || !hasPredicates()) {
+ return false;
}
- return false;
+
+ final List predicates = this.getPredicates();
+ final Predicate predicate = predicates.get(0);
+ final Expression predicateExpr = predicate.getFirst();
+
+ // only apply optimization if the static return type is a single number
+ // and there are no dependencies on the context item
+ return (Type.subTypeOfUnion(predicateExpr.returnsType(), Type.NUMBER) &&
+ !Dependency.dependsOn(predicateExpr, Dependency.CONTEXT_POSITION));
}
- public abstract Sequence eval( Sequence contextSequence, Item contextItem ) throws XPathException;
+ public abstract Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException;
public int getAxis() {
return axis;
}
- /* (non-Javadoc)
- * @see org.exist.xquery.AbstractExpression#setPrimaryAxis(int)
- */
+ @Override
public void setPrimaryAxis(int axis) {
this.axis = axis;
}
+ @Override
public int getPrimaryAxis() {
return this.axis;
}
@@ -152,59 +156,70 @@ public void setAbbreviated(boolean abbrev) {
abbreviatedStep = abbrev;
}
- /* (non-Javadoc)
- * @see org.exist.xquery.Expression#dump(org.exist.xquery.util.ExpressionDumper)
- */
+ @Override
public void dump(ExpressionDumper dumper) {
- if (axis != Constants.UNKNOWN_AXIS)
- {dumper.display( Constants.AXISSPECIFIERS[axis] );}
- dumper.display( "::" );
- if ( test != null )
+ if (axis != Constants.UNKNOWN_AXIS) {
+ dumper.display(Constants.AXISSPECIFIERS[axis]);
+ }
+ dumper.display("::");
+ if (test != null) {
//TODO : toString() or... dump ?
- {dumper.display( test.toString() );}
- else
- {dumper.display( "node()" );}
- if ( predicates.size() > 0 )
- for (final Predicate pred : predicates) {
- pred.dump(dumper);
+ dumper.display(test.toString());
+ } else {
+ dumper.display("node()");
+ }
+ if (predicates.size() > 0) {
+ for (final Predicate predicates : predicates) {
+ predicates.dump(dumper);
}
+ }
}
+ @Override
public String toString() {
final StringBuilder result = new StringBuilder();
- if (axis != Constants.UNKNOWN_AXIS)
- {result.append( Constants.AXISSPECIFIERS[axis] );}
- result.append( "::" );
- if (test != null )
- {result.append( test.toString() );}
- else
- {result.append( "node()" );}
- if (predicates.size() > 0 )
- for (final Predicate pred : predicates) {
- result.append(pred.toString());
+
+ if (axis != Constants.UNKNOWN_AXIS) {
+ result.append(Constants.AXISSPECIFIERS[axis]);
+ }
+
+ result.append("::");
+
+ if (test != null) {
+ result.append(test.toString());
+ } else {
+ result.append("node()");
+ }
+
+ if (predicates.size() > 0) {
+ for (final Predicate predicates : predicates) {
+ result.append(predicates.toString());
}
+ }
return result.toString();
}
+ @Override
public int returnsType() {
- //Polysemy of "." which might be atomic if the context sequence is atomic itself
+ // Polysemy of "." which might be atomic if the context sequence is atomic itself
if (axis == Constants.SELF_AXIS) {
- //Type.ITEM by default : this may change *after* evaluation
+ // Type.ITEM by default : this may change *after* evaluation
return staticReturnType;
- } else
- {return Type.NODE;}
+ } else {
+ return Type.NODE;
+ }
}
@Override
public Cardinality getCardinality() {
return Cardinality.ZERO_OR_MORE;
- }
+ }
- public void setAxis( int axis ) {
+ public void setAxis(int axis) {
this.axis = axis;
}
- public void setTest( NodeTest test ) {
+ public void setTest(NodeTest test) {
this.test = test;
}
@@ -212,13 +227,11 @@ public NodeTest getTest() {
return test;
}
- /* (non-Javadoc)
- * @see org.exist.xquery.AbstractExpression#resetState()
- */
+ @Override
public void resetState(boolean postOptimization) {
super.resetState(postOptimization);
- for (final Predicate pred : predicates) {
- pred.resetState(postOptimization);
+ for (final Predicate predicate : predicates) {
+ predicate.resetState(postOptimization);
}
}
}
\ No newline at end of file