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 becfe66efca3..f08e0f1b63f2 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java +++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java @@ -1560,18 +1560,55 @@ private > RexNode simplifyAnd2ForUnknownAsFalse( return RexUtil.composeConjunction(rexBuilder, terms); } + private RexNode simplifyNotEqual(RexNode e) { + final Comparison comparison = Comparison.of(e); + if (comparison == null) { + return e; + } + + for (RexNode node: predicates.pulledUpPredicates) { + final Comparison predicate = Comparison.of(node); + if (predicate == null + || predicate.kind != SqlKind.EQUALS + || !predicate.ref.equals(comparison.ref)) { + continue; + } + + // Given x=5, x!=5 can be simplified to 'null and x is null' and x!=3 can + // be simplified to 'null or x is not null'. + RexNode simplified; + if (predicate.literal.equals(comparison.literal)) { + simplified = rexBuilder.makeCall(SqlStdOperatorTable.AND, + rexBuilder.makeNullLiteral(e.getType()), + rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, comparison.ref)); + } else { + simplified = rexBuilder.makeCall(SqlStdOperatorTable.OR, + rexBuilder.makeNullLiteral(e.getType()), + rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, comparison.ref)); + } + return simplify(simplified); + } + + return e; + } + private > RexNode simplifyUsingPredicates(RexNode e, Class clazz) { if (predicates.pulledUpPredicates.isEmpty()) { return e; } + + if (e.getKind() == SqlKind.NOT_EQUALS) { + return simplifyNotEqual(e); + } + final Comparison comparison = Comparison.of(e); // Check for comparison with null values if (comparison == null - || comparison.kind == SqlKind.NOT_EQUALS || comparison.literal.getValue() == null) { return e; } + final C v0 = comparison.literal.getValueAs(clazz); final Range range = range(comparison.kind, v0); final Range range2 = 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 76b82eb04448..14d2c0d4ecb0 100644 --- a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java +++ b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java @@ -2551,6 +2551,20 @@ private static String getString(ImmutableMap map) { checkSimplifyFilter(gt(ref, literal(9)), relOptPredicateList, "false"); } + @Test public void testSimplifyNotEqual() { + RexNode ref = input(tInt(), 0); + RelOptPredicateList relOptPredicateList = RelOptPredicateList.of(rexBuilder, + ImmutableList.of(eq(ref, literal(9)))); + checkSimplifyFilter(ne(ref, literal(9)), relOptPredicateList, "false"); + checkSimplifyFilter(ne(ref, literal(5)), relOptPredicateList, "true"); + + ref = input(tInt(true), 0); + checkSimplifyFilter(ne(ref, literal(9)), relOptPredicateList, + "AND(null, IS NULL($0))"); + checkSimplifyFilter(ne(ref, literal(5)), relOptPredicateList, + "OR(null, IS NOT NULL($0))"); + } + @Test public void testSimplifyNonDeterministicFunction() { final SqlOperator ndc = new SqlSpecialOperator( "NDC", diff --git a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java index 4270115cb137..5b609a9d037a 100644 --- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java +++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java @@ -1208,7 +1208,7 @@ private static void checkNoMaterialize_(String materialize, String query, SqlStdOperatorTable.AND, i0_eq_0, i1_eq_1))); - checkSatisfiable(e6, "AND(=($0, 0), OR(<>($0, 0), <>($1, 1)))"); + checkSatisfiable(e6, "AND(=($0, 0), <>($1, 1))"); // "$0 = 0 AND ($1 = 1 AND NOT ($0 = 0))" is not satisfiable. final RexNode e7 = diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml index 9d04144a402d..cd291496879d 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -152,7 +152,7 @@ where case when (sal = 1000) then ($5, 1000)))]) + LogicalFilter(condition=[OR(=($5, 1000), =($5, 2000))]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]>