This is an automated email from the ASF dual-hosted git repository. tanner pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/calcite.git
commit 7e1e0298cbf755966f4d043c9f43a2cc48112f87 Author: Runkang He <[email protected]> AuthorDate: Mon Jun 26 08:34:41 2023 +0800 [CALCITE-5798] Improve simplification of '(x < y) IS NOT TRUE' when x and y are not nullable --- .../apache/calcite/plan/RelOptPredicateList.java | 12 +++-- .../org/apache/calcite/rex/RexProgramTest.java | 51 ++++++++++++++++++++++ .../org/apache/calcite/rex/RexProgramTestBase.java | 7 ++- .../apache/calcite/test/SqlToRelConverterTest.xml | 4 +- core/src/test/resources/sql/sub-query.iq | 2 +- 5 files changed, 65 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java b/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java index 9045bb589a..0ce5fca94e 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java @@ -18,7 +18,6 @@ package org.apache.calcite.plan; import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexCall; -import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; import org.apache.calcite.rex.RexUtil; import org.apache.calcite.sql.SqlKind; @@ -236,14 +235,13 @@ public class RelOptPredicateList { } } if (SqlKind.COMPARISON.contains(e.getKind())) { - // A comparison with a (non-null) literal, such as 'ref < 10', is not null if 'ref' - // is not null. List<RexNode> operands = ((RexCall) e).getOperands(); - // We can have just one operand in case e.g. of a RexSubQuery with IN operator. - if (operands.size() > 1 && operands.get(1) instanceof RexLiteral - && !((RexLiteral) operands.get(1)).isNull()) { - return isEffectivelyNotNull(operands.get(0)); + for (RexNode operand : operands) { + if (!isEffectivelyNotNull(operand)) { + return false; + } } + return true; } return false; } diff --git a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java index 499b92525f..e2f7562462 100644 --- a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java +++ b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java @@ -2010,6 +2010,57 @@ class RexProgramTest extends RexProgramTestBase { ">(?0.int0, 0)"); } + /** Unit test for + * <a href="https://issues.apache.org/jira/browse/CALCITE-5798">[CALCITE-5798] + * Improve simplification of '(x < y) IS NOT TRUE' and '(x < y) IS TRUE' + * when x and y are not nullable</a>. */ + @Test void testSimplifyWithIsNotNullPredicate() { + final RexNode xRef = input(tInt(true), 0); + final RexNode yRef = input(tInt(true), 1); + RelOptPredicateList relOptPredicateList = + RelOptPredicateList.of(rexBuilder, + ImmutableList.of(isNotNull(xRef), isNotNull(yRef))); + + // "(x < y) IS TRUE" (if x and y are both not nullable) => "x < y" + checkSimplifyWithPredicates( + isTrue(lt(xRef, yRef)), + relOptPredicateList, + RexUnknownAs.UNKNOWN, + "<($0, $1)"); + + // "(x < y) IS NOT TRUE" (if x and y are both not nullable) => "x >= y" + checkSimplifyFilter( + isNotTrue(lt(xRef, yRef)), + relOptPredicateList, + ">=($0, $1)"); + + // "(x < 1) IS TRUE" (if x is not nullable) => "x < 1" + checkSimplifyWithPredicates( + isTrue(lt(xRef, literal(1))), + relOptPredicateList, + RexUnknownAs.UNKNOWN, + "<($0, 1)"); + + // "(x < 1) IS NOT TRUE" (if x is not nullable) => "x >= 1" + checkSimplifyFilter( + isNotTrue(lt(xRef, literal(1))), + relOptPredicateList, + ">=($0, 1)"); + + // "(1 < x) IS TRUE" (if x is not nullable) => "1 < x" + checkSimplifyWithPredicates( + isTrue(lt(literal(1), xRef)), + relOptPredicateList, + RexUnknownAs.UNKNOWN, + "<(1, $0)"); + + // "(1 >= x) IS NOT TRUE" (if x is not nullable) => "1 >= x" + checkSimplifyFilter( + isNotTrue(lt(literal(1), xRef)), + relOptPredicateList, + ">=(1, $0)"); + } + /** Test strategies for {@code SargCollector.canMerge(Sarg, RexUnknownAs)}. */ @Test void testSargMerge() { checkSimplify3( diff --git a/core/src/test/java/org/apache/calcite/rex/RexProgramTestBase.java b/core/src/test/java/org/apache/calcite/rex/RexProgramTestBase.java index 111976ff1e..ba8d35895e 100644 --- a/core/src/test/java/org/apache/calcite/rex/RexProgramTestBase.java +++ b/core/src/test/java/org/apache/calcite/rex/RexProgramTestBase.java @@ -161,9 +161,14 @@ class RexProgramTestBase extends RexProgramBuilderBase { protected void checkSimplifyFilter(RexNode node, RelOptPredicateList predicates, String expected) { + checkSimplifyWithPredicates(node, predicates, RexUnknownAs.FALSE, expected); + } + + protected void checkSimplifyWithPredicates(RexNode node, + RelOptPredicateList predicates, RexUnknownAs unknownAs, String expected) { final RexNode simplified = simplify.withPredicates(predicates) - .simplifyUnknownAs(node, RexUnknownAs.FALSE); + .simplifyUnknownAs(node, unknownAs); assertThat(simplified, hasToString(expected)); } diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml index 6a8d48867d..2f0dadc19f 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -98,10 +98,10 @@ from empnullables]]> <Resource name="plan"> <![CDATA[ LogicalAggregate(group=[{}], EXPR$0=[COUNT() FILTER $0]) - LogicalProject($f0=[IS TRUE(IN($0, { + LogicalProject($f0=[CAST(IN($0, { LogicalProject(DEPTNO=[$7]) LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]]) -}))]) +})):BOOLEAN NOT NULL]) LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]]) ]]> </Resource> diff --git a/core/src/test/resources/sql/sub-query.iq b/core/src/test/resources/sql/sub-query.iq index f704fb41e5..42bc10884a 100644 --- a/core/src/test/resources/sql/sub-query.iq +++ b/core/src/test/resources/sql/sub-query.iq @@ -2143,7 +2143,7 @@ select empno from "scott".emp as e where e.empno > ANY( select 2 from "scott".dept e2 where e2.deptno = e.deptno) ; EnumerableCalc(expr#0..1=[{inputs}], EMPNO=[$t0]) - EnumerableHashJoin(condition=[AND(=($1, $6), OR(AND(>($0, $2), <>($3, 0)), AND(>($0, $2), <>($3, 0), IS NOT TRUE(>($0, $2)), IS NOT TRUE(>($3, $4)))))], joinType=[semi]) + EnumerableHashJoin(condition=[AND(=($1, $6), >($0, $2))], joinType=[semi]) EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], DEPTNO=[$t7]) EnumerableTableScan(table=[[scott, EMP]]) EnumerableCalc(expr#0..2=[{inputs}], expr#3=[2], expr#4=[1:BIGINT], expr#5=[true], m=[$t3], c=[$t4], d=[$t4], trueLiteral=[$t5], DEPTNO=[$t0])
