rubenada commented on code in PR #5184:
URL: https://github.com/apache/calcite/pull/5184#discussion_r3802666450
##########
core/src/test/java/org/apache/calcite/rex/RexProgramTest.java:
##########
@@ -3024,6 +3024,82 @@ trueLiteral, literal(1),
checkSimplifyUnchanged(div(cast(vVarchar(), tInt(false)), nullInt));
}
+ /** Test cases for peeling {@code IS [NOT] NULL} across a strong outer
+ * operator whose subtree contains a non-lossless {@code CAST}.
+ *
+ * <p>Distributing {@code IS [NOT] NULL} across a strong operator (e.g.
+ * {@code +}, {@code *}) preserves subtree evaluation: each operand is
+ * either recursively simplified or rewrapped verbatim as
+ * {@code IS [NOT] NULL(operand)}, so the presence of a non-lossless
+ * {@code CAST} deeper in the tree must not block the distribution. */
+ @Test void testSimplifyIsNotNullDistributesAcrossStrongOpWithLossyCast() {
+ // "(CAST(?0.varchar0):INTEGER + 1) IS NOT NULL"
+ // ==> "IS NOT NULL(CAST(?0.varchar0):INTEGER)"
+ // The outer PLUS is strong AND shallow-safe; distribution keeps the
+ // non-lossless CAST inside the rewrapped IS NOT NULL.
+ checkSimplify(
+ isNotNull(plus(cast(vVarchar(), tInt(true)), literal(1))),
+ "IS NOT NULL(CAST(?0.varchar0):INTEGER)");
+
+ // Symmetric IS NULL peel:
+ // "(CAST(?0.varchar0):INTEGER + 1) IS NULL"
+ // ==> "IS NULL(CAST(?0.varchar0):INTEGER)"
+ checkSimplify(
+ isNull(plus(cast(vVarchar(), tInt(true)), literal(1))),
+ "IS NULL(CAST(?0.varchar0):INTEGER)");
+
+ // Confirm this is consistent with same expression without CAST
+ checkSimplify(isNotNull(plus(vInt(), literal(1))), "IS NOT NULL(?0.int0)");
+ checkSimplify(isNull(plus(vInt(), literal(1))), "IS NULL(?0.int0)");
+
+ // MULTIPLY is also strong + shallow-safe.
+ checkSimplify(
+ isNotNull(mul(cast(vVarchar(), tInt(true)), literal(2))),
+ "IS NOT NULL(CAST(?0.varchar0):INTEGER)");
+ checkSimplify(
+ isNull(mul(cast(vVarchar(), tInt(true)), literal(2))),
+ "IS NULL(CAST(?0.varchar0):INTEGER)");
+ checkSimplify(isNotNull(mul(vInt(), literal(2))), "IS NOT NULL(?0.int0)");
+ checkSimplify(isNull(mul(vInt(), literal(2))), "IS NULL(?0.int0)");
+
+ // Nested PLUS on both sides: distribution still peels one layer
+ // and stops at the inner CAST, which is not shallow-safe.
+ // "((CAST(?0.varchar0):INTEGER + 1) + 2) IS NOT NULL"
+ // ==> "IS NOT NULL(CAST(?0.varchar0):INTEGER)"
+ checkSimplify(
+ isNotNull(
+ plus(plus(cast(vVarchar(), tInt(true)), literal(1)), literal(2))),
+ "IS NOT NULL(CAST(?0.varchar0):INTEGER)");
+ }
+
+ /** The distribution must still be suppressed when the outer node is
+ * itself not shallow-safe (e.g. DIVIDE by a literal zero) or when an
+ * operand is typed non-nullable yet not fully safe, otherwise
+ * {@link org.apache.calcite.rex.RexCall#isAlwaysTrue()} would collapse
+ * the rewrapped {@code IS NOT NULL(operand)} to {@code TRUE} and hide
+ * the runtime throw. */
+ @Test void testSimplifyIsNotNullDoesNotDistributeAcrossUnsafeOuter() {
+ // The outer PLUS is shallow-safe, but the div(1, 0) operand is typed
+ // non-nullable, so the peel would rewrap it as IS NOT NULL(/(1, 0))
+ // which the trivial isAlwaysTrue() shortcut would collapse to TRUE
+ // and lose the throw. The peel is therefore suppressed.
+ checkSimplifyUnchanged(isNotNull(plus(div(literal(1), literal(0)),
vIntNotNull())));
+ checkSimplifyUnchanged(isNull(plus(div(literal(1), literal(0)),
vIntNotNull())));
+
+ // IS NOT NULL(x/0) itself is not peeled, because DIVIDE with a
+ // literal-zero divisor is not shallow-safe (this branch would
+ // otherwise drop the throwing subexpression).
+ checkSimplifyUnchanged(isNotNull(div(vIntNotNull(), literal(0))));
+ checkSimplifyUnchanged(isNull(div(vIntNotNull(), literal(0))));
+ checkSimplifyUnchanged(isNull(div(cast(vIntNotNull(), tBigInt()),
literal(0))));
+
+ // IS NULL(CAST(10/0 AS BIGINT)) stays as IS NULL(10/0)
+ // after the lossless-CAST strip; the DIVIDE is not
+ // shallow-safe, so no further distribution occurs.
+ checkSimplify(isNull(cast(div(vIntNotNull(), literal(0)), tBigInt())),
Review Comment:
good point; added both cases
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]