You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2014/10/19 00:32:32 UTC

[4/4] git commit: [OPTIQ-438] Push predicates through SemiJoinRel

[OPTIQ-438] Push predicates through SemiJoinRel


Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/59191a7a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/59191a7a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/59191a7a

Branch: refs/heads/master
Commit: 59191a7add9f3141138d7c2cb5298939a0fa99e0
Parents: ee903d5
Author: John Pullokkaran <jp...@hortonworks.com>
Authored: Fri Oct 17 11:45:33 2014 -0400
Committer: Julian Hyde <ju...@gmail.com>
Committed: Fri Oct 17 11:45:33 2014 -0400

----------------------------------------------------------------------
 .../rel/rules/PushFilterPastJoinRule.java       | 37 ++++++++++++++++++--
 .../java/org/eigenbase/relopt/RelOptUtil.java   |  4 ++-
 .../org/eigenbase/test/RelOptRulesTest.java     | 22 ++++++++++++
 .../org/eigenbase/test/RelOptRulesTest.xml      | 29 +++++++++++++++
 4 files changed, 88 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/59191a7a/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java b/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java
index 969e93c..90369ad 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/PushFilterPastJoinRule.java
@@ -24,6 +24,7 @@ import org.eigenbase.rex.*;
 import org.eigenbase.util.Holder;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
 
 /**
  * PushFilterPastJoinRule implements the rule for pushing filters above and
@@ -69,11 +70,9 @@ public abstract class PushFilterPastJoinRule extends RelOptRule {
 
   protected void perform(RelOptRuleCall call, FilterRelBase filter,
       JoinRelBase join) {
-    if (join instanceof SemiJoinRel) {
-      return;
-    }
     final List<RexNode> joinFilters =
         RelOptUtil.conjunctions(join.getCondition());
+    final List<RexNode> origJoinFilters = ImmutableList.copyOf(joinFilters);
 
     // If there is only the joinRel,
     // make sure it does not match a cartesian product joinRel
@@ -117,6 +116,19 @@ public abstract class PushFilterPastJoinRule extends RelOptRule {
       filterPushed = true;
     }
 
+    // Move join filters up if needed
+    validateJoinFilters(aboveFilters, joinFilters, join);
+
+    // If no filter got pushed after validate reset filterPushed flag
+    if (leftFilters.isEmpty()
+        && rightFilters.isEmpty()
+        && joinFilters.size() == origJoinFilters.size()) {
+      if (Sets.newHashSet(joinFilters)
+          .equals(Sets.newHashSet(origJoinFilters))) {
+        filterPushed = false;
+      }
+    }
+
     // Try to push down filters in ON clause. A ON clause filter can only be
     // pushed down if it does not affect the non-matching set, i.e. it is
     // not on the side which is preserved.
@@ -204,6 +216,25 @@ public abstract class PushFilterPastJoinRule extends RelOptRule {
   }
 
   /**
+   * Validates that target execution framework can satisfy join filters.
+   *
+   * <p>If the join filter cannot be satifisfied (for example, if it is
+   * {@code l.c1 > r.c2} and the join only supports equi-join), removes the
+   * filter from {@code joinFilters} and adds it to {@code aboveFilters}.
+   *
+   * <p>The default implementation does nothing; i.e. the join can handle all
+   * conditions.
+   *
+   * @param aboveFilters Filter above Join
+   * @param joinFilters Filters in join condition
+   * @param join Join
+   */
+  protected void validateJoinFilters(List<RexNode> aboveFilters,
+      List<RexNode> joinFilters, JoinRelBase join) {
+    return;
+  }
+
+  /**
    * If the filter list passed in is non-empty, creates a FilterRel on top of
    * the existing RelNode; otherwise, just returns the RelNode
    *

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/59191a7a/core/src/main/java/org/eigenbase/relopt/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/relopt/RelOptUtil.java b/core/src/main/java/org/eigenbase/relopt/RelOptUtil.java
index bd9c306..d5ceaa0 100644
--- a/core/src/main/java/org/eigenbase/relopt/RelOptUtil.java
+++ b/core/src/main/java/org/eigenbase/relopt/RelOptUtil.java
@@ -1960,7 +1960,9 @@ public abstract class RelOptUtil {
     final List<RelDataTypeField> rightFields =
         joinRel.getInputs().get(1).getRowType().getFieldList();
     final int nFieldsRight = rightFields.size();
-    assert nTotalFields == nSysFields + nFieldsLeft + nFieldsRight;
+    assert nTotalFields == (joinRel instanceof SemiJoinRel
+        ? nSysFields + nFieldsLeft
+        : nSysFields + nFieldsLeft + nFieldsRight);
 
     // set the reference bitmaps for the left and right children
     BitSet leftBitmap =

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/59191a7a/core/src/test/java/org/eigenbase/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/eigenbase/test/RelOptRulesTest.java b/core/src/test/java/org/eigenbase/test/RelOptRulesTest.java
index 5c5513e..8668907 100644
--- a/core/src/test/java/org/eigenbase/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/eigenbase/test/RelOptRulesTest.java
@@ -192,6 +192,28 @@ public class RelOptRulesTest extends RelOptTestBase {
             + "  and emp.sal > 100)");
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/OPTIQ-438">[OPTIQ-438],
+   * Push predicates through SemiJoinRel</a>. */
+  @Test public void testPushFilterThroughSemiJoin() {
+    final HepProgram preProgram =
+        HepProgram.builder()
+            .addRuleInstance(SemiJoinRule.INSTANCE)
+            .build();
+
+    final HepProgram program =
+        HepProgram.builder()
+            .addRuleInstance(PushFilterPastProjectRule.INSTANCE)
+            .addRuleInstance(PushFilterPastJoinRule.FILTER_ON_JOIN)
+            .addRuleInstance(PushFilterPastJoinRule.JOIN)
+            .build();
+    checkPlanning(tester.withDecorrelation(true).withTrim(false), preProgram,
+        new HepPlanner(program),
+        "select * from (select * from dept where dept.deptno in (\n"
+            + "  select emp.deptno from emp\n"
+            + "  ))R where R.deptno <=10 ");
+  }
+
   protected void semiJoinTrim() {
     final DiffRepository diffRepos = getDiffRepos();
     String sql = diffRepos.expand(null, "${sql}");

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/59191a7a/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml b/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
index a4d2d31..4ef190a 100644
--- a/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
@@ -108,6 +108,35 @@ ProjectRel(EXPR$0=[1])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testPushFilterThroughSemiJoin">
+        <Resource name="sql">
+            <![CDATA[select * from (select * from dept where dept.deptno in (select emp.deptno from emp))R where R.deptno <=10 ]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+ProjectRel(DEPTNO=[$0], NAME=[$1])
+  FilterRel(condition=[<=($0, 10)])
+    ProjectRel(DEPTNO=[$0], NAME=[$1])
+      SemiJoinRel(condition=[=($2, $3)], joinType=[inner])
+        ProjectRel($f0=[$0], $f1=[$1], $f2=[$0])
+          TableAccessRel(table=[[CATALOG, SALES, DEPT]])
+        ProjectRel(DEPTNO=[$7])
+          TableAccessRel(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+ProjectRel(DEPTNO=[$0], NAME=[$1])
+  ProjectRel(DEPTNO=[$0], NAME=[$1])
+    SemiJoinRel(condition=[=($2, $3)], joinType=[inner])
+      FilterRel(condition=[<=($0, 10)])
+        ProjectRel($f0=[$0], $f1=[$1], $f2=[$0])
+          TableAccessRel(table=[[CATALOG, SALES, DEPT]])
+      ProjectRel(DEPTNO=[$7])
+        TableAccessRel(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testPushFilterPastAgg">
         <Resource name="sql">
             <![CDATA[select dname, c from (select name dname, count(*) as c from dept group by name) t where dname = 'Charlie']]>