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']]>