Repository: calcite
Updated Branches:
  refs/heads/master f21719623 -> 5bf7b9a4d


[CALCITE-2205] JoinPushTransitivePredicatesRule should not create Filter on top 
of equivalent Filter (Vitalii Diravka)

Close apache/calcite#645


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/499f0c6e
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/499f0c6e
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/499f0c6e

Branch: refs/heads/master
Commit: 499f0c6e9c3b2c35b803037f5b60e54fd4a6a5f3
Parents: f217196
Author: Vitalii Diravka <[email protected]>
Authored: Tue Mar 6 14:49:26 2018 +0200
Committer: Julian Hyde <[email protected]>
Committed: Sat Mar 24 15:58:00 2018 -0700

----------------------------------------------------------------------
 .../calcite/rel/metadata/RelMdPredicates.java   | 102 ++++++++++---------
 .../org/apache/calcite/rex/RexSimplify.java     |  19 ++++
 .../org/apache/calcite/tools/RelBuilder.java    |  14 +--
 .../org/apache/calcite/test/RelBuilderTest.java |  18 ++++
 .../apache/calcite/test/RelMetadataTest.java    |   8 +-
 .../apache/calcite/test/RelOptRulesTest.java    |  26 +++++
 .../org/apache/calcite/test/RexProgramTest.java |  21 +++-
 .../org/apache/calcite/test/RelOptRulesTest.xml |  58 +++++++++--
 8 files changed, 195 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/499f0c6e/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java 
b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
index bf3a241..2c69ed5 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
@@ -290,40 +290,31 @@ public class RelMdPredicates
                     RelOptUtil.conjunctions(filter.getCondition()))));
   }
 
-  /** Infers predicates for a {@link org.apache.calcite.rel.core.SemiJoin}. */
-  public RelOptPredicateList getPredicates(SemiJoin semiJoin,
-      RelMetadataQuery mq) {
-    RexBuilder rB = semiJoin.getCluster().getRexBuilder();
-    final RelNode left = semiJoin.getInput(0);
-    final RelNode right = semiJoin.getInput(1);
-
-    final RelOptPredicateList leftInfo = mq.getPulledUpPredicates(left);
-    final RelOptPredicateList rightInfo = mq.getPulledUpPredicates(right);
-
-    JoinConditionBasedPredicateInference jI =
-        new JoinConditionBasedPredicateInference(semiJoin,
-            RexUtil.composeConjunction(rB, leftInfo.pulledUpPredicates, false),
-            RexUtil.composeConjunction(rB, rightInfo.pulledUpPredicates, 
false));
-
-    return jI.inferPredicates(false);
-  }
-
-  /** Infers predicates for a {@link org.apache.calcite.rel.core.Join}. */
+  /**
+   * Infers predicates for a {@link org.apache.calcite.rel.core.Join} 
(including
+   * {@link org.apache.calcite.rel.core.SemiJoin}).
+   */
   public RelOptPredicateList getPredicates(Join join, RelMetadataQuery mq) {
-    RexBuilder rB = join.getCluster().getRexBuilder();
-    RelNode left = join.getInput(0);
-    RelNode right = join.getInput(1);
+    RelOptCluster cluster = join.getCluster();
+    RexBuilder rexBuilder = cluster.getRexBuilder();
+    final RexExecutor executor =
+        Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR);
+    final RelNode left = join.getInput(0);
+    final RelNode right = join.getInput(1);
 
     final RelOptPredicateList leftInfo = mq.getPulledUpPredicates(left);
     final RelOptPredicateList rightInfo = mq.getPulledUpPredicates(right);
 
-    JoinConditionBasedPredicateInference jI =
+    final RexSimplify simplifier =
+        new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, true, executor);
+
+    JoinConditionBasedPredicateInference joinInference =
         new JoinConditionBasedPredicateInference(join,
-            RexUtil.composeConjunction(rB, leftInfo.pulledUpPredicates, false),
-            RexUtil.composeConjunction(rB, rightInfo.pulledUpPredicates,
-                false));
+            RexUtil.composeConjunction(rexBuilder, 
leftInfo.pulledUpPredicates, false),
+            RexUtil.composeConjunction(rexBuilder, 
rightInfo.pulledUpPredicates, false),
+            simplifier);
 
