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