use of org.exist.xquery.Predicate.ExecutionMode in project exist by eXist-db.
the class Predicate method evalPredicate.
public Sequence evalPredicate(final Sequence outerSequence, final Sequence contextSequence, final int mode) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
}
Sequence result;
final Expression inner = steps.size() == 1 ? getSubExpression(0) : this;
if (inner == null) {
result = Sequence.EMPTY_SEQUENCE;
} else {
if (executionMode == UNKNOWN) {
executionMode = BOOLEAN;
}
final Tuple2<ExecutionMode, Sequence> recomputed = recomputeExecutionMode(contextSequence, inner);
final ExecutionMode recomputedExecutionMode = recomputed._1;
Sequence innerSeq = recomputed._2;
switch(recomputedExecutionMode) {
case NODE:
if (context.getProfiler().isEnabled()) {
context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION CHOICE", "Node selection");
}
result = selectByNodeSet(contextSequence);
break;
case BOOLEAN:
if (context.getProfiler().isEnabled()) {
context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION CHOICE", "Boolean evaluation");
}
result = evalBoolean(contextSequence, inner, mode);
break;
case POSITIONAL:
if (context.getProfiler().isEnabled()) {
context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION CHOICE", "Positional evaluation");
}
// In case it hasn't been evaluated above
if (innerSeq == null) {
// for a positional predicate, check if it depends on the context item
// if not, do not pass the context sequence to avoid cardinality errors
context.setContextSequencePosition(0, contextSequence);
innerSeq = inner.eval(Dependency.dependsOn(inner.getDependencies(), Dependency.CONTEXT_ITEM) ? contextSequence : null);
}
// We must check for empty sequences here to avoid an NPE
if (innerSeq.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else if (innerSeq.getCardinality().isSubCardinalityOrEqualOf(Cardinality.EXACTLY_ONE)) {
result = selectByPosition(outerSequence, contextSequence, mode, innerSeq);
} else {
throw new XPathException(this, ErrorCodes.FORG0006, "Effective boolean value is not defined for a sequence of two or more items starting with a " + Type.getTypeName(innerSeq.itemAt(0).getType()) + " value");
}
break;
default:
throw new IllegalArgumentException("Unsupported execution mode: '" + recomputedExecutionMode + "'");
}
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
use of org.exist.xquery.Predicate.ExecutionMode in project exist by eXist-db.
the class Predicate method recomputeExecutionMode.
private Tuple2<ExecutionMode, Sequence> recomputeExecutionMode(final Sequence contextSequence, final Expression inner) throws XPathException {
ExecutionMode recomputedExecutionMode = executionMode;
Sequence innerSeq = null;
// Atomic context sequences :
if (Type.subTypeOf(contextSequence.getItemType(), Type.ATOMIC)) {
// the inner sequence
if (executionMode == NODE && !(contextSequence instanceof VirtualNodeSet)) {
// (1,2,2,4)[.]
if (Type.subTypeOfUnion(contextSequence.getItemType(), Type.NUMBER)) {
recomputedExecutionMode = POSITIONAL;
} else {
recomputedExecutionMode = BOOLEAN;
}
}
// If there is no dependency on the context item, try a positional promotion
if (executionMode == BOOLEAN && !Dependency.dependsOn(inner, Dependency.CONTEXT_ITEM) && // computation should now be better
!((inner instanceof GeneralComparison) && ((GeneralComparison) inner).invalidNodeEvaluation)) {
innerSeq = inner.eval(contextSequence);
// Only if we have an actual *singleton* of numeric items
if (innerSeq.hasOne() && Type.subTypeOfUnion(innerSeq.getItemType(), Type.NUMBER)) {
recomputedExecutionMode = POSITIONAL;
}
}
} else if (executionMode == NODE && !contextSequence.isPersistentSet()) {
recomputedExecutionMode = BOOLEAN;
} else {
if (executionMode == BOOLEAN && !Dependency.dependsOn(inner, Dependency.CONTEXT_ITEM)) {
/*
*
* WARNING : this sequence will be evaluated with
* preloadable nodesets !
*/
innerSeq = inner.eval(contextSequence);
// We are now sure of the inner sequence return type
if (Type.subTypeOf(innerSeq.getItemType(), Type.NODE) && innerSeq.isPersistentSet()) {
recomputedExecutionMode = NODE;
// Try to promote a boolean evaluation to a positional one
// Only if we have an actual *singleton* of numeric items
} else if (innerSeq.hasOne() && Type.subTypeOfUnion(innerSeq.getItemType(), Type.NUMBER)) {
recomputedExecutionMode = POSITIONAL;
}
}
}
return Tuple(recomputedExecutionMode, innerSeq);
}
Aggregations