-    return jI.inferPredicates(false);
+    return joinInference.inferPredicates(false);
   }
 
   /**
@@ -374,7 +365,7 @@ public class RelMdPredicates
    * Infers predicates for a Union.
    */
   public RelOptPredicateList getPredicates(Union union, RelMetadataQuery mq) {
-    RexBuilder rB = union.getCluster().getRexBuilder();
+    RexBuilder rexBuilder = union.getCluster().getRexBuilder();
 
     Map<String, RexNode> finalPreds = new HashMap<>();
     List<RexNode> finalResidualPreds = new ArrayList<>();
@@ -399,14 +390,14 @@ public class RelMdPredicates
         }
       }
       // Add new residual preds
-      finalResidualPreds.add(RexUtil.composeConjunction(rB, residualPreds, 
false));
+      finalResidualPreds.add(RexUtil.composeConjunction(rexBuilder, 
residualPreds, false));
       // Add those that are not part of the final set to residual
       for (Entry<String, RexNode> e : finalPreds.entrySet()) {
         if (!preds.containsKey(e.getKey())) {
           // This node was in previous union inputs, but it is not in this one
           for (int j = 0; j < i; j++) {
             finalResidualPreds.set(j,
-                RexUtil.composeConjunction(rB,
+                RexUtil.composeConjunction(rexBuilder,
                     Lists.newArrayList(finalResidualPreds.get(j), 
e.getValue()), false));
           }
         }
@@ -421,12 +412,12 @@ public class RelMdPredicates
         Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR);
     final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
     final RexSimplify simplify =
-        new RexSimplify(rB, predicates, true, executor);
+        new RexSimplify(rexBuilder, predicates, true, executor);
     RexNode disjPred = simplify.simplifyOrs(finalResidualPreds);
     if (!disjPred.isAlwaysTrue()) {
       preds.add(disjPred);
     }
-    return RelOptPredicateList.of(rB, preds);
+    return RelOptPredicateList.of(rexBuilder, preds);
   }
 
   /**
@@ -497,21 +488,23 @@ public class RelMdPredicates
     final ImmutableBitSet allFieldsBitSet;
     SortedMap<Integer, BitSet> equivalence;
     final Map<String, ImmutableBitSet> exprFields;
-    final Set<String> allExprsDigests;
+    final Set<String> allExprDigests;
     final Set<String> equalityPredicates;
     final RexNode leftChildPredicates;
     final RexNode rightChildPredicates;
+    final RexSimplify simplifier;
 
     JoinConditionBasedPredicateInference(Join joinRel,
-            RexNode lPreds, RexNode rPreds) {
-      this(joinRel, joinRel instanceof SemiJoin, lPreds, rPreds);
+            RexNode lPreds, RexNode rPreds, RexSimplify simplifier) {
+      this(joinRel, joinRel instanceof SemiJoin, lPreds, rPreds, simplifier);
     }
 
     private JoinConditionBasedPredicateInference(Join joinRel, boolean 
isSemiJoin,
-        RexNode lPreds, RexNode rPreds) {
+        RexNode lPreds, RexNode rPreds, RexSimplify simplifier) {
       super();
       this.joinRel = joinRel;
       this.isSemiJoin = isSemiJoin;
+      this.simplifier = simplifier;
       nFieldsLeft = joinRel.getLeft().getRowType().getFieldList().size();
       nFieldsRight = joinRel.getRight().getRowType().getFieldList().size();
       nSysFields = joinRel.getSystemFieldList().size();
@@ -523,7 +516,7 @@ public class RelMdPredicates
           nSysFields + nFieldsLeft + nFieldsRight);
 
       exprFields = Maps.newHashMap();
-      allExprsDigests = new HashSet<>();
+      allExprDigests = new HashSet<>();
 
       if (lPreds == null) {
         leftChildPredicates = null;
@@ -533,9 +526,10 @@ public class RelMdPredicates
         leftChildPredicates = lPreds.accept(
             new RexPermuteInputsShuttle(leftMapping, joinRel.getInput(0)));
 
+        allExprDigests.add(leftChildPredicates.toString());
         for (RexNode r : RelOptUtil.conjunctions(leftChildPredicates)) {
           exprFields.put(r.toString(), RelOptUtil.InputFinder.bits(r));
-          allExprsDigests.add(r.toString());
+          allExprDigests.add(r.toString());
         }
       }
       if (rPreds == null) {
@@ -547,9 +541,10 @@ public class RelMdPredicates
         rightChildPredicates = rPreds.accept(
             new RexPermuteInputsShuttle(rightMapping, joinRel.getInput(1)));
 
+        allExprDigests.add(rightChildPredicates.toString());
         for (RexNode r : RelOptUtil.conjunctions(rightChildPredicates)) {
           exprFields.put(r.toString(), RelOptUtil.InputFinder.bits(r));
-          allExprsDigests.add(r.toString());
+          allExprDigests.add(r.toString());
         }
       }
 
@@ -595,12 +590,12 @@ public class RelMdPredicates
     public RelOptPredicateList inferPredicates(
         boolean includeEqualityInference) {
       final List<RexNode> inferredPredicates = new ArrayList<>();
-      final Set<String> allExprsDigests = new HashSet<>(this.allExprsDigests);
+      final Set<String> allExprDigests = new HashSet<>(this.allExprDigests);
       final JoinRelType joinType = joinRel.getJoinType();
       switch (joinType) {
       case INNER:
       case LEFT:
-        infer(leftChildPredicates, allExprsDigests, inferredPredicates,
+        infer(leftChildPredicates, allExprDigests, inferredPredicates,
             includeEqualityInference,
             joinType == JoinRelType.LEFT ? rightFieldsBitSet
                 : allFieldsBitSet);
@@ -609,7 +604,7 @@ public class RelMdPredicates
       switch (joinType) {
       case INNER:
       case RIGHT:
-        infer(rightChildPredicates, allExprsDigests, inferredPredicates,
+        infer(rightChildPredicates, allExprDigests, inferredPredicates,
             includeEqualityInference,
             joinType == JoinRelType.RIGHT ? leftFieldsBitSet
                 : allFieldsBitSet);
@@ -678,7 +673,7 @@ public class RelMdPredicates
     }
 
     private void infer(RexNode predicates, Set<String> allExprsDigests,
-        List<RexNode> inferedPredicates, boolean includeEqualityInference,
+        List<RexNode> inferredPredicates, boolean includeEqualityInference,
         ImmutableBitSet inferringFields) {
       for (RexNode r : RelOptUtil.conjunctions(predicates)) {
         if (!includeEqualityInference
@@ -689,11 +684,15 @@ public class RelMdPredicates
           RexNode tr = r.accept(
               new RexPermuteInputsShuttle(m, joinRel.getInput(0),
                   joinRel.getInput(1)));
-          if (inferringFields.contains(RelOptUtil.InputFinder.bits(tr))
-              && !allExprsDigests.contains(tr.toString())
-              && !isAlwaysTrue(tr)) {
-            inferedPredicates.add(tr);
-            allExprsDigests.add(tr.toString());
+          // Filter predicates can be already simplified, so we should work 
with
+          // simplified RexNode versions as well. It also allows prevent of 
having
+          // some duplicates in in result pulledUpPredicates
+          RexNode simplifiedTarget =
+              simplifier.simplifyFilterPredicates(RelOptUtil.conjunctions(tr));
+          if (checkTarget(inferringFields, allExprsDigests, tr)
+              && checkTarget(inferringFields, allExprsDigests, 
simplifiedTarget)) {
+            inferredPredicates.add(simplifiedTarget);
+            allExprsDigests.add(simplifiedTarget.toString());
           }
         }
       }
@@ -711,6 +710,13 @@ public class RelMdPredicates
       };
     }
 
+    private boolean checkTarget(ImmutableBitSet inferringFields,
+        Set<String> allExprsDigests, RexNode tr) {
+      return inferringFields.contains(RelOptUtil.InputFinder.bits(tr))
+          && !allExprsDigests.contains(tr.toString())
+          && !isAlwaysTrue(tr);
+    }
+
     private void equivalent(int p1, int p2) {
       BitSet b = equivalence.get(p1);
       b.set(p2);

http://git-wip-us.apache.org/repos/asf/calcite/blob/499f0c6e/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 568ddbc..9be7a99 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -1357,6 +1357,25 @@ public class RexSimplify {
       return false;
     }
   }
+
+  /**
+   * Combines predicates AND, optimizes, and returns null if the result is
+   * always false.
+   *
+   * @param predicates Filter condition predicates
+   * @return simplified conjunction of predicates for the filter, null if 
always false
+   */
+  public RexNode simplifyFilterPredicates(Iterable<? extends RexNode> 
predicates) {
+    final RexNode simplifiedAnds = simplifyAnds(predicates);
+    if (simplifiedAnds.isAlwaysFalse()) {
+      return null;
+    }
+
+    // Remove cast of BOOLEAN NOT NULL to BOOLEAN or vice versa. Filter accepts
+    // nullable and not-nullable conditions, but a CAST might get in the way of
+    // other rewrites.
+    return removeNullabilityCast(simplifiedAnds);
+  }
 }
 
 // End RexSimplify.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/499f0c6e/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java 
