This is an automated email from the ASF dual-hosted git repository.

rubenada pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new 116a746c42 [CALCITE-7758] RexSimplify does not absorb redundant IS NOT 
NULL on non-input-ref sub-expressions in AND simplification
116a746c42 is described below

commit 116a746c426971d6a62b18b069169ff294de7f9d
Author: Ruben Quesada Lopez <[email protected]>
AuthorDate: Mon Aug 31 16:58:04 2026 +0100

    [CALCITE-7758] RexSimplify does not absorb redundant IS NOT NULL on 
non-input-ref sub-expressions in AND simplification
---
 .../java/org/apache/calcite/rex/RexSimplify.java   | 19 ++++++++++++
 .../org/apache/calcite/rex/RexProgramTest.java     | 36 ++++++++++++++++++++++
 2 files changed, 55 insertions(+)

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 98fbbb781b..cf18e7c6f5 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -2139,6 +2139,25 @@ private <C extends Comparable<C>> RexNode 
simplifyAnd2ForUnknownAsFalse(
           strongOperands.add(rexFieldAccess);
         }
       }
+      // Also probe sub-expressions coming from IS_NOT_NULL(...) predicates 
that
+      // are not bare input refs or field accesses (e.g. CAST calls); without
+      // this, IS_NOT_NULL(CAST(x)) AND (CAST(x) + 1) < 10 would not be 
absorbed
+      for (RexNode operand : notNullOperands) {
+        if (operand instanceof RexInputRef
+            || operand instanceof RexFieldAccess
+            || strongOperands.contains(operand)
+            || !RexUtil.isDeterministic(operand)) {
+          continue;
+        }
+        final Strong strong = new Strong() {
+          @Override public boolean isNull(RexNode node) {
+            return node.equals(operand) || super.isNull(node);
+          }
+        };
+        if (strong.isNotTrue(term)) {
+          strongOperands.add(operand);
+        }
+      }
     }
     // If one column should be null and is in a comparison predicate,
     // it is not satisfiable.
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 0dbbcd9cde..2a2efb7521 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
@@ -30,6 +30,7 @@
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
+import org.apache.calcite.sql.fun.SqlLibraryOperators;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
@@ -3025,6 +3026,41 @@ trueLiteral, literal(1),
     checkSimplifyUnchanged(div(cast(vVarchar(), tInt(false)), nullInt));
   }
 
+  /**
+   * Test cases for <a 
href="https://issues.apache.org/jira/browse/CALCITE-7758";>[CALCITE-7758]
+   * RexSimplify does not absorb redundant IS NOT NULL on non-input-ref 
sub-expressions
+   * in AND simplification</a>.
+   */
+  @Test void testSimplifyIsNotNullAndStrongExpression() {
+    // "unsafe" cast: (CAST(a) + 1) < 10 AND IS_NOT_NULL(CAST(a)) ==> (CAST(a) 
+ 1) < 10
+    checkSimplifyFilter(
+        and(
+            lt(plus(cast(vVarchar(), tDouble(true)), literal(1)), literal(10)),
+            isNotNull(cast(vVarchar(), tDouble(true)))),
+        "<(+(CAST(?0.varchar0):DOUBLE, 1), 10)");
+
+    // safe cast: (CAST(a) + 1) < 10 AND IS_NOT_NULL(CAST(a)) ==> (CAST(a) + 
1) < 10
+    checkSimplifyFilter(
+        and(
+            lt(plus(cast(vInt(), tDouble(true)), literal(1)), literal(10)),
+            isNotNull(cast(vInt(), tDouble(true)))),
+        "<(+(CAST(?0.int0):DOUBLE, 1), 10)");
+
+    // op that can return NULL on non-NULL args:
+    // IS_NOT_NULL(REGEXP_SUBSTR(myField, '[xw]yz')) AND 
REGEXP_SUBSTR(myField, '[xw]yz') = 'xyz'
+    // ==> REGEXP_SUBSTR(myField, '[xw]yz') = 'xyz'
+    checkSimplifyFilter(
+        and(
+            isNotNull(
+                rexBuilder.makeCall(
+                SqlLibraryOperators.REGEXP_SUBSTR, vVarchar(), 
literal("[xw]yz"))),
+            eq(
+                rexBuilder.makeCall(
+                    SqlLibraryOperators.REGEXP_SUBSTR, vVarchar(), 
literal("[xw]yz")),
+                literal("xyz"))),
+        "=(REGEXP_SUBSTR(?0.varchar0, '[xw]yz'), 'xyz')");
+  }
+
   /**
    * Test cases for <a 
href="https://issues.apache.org/jira/browse/CALCITE-7722";>[CALCITE-7722]
    * RexSimplify IS [NOT] NULL on a safe operator with Strong policy ANY and 
unsafe operands

Reply via email to