Skip to content

Commit

Permalink
[CALCITE-2007] Fix RexSimplify behavior when literals come first.
Browse files Browse the repository at this point in the history
It would incorrectly simplify "1 < x AND x < 3" to "x < 3".
  • Loading branch information
gianm committed Oct 12, 2017
1 parent 453e928 commit 06c18ca
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 10 deletions.
50 changes: 40 additions & 10 deletions core/src/main/java/org/apache/calcite/rex/RexSimplify.java
Original file line number Diff line number Diff line change
Expand Up @@ -1125,12 +1125,9 @@ private static <C extends Comparable<C>> RexNode processRange(
if (removeUpperBound) {
ImmutableList.Builder<RexNode> newBounds = ImmutableList.builder();
for (RexNode e : p.right) {
switch (e.getKind()) {
case LESS_THAN:
case LESS_THAN_OR_EQUAL:
if (isUpperBound(e)) {
Collections.replaceAll(terms, e, rexBuilder.makeLiteral(true));
break;
default:
} else {
newBounds.add(e);
}
}
Expand All @@ -1140,12 +1137,9 @@ private static <C extends Comparable<C>> RexNode processRange(
} else if (removeLowerBound) {
ImmutableList.Builder<RexNode> newBounds = ImmutableList.builder();
for (RexNode e : p.right) {
switch (e.getKind()) {
case GREATER_THAN:
case GREATER_THAN_OR_EQUAL:
if (isLowerBound(e)) {
Collections.replaceAll(terms, e, rexBuilder.makeLiteral(true));
break;
default:
} else {
newBounds.add(e);
}
}
Expand Down Expand Up @@ -1218,6 +1212,42 @@ static Comparison of(RexNode e) {
return null;
}
}

private static boolean isUpperBound(final RexNode e) {
final List<RexNode> operands;
switch (e.getKind()) {
case LESS_THAN:
case LESS_THAN_OR_EQUAL:
operands = ((RexCall) e).getOperands();
return RexUtil.isReferenceOrAccess(operands.get(0), true)
&& operands.get(1).isA(SqlKind.LITERAL);
case GREATER_THAN:
case GREATER_THAN_OR_EQUAL:
operands = ((RexCall) e).getOperands();
return RexUtil.isReferenceOrAccess(operands.get(1), true)
&& operands.get(0).isA(SqlKind.LITERAL);
default:
return false;
}
}

private static boolean isLowerBound(final RexNode e) {
final List<RexNode> operands;
switch (e.getKind()) {
case LESS_THAN:
case LESS_THAN_OR_EQUAL:
operands = ((RexCall) e).getOperands();
return RexUtil.isReferenceOrAccess(operands.get(1), true)
&& operands.get(0).isA(SqlKind.LITERAL);
case GREATER_THAN:
case GREATER_THAN_OR_EQUAL:
operands = ((RexCall) e).getOperands();
return RexUtil.isReferenceOrAccess(operands.get(0), true)
&& operands.get(1).isA(SqlKind.LITERAL);
default:
return false;
}
}
}

// End RexSimplify.java
24 changes: 24 additions & 0 deletions core/src/test/java/org/apache/calcite/test/RexProgramTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,30 @@ private void checkExponentialCnf(int n) {
// condition with null value for range
checkSimplifyFilter(and(gt(aRef, unknownLiteral), ge(bRef, literal1)), "false");

// condition "1 < a && 5 < x" yields "5 < x"
checkSimplifyFilter(
and(lt(literal1, aRef), lt(literal5, aRef)),
RelOptPredicateList.EMPTY,
"<(5, ?0.a)");

// condition "1 < a && a < 5" is unchanged
checkSimplifyFilter(
and(lt(literal1, aRef), lt(aRef, literal5)),
RelOptPredicateList.EMPTY,
"AND(<(1, ?0.a), <(?0.a, 5))");

// condition "1 > a && 5 > x" yields "1 > a"
checkSimplifyFilter(
and(gt(literal1, aRef), gt(literal5, aRef)),
RelOptPredicateList.EMPTY,
">(1, ?0.a)");

// condition "1 > a && a > 5" yields false
checkSimplifyFilter(
and(gt(literal1, aRef), gt(aRef, literal5)),
RelOptPredicateList.EMPTY,
"false");

// range with no predicates;
// condition "a > 1 && a < 10 && a < 5" yields "a < 1 && a < 5"
checkSimplifyFilter(
Expand Down

0 comments on commit 06c18ca

Please sign in to comment.