b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index bdfcb59..680cded 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -933,19 +933,15 @@ public class RelBuilder {
    * and optimized in a similar way to the {@link #and} method.
    * If the result is TRUE no filter is created. */
   public RelBuilder filter(Iterable<? extends RexNode> predicates) {
-    final RexNode x = simplifierUnknownAsFalse.simplifyAnds(predicates);
-    if (x.isAlwaysFalse()) {
+    final RexNode simplifiedPredicates =
+        simplifierUnknownAsFalse.simplifyFilterPredicates(predicates);
+    if (simplifiedPredicates == null) {
       return empty();
     }
 
-    // Remove cast of BOOLEAN NOT NULL to BOOLEAN or vice versa. Filter accepts
-    // nullable and not-nullable conditions, but a CAST might get in the way of
-    // other rewrites.
-    final RexNode x2 = simplifierUnknownAsFalse.removeNullabilityCast(x);
-
-    if (!x2.isAlwaysTrue()) {
+    if (!simplifiedPredicates.isAlwaysTrue()) {
       final Frame frame = stack.pop();
-      final RelNode filter = filterFactory.createFilter(frame.rel, x2);
+      final RelNode filter = filterFactory.createFilter(frame.rel, 
simplifiedPredicates);
       stack.push(new Frame(filter, frame.fields));
     }
     return this;

http://git-wip-us.apache.org/repos/asf/calcite/blob/499f0c6e/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java 
b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index 1290191..1f166f2 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -2067,6 +2067,24 @@ public class RelBuilderTest {
         + "  LogicalTableScan(table=[[scott, EMP]])\n";
     assertThat(root, hasTree(expected));
   }
+
+  @Test public void testFilterCastNull() {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelDataTypeFactory typeFactory = builder.getTypeFactory();
+    final RelNode root =
+        builder.scan("EMP")
+            .filter(
+                builder.getRexBuilder().makeCast(
+                    typeFactory.createTypeWithNullability(
+                        typeFactory.createSqlType(SqlTypeName.BOOLEAN), true),
+                    builder.equals(builder.field("DEPTNO"),
+                        builder.literal(10))))
+            .build();
+    final String expected = ""
+        + "LogicalFilter(condition=[=($7, 10)])\n"
+        + "  LogicalTableScan(table=[[scott, EMP]])\n";
+    assertThat(root, hasTree(expected));
+  }
 }
 
 // End RelBuilderTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/499f0c6e/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java 
b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
index 580a196..9da50f2 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -1391,7 +1391,7 @@ public class RelMetadataTest extends SqlToRelTestBase {
   }
 
   /** Unit test for
-   * {@link 
org.apache.calcite.rel.metadata.RelMdPredicates#getPredicates(SemiJoin, 
RelMetadataQuery)}. */
+   * {@link 
org.apache.calcite.rel.metadata.RelMdPredicates#getPredicates(Join, 
RelMetadataQuery)}. */
   @Test public void testPredicates() {
     final Project rel = (Project) convertSql("select * from emp, dept");
     final Join join = (Join) rel.getInput();
@@ -1529,7 +1529,9 @@ public class RelMetadataTest extends SqlToRelTestBase {
   /** Test case for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-1960";>[CALCITE-1960]
    * RelMdPredicates.getPredicates is slow if there are many equivalent
-   * columns</a>. Since this is a performance problem, the test result does not
+   * columns</a>. There are much less duplicates after
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2205";>[CALCITE-2205]</a>.
+   * Since this is a performance problem, the test result does not
    * change, but takes over 15 minutes before the fix and 6 seconds after. */
   @Test(timeout = 20_000) public void testPullUpPredicatesForExprsItr() {
     // If we're running Windows, we are probably in a VM and the test may
@@ -1557,7 +1559,7 @@ public class RelMetadataTest extends SqlToRelTestBase {
       final RelNode rel = convertSql(sql);
       final RelMetadataQuery mq = RelMetadataQuery.instance();
       RelOptPredicateList inputSet = mq.getPulledUpPredicates(rel.getInput(0));
-      assertThat(inputSet.pulledUpPredicates.size(), is(131089));
+      assertThat(inputSet.pulledUpPredicates.size(), is(18));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/499f0c6e/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java 
b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index e24aaad..24adbb6 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -3010,6 +3010,9 @@ public class RelOptRulesTest extends RelOptTestBase {
     sql(sql).withPre(preProgram).with(program).check();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2200";>[CALCITE-2200]
+   * Infinite loop for JoinPushTransitivePredicatesRule</a>. */
   @Test public void testJoinPushTransitivePredicatesRule() {
     HepProgram preProgram = new HepProgramBuilder()
         .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
@@ -3027,6 +3030,29 @@ public class RelOptRulesTest extends RelOptTestBase {
   }
 
   /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2205";>[CALCITE-2205]
+   * One more infinite loop for JoinPushTransitivePredicatesRule</a>. */
+  @Test public void testJoinPushTransitivePredicatesRule2() {
+    HepProgram hepProgram = new HepProgramBuilder()
+        .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
+        .addRuleInstance(FilterJoinRule.JOIN)
+        .addRuleInstance(JoinPushTransitivePredicatesRule.INSTANCE)
+        .build();
+    HepPlanner hepPlanner = new HepPlanner(hepProgram);
+
+    final String sql = "select n1.SAL\n"
+        + "from EMPNULLABLES_20 n1\n"
+        + "where n1.SAL IN (\n"
+        + "  select n2.SAL\n"
+        + "  from EMPNULLABLES_20 n2\n"
+        + "  where n1.SAL = n2.SAL or n1.SAL = 4)";
+    sql(sql)
+        .withDecorrelation(true)
+        .with(hepPlanner)
+        .check();
+  }
+
+  /** Test case for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2195";>[CALCITE-2195]
    * AggregateJoinTransposeRule fails to aggregate over unique column</a>. */
   @Test public void testPushAggregateThroughJoin6() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/499f0c6e/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 94eb792..ea1f449 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
@@ -76,6 +76,7 @@ import java.util.TreeMap;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
@@ -1300,9 +1301,27 @@ public class RexProgramTest {
         "false");
 
     // simplify equals boolean
-    checkSimplifyFilter(and(eq(eq(aRef, literal1), trueLiteral), eq(bRef, 
literal1)),
+    final ImmutableList<RexNode> args =
+        ImmutableList.of(eq(eq(aRef, literal1), trueLiteral),
+            eq(bRef, literal1));
+    checkSimplifyFilter(and(args),
         "AND(=(?0.a, 1), =(?0.b, 1))");
 
+    // as previous, using simplifyFilterPredicates
+    assertThat(simplify.withUnknownAsFalse(true)
+            .simplifyFilterPredicates(args)
+            .toString(),
+        equalTo("AND(=(?0.a, 1), =(?0.b, 1))"));
+
+    // "a = 1 and a = 10" is always false
+    final ImmutableList<RexNode> args2 =
+        ImmutableList.of(eq(aRef, literal1), eq(aRef, literal10));
+    checkSimplifyFilter(and(args2), "false");
+
+    assertThat(simplify.withUnknownAsFalse(true)
+            .simplifyFilterPredicates(args2),
+        nullValue());
+
     // equality on constants, can remove the equality on the variables
     checkSimplifyFilter(and(eq(aRef, literal1), eq(bRef, literal1), eq(aRef, 
bRef)),
         "AND(=(?0.a, 1), =(?0.b, 1))");

http://git-wip-us.apache.org/repos/asf/calcite/blob/499f0c6e/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
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 89f7dc7..290799d 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -2626,20 +2626,58 @@ LogicalProject(DEPTNO=[$7])
             LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
+    </TestCase>
+    <TestCase name="testJoinPushTransitivePredicatesRule2">
+        <Resource name="sql">
+            <![CDATA[select n1.SAL
+from EMPNULLABLES_20 n1
+where n1.SAL IN (
+  select n2.SAL
+  from EMPNULLABLES_20 n2
+  where n1.SAL = n2.SAL or n1.SAL = 4)]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(SAL=[$5])
+  LogicalJoin(condition=[AND(=($5, $9), =($5, $8))], joinType=[inner])
+    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], 
SAL=[$5], COMM=[$6], SLACKER=[$8])
+      LogicalFilter(condition=[AND(=($7, 20), >($5, 1000))])
+        LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]])
+    LogicalAggregate(group=[{0, 1}])
+      LogicalProject(SAL=[$0], SAL0=[$1])
+        LogicalProject(SAL=[$5], SAL0=[$8])
+          LogicalJoin(condition=[OR(=($8, $5), =($8, 4))], joinType=[inner])
+            LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], 
HIREDATE=[$4], SAL=[$5], COMM=[$6], SLACKER=[$8])
+              LogicalFilter(condition=[AND(=($7, 20), >($5, 1000))])
+                LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]])
+            LogicalAggregate(group=[{0}])
+              LogicalProject(SAL=[$5])
+                LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], 
HIREDATE=[$4], SAL=[$5], COMM=[$6], SLACKER=[$8])
+                  LogicalFilter(condition=[AND(=($7, 20), >($5, 1000))])
+                    LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]])
+]]>
+        </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(DEPTNO=[$7])
-  LogicalJoin(condition=[AND(=($7, $10), =($7, $9))], joinType=[inner])
-    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
-    LogicalFilter(condition=[OR(=($1, $0), =($1, 4))])
+LogicalProject(SAL=[$5])
+  LogicalJoin(condition=[AND(=($5, $9), =($5, $8))], joinType=[inner])
+    LogicalFilter(condition=[OR(IS NOT NULL($5), =($5, 4))])
+      LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], 
HIREDATE=[$4], SAL=[$5], COMM=[$6], SLACKER=[$8])
+        LogicalFilter(condition=[AND(=($7, 20), >($5, 1000))])
+          LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]])
+    LogicalFilter(condition=[AND(OR(IS NOT NULL($0), =($0, 4)), OR(=($0, $1), 
=($0, 4)), OR(IS NOT NULL($1), =($1, 4)))])
       LogicalAggregate(group=[{0, 1}])
-        LogicalProject(DEPTNO=[$0], DEPTNO0=[$1])
-          LogicalProject(DEPTNO=[$7], DEPTNO0=[$9])
-            LogicalJoin(condition=[OR(=($7, $9), =($7, 4))], joinType=[inner])
-              LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+        LogicalProject(SAL=[$0], SAL0=[$1])
+          LogicalProject(SAL=[$5], SAL0=[$8])
+            LogicalJoin(condition=[OR(=($8, $5), =($8, 4))], joinType=[inner])
+              LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], 
HIREDATE=[$4], SAL=[$5], COMM=[$6], SLACKER=[$8])
+                LogicalFilter(condition=[AND(=($7, 20), >($5, 1000))])
+                  LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]])
               LogicalAggregate(group=[{0}])
-                LogicalProject(DEPTNO=[$7])
-                  LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+                LogicalProject(SAL=[$5])
+                  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], 
HIREDATE=[$4], SAL=[$5], COMM=[$6], SLACKER=[$8])
+                    LogicalFilter(condition=[AND(=($7, 20), >($5, 1000))])
+                      LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]])
 ]]>
         </Resource>
     </TestCase>

Reply via email to