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])

Reply via email to