Repository: calcite Updated Branches: refs/heads/master 9f7e565ff -> c8e91ea1d
[CALCITE-2327] RexSimplify: AND(x, y, NOT(y)) ==> AND(x, null, IS NULL(y)) Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/c8e91ea1 Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/c8e91ea1 Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/c8e91ea1 Branch: refs/heads/master Commit: c8e91ea1db1e519d9d73bbb8b08ee27f710cb1d4 Parents: 6b2b9ff Author: Vladimir Sitnikov <[email protected]> Authored: Tue Aug 28 15:04:31 2018 +0300 Committer: Vladimir Sitnikov <[email protected]> Committed: Tue Aug 28 15:06:33 2018 +0300 ---------------------------------------------------------------------- .../org/apache/calcite/rex/RexSimplify.java | 22 ++++++++++++-------- .../org/apache/calcite/test/RexProgramTest.java | 20 ++++++++++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/c8e91ea1/core/src/main/java/org/apache/calcite/rex/RexSimplify.java ---------------------------------------------------------------------- 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 1274391..f5a99ef 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java +++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java @@ -718,7 +718,7 @@ public class RexSimplify { // Example #1. x AND y AND z AND NOT (x AND y) - not satisfiable // Example #2. x AND y AND NOT (x AND y) - not satisfiable // Example #3. x AND y AND NOT (x AND y AND z) - may be satisfiable - RexNode bestNotDisjunction = null; + List<RexNode> notSatisfiableNullables = null; for (RexNode notDisjunction : notTerms) { final List<RexNode> terms2 = RelOptUtil.conjunctions(notDisjunction); if (!terms.containsAll(terms2)) { @@ -732,17 +732,21 @@ public class RexSimplify { // x AND NOT(x) is UNKNOWN for NULL input // So we search for the shortest notDisjunction then convert // original expression to NULL and x IS NULL - if (bestNotDisjunction == null - || bestNotDisjunction.toString().length() > notDisjunction.toString().length()) { - bestNotDisjunction = notDisjunction; + if (notSatisfiableNullables == null) { + notSatisfiableNullables = new ArrayList<>(); } + notSatisfiableNullables.add(notDisjunction); } - if (bestNotDisjunction != null) { + if (notSatisfiableNullables != null) { + terms.removeAll(notSatisfiableNullables); + terms.add(rexBuilder.makeNullLiteral(notSatisfiableNullables.get(0).getType())); + for (RexNode notSatisfiableNullable : notSatisfiableNullables) { + terms.add( + simplifyIs((RexCall) + rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, notSatisfiableNullable))); + } // NULL AND (x IS NULL) - return rexBuilder.makeCall(SqlStdOperatorTable.AND, - rexBuilder.makeNullLiteral(bestNotDisjunction.getType()), - simplifyIs( - (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, bestNotDisjunction))); + return rexBuilder.makeCall(SqlStdOperatorTable.AND, terms); } // Add the NOT disjunctions back in. for (RexNode notDisjunction : notTerms) { http://git-wip-us.apache.org/repos/asf/calcite/blob/c8e91ea1/core/src/test/java/org/apache/calcite/test/RexProgramTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java index 25c99e5..7d0afee 100644 --- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java +++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java @@ -581,6 +581,26 @@ public class RexProgramTest extends RexProgramBuilderBase { } + @Test public void xAndNotX() { + checkSimplify2( + and(vBool(), not(vBool()), + vBool(1), not(vBool(1))), + "AND(null, IS NULL(?0.bool0), IS NULL(?0.bool1))", + "false"); + + checkSimplify2( + and(vBool(), + vBool(1), not(vBool(1))), + "AND(?0.bool0, null, IS NULL(?0.bool1))", + "false"); + + checkSimplify2( + and(vBool(), not(vBool()), + vBoolNotNull(1), not(vBoolNotNull(1))), + "false", + "false"); + } + /** Unit test for {@link org.apache.calcite.rex.RexUtil#isLosslessCast(RexNode)}. */ @Test public void testLosslessCast() { final RelDataType tinyIntType = typeFactory.createSqlType(SqlTypeName.TINYINT);
