Skip to content

Commit

Permalink
[bugfix] Check before optimizing innerExpr. No need to optimize if it…
Browse files Browse the repository at this point in the history
… is already optimized.

Closes #3624
  • Loading branch information
marmoure authored and adamretter committed Jul 16, 2023
1 parent 0916686 commit 77231a9
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

Expand Down Expand Up @@ -153,7 +152,7 @@ public class Lookup extends Function implements Optimizable {
private boolean optimizeChild = false;
private boolean usesCollation = false;
@Nullable private Expression fallback = null;
@Nullable private final NodePath contextPath;
@Nullable private NodePath contextPath;

/**
* Constructor called via reflection from {@link Function#createFunction(XQueryContext, XQueryAST, Module, FunctionDef)}.
Expand All @@ -178,6 +177,24 @@ private Lookup(final XQueryContext context, final FunctionSignature signature, @
this.contextPath = contextPath;
}

/**
* Get the node path of the optimization.
*
* @return the node path of the optimization, or null if unknown.
*/
public @Nullable NodePath getContextPath() {
return contextPath;
}

/**
* Set the node path of the optimization.
*
* @param contextPath the node path of the optimization, or null if unknown.
*/
public void setContextPath(@Nullable final NodePath contextPath) {
this.contextPath = contextPath;
}

public void setFallback(@Nullable Expression expression, final int optimizeAxis) {
if (expression instanceof final InternalFunctionCall fcall) {
expression = fcall.getFunction();

Check warning on line 200 in extensions/indexes/range/src/main/java/org/exist/xquery/modules/range/Lookup.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

extensions/indexes/range/src/main/java/org/exist/xquery/modules/range/Lookup.java#L200

Avoid reassigning parameters such as 'expression'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
Expand Down Expand Up @@ -60,16 +61,16 @@ public Pragma rewriteLocationStep(final LocationStep locationStep) throws XPathE
// will become true if optimizable expression is found
boolean canOptimize = false;
// get path of path expression before the predicates
NodePath contextPath = toNodePath(getPrecedingSteps(locationStep));
final NodePath contextPath = toNodePath(getPrecedingSteps(locationStep));
// process the remaining predicates
for (Predicate pred : preds) {
for (final Predicate pred : preds) {
if (pred.getLength() != 1) {
// can only optimize predicates with one expression
break;
}

Expression innerExpr = pred.getExpression(0);
List<LocationStep> steps = getStepsToOptimize(innerExpr);
final Expression innerExpr = pred.getExpression(0);
final List<LocationStep> steps = getStepsToOptimize(innerExpr);
if (steps == null || steps.isEmpty()) {
// no optimizable steps found
continue;
Expand All @@ -90,11 +91,11 @@ public Pragma rewriteLocationStep(final LocationStep locationStep) throws XPathE
}

// compute left hand path
NodePath innerPath = toNodePath(steps);
final NodePath innerPath = toNodePath(steps);
if (innerPath == null) {
continue;
}
NodePath path;
final NodePath path;
if (contextPath == null) {
path = innerPath;
} else {
Expand All @@ -103,14 +104,24 @@ public Pragma rewriteLocationStep(final LocationStep locationStep) throws XPathE
}

if (path.length() > 0) {
// replace with call to lookup function
// collect arguments
Lookup func = rewrite(innerExpr, path);
// preserve original comparison: may need it for in-memory lookups
func.setFallback(innerExpr, axis);
func.setLocation(innerExpr.getLine(), innerExpr.getColumn());
if (innerExpr instanceof final InternalFunctionCall internalFunctionCall
&& internalFunctionCall.getFunction() instanceof final Lookup lookup) {

// innerExpr was already optimized, just update the contextPath if it is missing
if (lookup.getContextPath() == null) {
lookup.setContextPath(path);;
}

} else {
// replace with call to lookup function
final Lookup func = rewrite(innerExpr, path);
// preserve original comparison: may need it for in-memory lookups
func.setFallback(innerExpr, axis);
func.setLocation(innerExpr.getLine(), innerExpr.getColumn());

pred.replace(innerExpr, new InternalFunctionCall(func));
}

pred.replace(innerExpr, new InternalFunctionCall(func));
canOptimize = true;
}
}
Expand All @@ -126,28 +137,23 @@ public Pragma rewriteLocationStep(final LocationStep locationStep) throws XPathE
return null;
}

protected static Lookup rewrite(Expression expression, NodePath path) throws XPathException {
ArrayList<Expression> eqArgs = new ArrayList<>(2);
if (expression instanceof GeneralComparison) {
GeneralComparison comparison = (GeneralComparison) expression;
eqArgs.add(comparison.getLeft());
eqArgs.add(comparison.getRight());
Lookup func = Lookup.create(comparison.getContext(), getOperator(expression), path);
func.setArguments(eqArgs);
return func;
protected static @Nullable Lookup rewrite(final Expression expression, final NodePath path) throws XPathException {
if (expression instanceof final GeneralComparison comparison) {
final List<Expression> eqArgs = Arrays.asList(comparison.getLeft(), comparison.getRight());
final Lookup lookup = Lookup.create(comparison.getContext(), getOperator(expression), path);
if (lookup != null) {
lookup.setArguments(eqArgs);
}
return lookup;
} else if (expression instanceof InternalFunctionCall) {
InternalFunctionCall fcall = (InternalFunctionCall) expression;
Function function = fcall.getFunction();
if (function instanceof Lookup) {
if (function.isCalledAs("matches")) {
eqArgs.add(function.getArgument(0));
eqArgs.add(function.getArgument(1));
Lookup func = Lookup.create(function.getContext(), RangeIndex.Operator.MATCH, path);
func.setArguments(eqArgs);
return func;
}
final InternalFunctionCall fcall = (InternalFunctionCall) expression;
final Function function = fcall.getFunction();
if (function instanceof final Lookup lookup && lookup.getContextPath() == null) {
lookup.setContextPath(path);
return lookup;
}
}

return null;
}

Expand All @@ -159,6 +165,7 @@ protected static List<LocationStep> getStepsToOptimize(Expression expr) {
InternalFunctionCall fcall = (InternalFunctionCall) expr;
Function function = fcall.getFunction();
if (function instanceof Lookup) {
// TODO(AR) is this check for range:matches needed here?
if (function.isCalledAs("matches")) {
return BasicExpressionVisitor.findLocationSteps(function.getArgument(0));
} else {
Expand All @@ -171,16 +178,20 @@ protected static List<LocationStep> getStepsToOptimize(Expression expr) {
}

public static RangeIndex.Operator getOperator(Expression expr) {
if (expr instanceof InternalFunctionCall) {
InternalFunctionCall fcall = (InternalFunctionCall) expr;
Function function = fcall.getFunction();
if (function instanceof Lookup) {
expr = ((Lookup)function).getFallback();
if (expr instanceof final InternalFunctionCall fcall) {
final Function function = fcall.getFunction();
if (function instanceof final Lookup lookup) {
final Expression fallback = lookup.getFallback();
if (fallback != null) {
expr = fallback;

Check warning on line 186 in extensions/indexes/range/src/main/java/org/exist/xquery/modules/range/RangeQueryRewriter.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

extensions/indexes/range/src/main/java/org/exist/xquery/modules/range/RangeQueryRewriter.java#L186

Avoid reassigning parameters such as 'expr'
} else {
expr = lookup;
}
}
}

RangeIndex.Operator operator = RangeIndex.Operator.EQ;
if (expr instanceof GeneralComparison) {
GeneralComparison comparison = (GeneralComparison) expr;
if (expr instanceof final GeneralComparison comparison) {
final Comparison relation = comparison.getRelation();
switch(relation) {
case LT:
Expand Down Expand Up @@ -216,15 +227,14 @@ public static RangeIndex.Operator getOperator(Expression expr) {
break;

}
} else if (expr instanceof InternalFunctionCall) {
InternalFunctionCall fcall = (InternalFunctionCall) expr;
Function function = fcall.getFunction();
if (function instanceof Lookup && function.isCalledAs("matches")) {
operator = RangeIndex.Operator.MATCH;
}
} else if (expr instanceof Lookup && ((Function)expr).isCalledAs("matches")) {
} else if (expr instanceof final InternalFunctionCall fcall) {
expr = fcall.getFunction();
}

if (expr instanceof final Lookup lookup && lookup.isCalledAs("matches")) {
operator = RangeIndex.Operator.MATCH;
}

return operator;
}

Expand Down

0 comments on commit 77231a9

Please sign in to comment.