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

xuzifu666 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 2e5c1585c4 [CALCITE-5907] RexSimplify replaces a comparison with a 
BOOLEAN literal by a non-BOOLEAN operand
2e5c1585c4 is described below

commit 2e5c1585c4fd4ad5279b8a11b7ea62100fbbbcbe
Author: Yu Xu <[email protected]>
AuthorDate: Thu Oct 8 22:25:42 2026 +0800

    [CALCITE-5907] RexSimplify replaces a comparison with a BOOLEAN literal by 
a non-BOOLEAN operand
---
 .../java/org/apache/calcite/rex/RexSimplify.java   | 11 +++-
 .../org/apache/calcite/rex/RexProgramTest.java     | 58 ++++++++++++++++++++++
 2 files changed, 68 insertions(+), 1 deletion(-)

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 65461ddab6..3bbfa92916 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -703,6 +703,12 @@ private static boolean 
containsEquivalentComparison(List<RexNode> nodes,
     return false;
   }
 
+  /** Returns whether both operands of a comparison have type BOOLEAN. */
+  private static boolean isBooleanComparison(RexNode left, RexNode right) {
+    return left.getType().getSqlTypeName() == SqlTypeName.BOOLEAN
+        && right.getType().getSqlTypeName() == SqlTypeName.BOOLEAN;
+  }
+
   // e must be a comparison (=, >, >=, <, <=, !=)
   private RexNode simplifyComparison(RexCall e, RexUnknownAs unknownAs) {
     //noinspection unchecked
@@ -748,7 +754,7 @@ private <C extends Comparable<C>> RexNode 
simplifyComparison(RexCall e,
       }
     }
 
-    if (o0.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
+    if (isBooleanComparison(o0, o1)) {
       Comparison cmp =
           Comparison.of(
               rexBuilder.makeCall(e.getParserPosition(), e.getOperator(), o0, 
o1), node -> true);
@@ -2013,6 +2019,9 @@ private <C extends Comparable<C>> RexNode 
simplifyAnd2ForUnknownAsFalse(
       // Simplify BOOLEAN expressions if possible
       while (term.getKind() == SqlKind.EQUALS) {
         RexCall call = (RexCall) term;
+        if (!isBooleanComparison(call.getOperands().get(0), 
call.getOperands().get(1))) {
+          break;
+        }
         if (call.getOperands().get(0).isAlwaysTrue()) {
           term = call.getOperands().get(1);
           terms.set(i, term);
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 dc3c5fb423..4b5283451c 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
@@ -2472,6 +2472,64 @@ private void checkExponentialCnf(int n) {
         "=(?0.notNullInt0, ?0.int1)");
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5907";>[CALCITE-5907]
+   * RexSimplify replaces a comparison with a BOOLEAN literal by a non-BOOLEAN
+   * operand</a>.
+   */
+  @Test void testSimplifyAndEqualityTrue() {
+    // "=(x, true)" simplifies to "x" only if x is BOOLEAN;
+    // otherwise the AND would get a non-BOOLEAN operand
+    //
+    // With paranoid mode on, a wrong simplification of these non-BOOLEAN
+    // inputs fails inside RexSimplify.verify with an exception that hides
+    // the result; turn it off so that checkSimplifyUnchanged prints the
+    // simplified expression
+    simplify = this.simplify.withParanoid(false);
+    checkSimplifyUnchanged(
+        and(eq(vVarchar(0), trueLiteral),
+            eq(vVarchar(1), trueLiteral)));
+    checkSimplifyUnchanged(
+        and(eq(vInt(0), trueLiteral),
+            eq(vInt(1), trueLiteral)));
+    // same, with NOT NULL variables
+    checkSimplifyUnchanged(
+        and(eq(vVarcharNotNull(0), trueLiteral),
+            eq(vVarcharNotNull(1), trueLiteral)));
+    checkSimplifyUnchanged(
+        and(eq(vIntNotNull(0), trueLiteral),
+            eq(vIntNotNull(1), trueLiteral)));
+    // literal on the left (swapped) form
+    checkSimplifyUnchanged(eq(trueLiteral, vVarchar(0)));
+    checkSimplifyUnchanged(
+        and(eq(trueLiteral, vVarchar(0)),
+            eq(trueLiteral, vVarchar(1))));
+    checkSimplifyUnchanged(
+        and(eq(falseLiteral, vVarchar(0)),
+            eq(falseLiteral, vVarchar(1))));
+    checkSimplifyUnchanged(
+        and(ne(falseLiteral, vVarchar(0)),
+            ne(falseLiteral, vVarchar(1))));
+    // "=($0, true)" stays when $0 has type ANY, since its value need not be
+    // BOOLEAN; ITEM on a MAP<VARCHAR, ANY> column, such as MongoDB's _MAP,
+    // has type ANY
+    final RexNode anyRef = input(typeFactory.createSqlType(SqlTypeName.ANY), 
0);
+    checkSimplifyUnchanged(
+        and(eq(anyRef, trueLiteral), vBool(1)));
+    simplify = simplify.withParanoid(true);
+
+    // "=(x, true)" is simplified to "x" if x has BOOLEAN type
+    checkSimplifyFilter(
+        and(eq(vBool(0), trueLiteral),
+            eq(vBool(1), trueLiteral)),
+        "AND(?0.bool0, ?0.bool1)");
+    // same, with NOT NULL variables
+    checkSimplifyFilter(
+        and(eq(vBoolNotNull(0), trueLiteral),
+            eq(vBoolNotNull(1), trueLiteral)),
+        "AND(?0.notNullBool0, ?0.notNullBool1)");
+  }
+
   @Test void testSimplifyEqualityAndNotEqualityWithOverlapping() {
     final RexLiteral literal3 = literal(3);
     final RexLiteral literal5 = literal(5);

Reply via email to