Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions core/src/main/java/org/apache/calcite/rex/RexCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,13 @@ private boolean digestWithType() {
return operands.get(0).isAlwaysFalse();
case IS_NOT_FALSE:
case IS_TRUE:
case CAST:
return operands.get(0).isAlwaysTrue();
case CAST:
// Only delegate to the operand if the result type is also BOOLEAN.
// CAST(TRUE AS INTEGER) has isAlwaysTrue() == false even though its
// operand is always true, because the result is an INTEGER, not a BOOLEAN.
return getType().getSqlTypeName() == SqlTypeName.BOOLEAN
&& operands.get(0).isAlwaysTrue();
case SEARCH:
final Sarg<?> sarg = ((RexLiteral) operands.get(1)).getValueAs(Sarg.class);
return requireNonNull(sarg, "sarg").isAll()
Expand All @@ -250,8 +255,11 @@ private boolean digestWithType() {
return operands.get(0).isAlwaysTrue();
case IS_NOT_FALSE:
case IS_TRUE:
case CAST:
return operands.get(0).isAlwaysFalse();
case CAST:
// Only delegate to the operand if the result type is also BOOLEAN.
return getType().getSqlTypeName() == SqlTypeName.BOOLEAN
&& operands.get(0).isAlwaysFalse();
case SEARCH:
final Sarg<?> sarg = ((RexLiteral) operands.get(1)).getValueAs(Sarg.class);
return requireNonNull(sarg, "sarg").isNone()
Expand Down
49 changes: 49 additions & 0 deletions core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4130,6 +4130,55 @@ private void checkSarg(String message, Sarg sarg,
checkSimplify(isTrue(like(ref, literal("%"))), "IS NOT NULL($0)");
}

/** Unit tests for
* <a href="https://issues.apache.org/jira/browse/CALCITE-7542">[CALCITE-7542]
* RexCall.isAlwaysTrue()/isAlwaysFalse() incorrectly returns true
* for CAST(boolean AS non-boolean)</a>. */
@Test void testIsAlwaysTrueCastBooleanToInteger() {
// CAST(TRUE AS INTEGER) is not a boolean expression; isAlwaysTrue() must be false.
final RexNode castTrueToInt = abstractCast(trueLiteral, tInt());
assertThat("CAST(TRUE AS INTEGER).isAlwaysTrue()",
castTrueToInt.isAlwaysTrue(), is(false));
assertThat("CAST(TRUE AS INTEGER).isAlwaysFalse()",
castTrueToInt.isAlwaysFalse(), is(false));
}

@Test void testIsAlwaysFalseCastBooleanToInteger() {
// CAST(FALSE AS INTEGER) is not a boolean expression; isAlwaysFalse() must be false.
final RexNode castFalseToInt = abstractCast(falseLiteral, tInt());
assertThat("CAST(FALSE AS INTEGER).isAlwaysFalse()",
castFalseToInt.isAlwaysFalse(), is(false));
assertThat("CAST(FALSE AS INTEGER).isAlwaysTrue()",
castFalseToInt.isAlwaysTrue(), is(false));
}

@Test void testIsAlwaysTrueCastBooleanToBoolean() {
// CAST(TRUE AS BOOLEAN) preserves the always-true property.
final RexNode castTrueToBool = abstractCast(trueLiteral, tBool());
assertThat("CAST(TRUE AS BOOLEAN).isAlwaysTrue()",
castTrueToBool.isAlwaysTrue(), is(true));
}

@Test void testIsAlwaysFalseCastBooleanToBoolean() {
// CAST(FALSE AS BOOLEAN) preserves the always-false property.
final RexNode castFalseToBool = abstractCast(falseLiteral, tBool());
assertThat("CAST(FALSE AS BOOLEAN).isAlwaysFalse()",
castFalseToBool.isAlwaysFalse(), is(true));
}

@Test void testIsAlwaysTrueFalseCastNonBooleanCallToBoolean() {
// CAST(1 + 1 AS BOOLEAN): the inner operand is a non-literal, non-boolean
// RexCall. isAlwaysTrue()/isAlwaysFalse() must safely return false on the
// recursive call rather than crashing — the contract is "ask freely, get
// a safe false for non-boolean expressions," matching RexLiteral and the
// RexNode base class.
final RexNode castIntExprToBool = abstractCast(plus(literal(1), literal(1)), tBool());
assertThat("CAST(1 + 1 AS BOOLEAN).isAlwaysTrue()",
castIntExprToBool.isAlwaysTrue(), is(false));
assertThat("CAST(1 + 1 AS BOOLEAN).isAlwaysFalse()",
castIntExprToBool.isAlwaysFalse(), is(false));
}

/** Unit tests for
* <a href="https://issues.apache.org/jira/browse/CALCITE-2438">[CALCITE-2438]
* RexCall#isAlwaysTrue returns incorrect result</a>. */
Expand Down
Loading