From cf9b38d00caff4609e191178d6953fd18e710a81 Mon Sep 17 00:00:00 2001 From: wangyanjing Date: Fri, 6 Dec 2024 12:11:16 +0800 Subject: [PATCH] [CALCITE-6718] Optimize SubstitutionVisitor's splitFilter with early return and uniform simplification for equivalence checking --- .../calcite/plan/SubstitutionVisitor.java | 7 +++- .../org/apache/calcite/rex/RexSimplify.java | 2 +- ...terializedViewSubstitutionVisitorTest.java | 37 ++++++++++++++++++- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java index 5a76cb99b3e7..dc92ce21aa61 100644 --- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java +++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java @@ -297,8 +297,11 @@ void register(MutableRel result, MutableRel query) { RexNode condition, RexNode target) { final RexBuilder rexBuilder = simplify.rexBuilder; condition = simplify.simplify(condition); - target = simplify.simplify(target); RexNode condition2 = canonizeNode(rexBuilder, condition); + if (target.isAlwaysTrue()) { + return condition2; + } + target = simplify.simplify(target); RexNode target2 = canonizeNode(rexBuilder, target); // First, try splitting into ORs. @@ -321,7 +324,7 @@ void register(MutableRel result, MutableRel query) { RexUtil.composeConjunction(rexBuilder, ImmutableList.of(condition2, target2)); RexNode r = - canonizeNode(rexBuilder, simplify.simplifyUnknownAsFalse(x2)); + canonizeNode(rexBuilder, simplify.simplify(x2)); if (!r.isAlwaysFalse() && isEquivalent(condition2, r)) { List conjs = RelOptUtil.conjunctions(r); for (RexNode e : RelOptUtil.conjunctions(target2)) { diff --git a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java index ee20c5ad5d2d..a8d3e32bc4a6 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java +++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java @@ -1526,7 +1526,7 @@ RexNode simplifyAnd(RexCall e, RexUnknownAs unknownAs) { if (unknownAs == FALSE && predicateElimination) { simplifyAndTerms(operands, FALSE); } else { - simplifyList(operands, unknownAs); + simplifyAndTerms(operands, unknownAs); } final List terms = new ArrayList<>(); diff --git a/core/src/test/java/org/apache/calcite/test/MaterializedViewSubstitutionVisitorTest.java b/core/src/test/java/org/apache/calcite/test/MaterializedViewSubstitutionVisitorTest.java index 8e1419e9166c..39192fe09d09 100644 --- a/core/src/test/java/org/apache/calcite/test/MaterializedViewSubstitutionVisitorTest.java +++ b/core/src/test/java/org/apache/calcite/test/MaterializedViewSubstitutionVisitorTest.java @@ -34,6 +34,7 @@ import org.apache.calcite.rex.RexSimplify; import org.apache.calcite.rex.RexUtil; import org.apache.calcite.sql.fun.SqlStdOperatorTable; +import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.util.Pair; import com.google.common.collect.ImmutableList; @@ -1646,11 +1647,14 @@ protected final MaterializedViewFixture sql(String materialize, final RexBuilder rexBuilder = f.rexBuilder; final RexSimplify simplify = f.simplify; + final RelDataType intType = f.typeFactory.createType(int.class); + final RelDataType booleanType = f.typeFactory.createSqlType(SqlTypeName.BOOLEAN); final RexLiteral i1 = rexBuilder.makeExactLiteral(BigDecimal.ONE); final RexLiteral i2 = rexBuilder.makeExactLiteral(BigDecimal.valueOf(2)); final RexLiteral i3 = rexBuilder.makeExactLiteral(BigDecimal.valueOf(3)); + final RexLiteral nullIntLiteral = rexBuilder.makeNullLiteral(intType); + final RexLiteral nullBooleanLiteral = rexBuilder.makeNullLiteral(booleanType); - final RelDataType intType = f.typeFactory.createType(int.class); final RexInputRef x = rexBuilder.makeInputRef(intType, 0); // $0 final RexInputRef y = rexBuilder.makeInputRef(intType, 1); // $1 final RexInputRef z = rexBuilder.makeInputRef(intType, 2); // $2 @@ -1695,6 +1699,15 @@ protected final MaterializedViewFixture sql(String materialize, rexBuilder.makeCall(SqlStdOperatorTable.PLUS, x, y), i2); + // x in (null:int) + final RexNode x_in_null = rexBuilder.makeIn(x, ImmutableList.of(nullIntLiteral)); + // x in (null:int) and x = 1 + final RexNode x_in_null_and_x_eq_1 = + rexBuilder.makeCall(SqlStdOperatorTable.AND, x_in_null, x_eq_1); + // x = 1 and null:boolean + final RexNode x_eq_1_and_null = + rexBuilder.makeCall(SqlStdOperatorTable.AND, x_eq_1, nullBooleanLiteral); + RexNode newFilter; // Example 1. @@ -1853,6 +1866,28 @@ protected final MaterializedViewFixture sql(String materialize, SubstitutionVisitor.splitFilter(simplify, x_times_y_gt, y_times_x_gt); assertThat(newFilter, notNullValue()); assertThat(newFilter.isAlwaysTrue(), equalTo(true)); + + // Example 11. + // condition: x in (null:int) and x = 1 + // target: true + // yields + // residue: x = 1 and null:boolean + newFilter = + SubstitutionVisitor.splitFilter(simplify, x_in_null_and_x_eq_1, + rexBuilder.makeLiteral(true)); + assertThat(newFilter, notNullValue()); + assertThat(newFilter, equalTo(x_eq_1_and_null)); + + // Example 12. + // condition: x in (null:int) and x = 1 + // target: x = 1 + // yields + // residue: null:boolean + newFilter = + SubstitutionVisitor.splitFilter(simplify, x_in_null_and_x_eq_1, + x_eq_1); + assertThat(newFilter, notNullValue()); + assertThat(newFilter, equalTo(nullBooleanLiteral)); } @Test void testSubQuery() {