You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by vl...@apache.org on 2019/01/08 16:05:43 UTC
[calcite] 01/01: [CALCITE-2437] FilterMultiJoinMerge should combine
filters from Filter relation and multijoin post-join filters
This is an automated email from the ASF dual-hosted git repository.
vladimirsitnikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git
commit d368fc570a5d0f836c049c6acd73f2dd9f467f79
Author: Laurent Goujon <la...@dremio.com>
AuthorDate: Fri Dec 21 09:54:55 2018 -0800
[CALCITE-2437] FilterMultiJoinMerge should combine filters from Filter relation and multijoin post-join filters
The FilterMultiJoinMergeRule class is intended to combine a filter on
top of a multi join into a single multijoin. But instead of combining
the post join filter with the filter's condition, it simply replaces
it.
Fixing the issue by composing a conjuction of the two filters and
adding it to the new multijoin.
fixes #977
---
.../rel/rules/FilterMultiJoinMergeRule.java | 15 +++++++++++++-
.../org/apache/calcite/test/RelOptRulesTest.java | 14 +++++++++++++
.../org/apache/calcite/test/RelOptRulesTest.xml | 24 ++++++++++++++++++++++
3 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterMultiJoinMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterMultiJoinMergeRule.java
index 73f24aa..ee96b90 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterMultiJoinMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterMultiJoinMergeRule.java
@@ -20,8 +20,14 @@ import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.tools.RelBuilderFactory;
+import java.util.Arrays;
+import java.util.List;
+
/**
* Planner rule that merges a
* {@link org.apache.calcite.rel.logical.LogicalFilter}
@@ -52,6 +58,13 @@ public class FilterMultiJoinMergeRule extends RelOptRule {
LogicalFilter filter = call.rel(0);
MultiJoin multiJoin = call.rel(1);
+ // Create a new post-join filter condition
+ // Conditions are nullable, so ImmutableList can't be used here
+ List<RexNode> filters = Arrays.asList(
+ filter.getCondition(),
+ multiJoin.getPostJoinFilter());
+
+ final RexBuilder rexBuilder = multiJoin.getCluster().getRexBuilder();
MultiJoin newMultiJoin =
new MultiJoin(
multiJoin.getCluster(),
@@ -63,7 +76,7 @@ public class FilterMultiJoinMergeRule extends RelOptRule {
multiJoin.getJoinTypes(),
multiJoin.getProjFields(),
multiJoin.getJoinFieldRefCountsMap(),
- filter.getCondition());
+ RexUtil.composeConjunction(rexBuilder, filters, true));
call.transformTo(newMultiJoin);
}
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 ae82438..83aeda3 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -65,6 +65,7 @@ import org.apache.calcite.rel.rules.DateRangeRules;
import org.apache.calcite.rel.rules.FilterAggregateTransposeRule;
import org.apache.calcite.rel.rules.FilterJoinRule;
import org.apache.calcite.rel.rules.FilterMergeRule;
+import org.apache.calcite.rel.rules.FilterMultiJoinMergeRule;
import org.apache.calcite.rel.rules.FilterProjectTransposeRule;
import org.apache.calcite.rel.rules.FilterRemoveIsNotDistinctFromRule;
import org.apache.calcite.rel.rules.FilterSetOpTransposeRule;
@@ -82,6 +83,7 @@ import org.apache.calcite.rel.rules.ProjectCorrelateTransposeRule;
import org.apache.calcite.rel.rules.ProjectFilterTransposeRule;
import org.apache.calcite.rel.rules.ProjectJoinTransposeRule;
import org.apache.calcite.rel.rules.ProjectMergeRule;
+import org.apache.calcite.rel.rules.ProjectMultiJoinMergeRule;
import org.apache.calcite.rel.rules.ProjectRemoveRule;
import org.apache.calcite.rel.rules.ProjectSetOpTransposeRule;
import org.apache.calcite.rel.rules.ProjectToCalcRule;
@@ -1691,6 +1693,18 @@ public class RelOptRulesTest extends RelOptTestBase {
+ "where e1.deptno = d.deptno and d.deptno = e2.deptno");
}
+ @Test public void testManyFiltersOnTopOfMultiJoinShouldCollapse() throws Exception {
+ HepProgram program = new HepProgramBuilder()
+ .addMatchOrder(HepMatchOrder.BOTTOM_UP)
+ .addRuleInstance(JoinToMultiJoinRule.INSTANCE)
+ .addRuleCollection(
+ Arrays.asList(FilterMultiJoinMergeRule.INSTANCE, ProjectMultiJoinMergeRule.INSTANCE))
+ .build();
+ checkPlanning(program,
+ "select * from (select * from emp e1 left outer join dept d on e1.deptno = d.deptno "
+ + "where d.deptno > 3) where ename LIKE 'bar'");
+ }
+
@Test public void testReduceConstants() throws Exception {
HepProgram program = new HepProgramBuilder()
.addRuleInstance(ReduceExpressionsRule.PROJECT_INSTANCE)
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 23bf02a..8f98593 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -4144,6 +4144,30 @@ LogicalProject(ENAME=[$1])
]]>
</Resource>
</TestCase>
+ <TestCase name="testManyFiltersOnTopOfMultiJoinShouldCollapse">
+ <Resource name="sql">
+ <![CDATA[select * from (select * from emp e1 left outer join dept d on e1.deptno = d.deptno where d.deptno > 3) where ename LIKE 'bar']]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
+ LogicalFilter(condition=[LIKE($1, 'bar')])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
+ LogicalFilter(condition=[>($9, 3)])
+ LogicalJoin(condition=[=($7, $9)], joinType=[left])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
+ MultiJoin(joinFilter=[true], isFullOuterJoin=[false], joinTypes=[[INNER, LEFT]], outerJoinConditions=[[NULL, =($7, $9)]], projFields=[[{0, 1, 2, 3, 4, 5, 6, 7, 8}, {0, 1}]], postJoinFilter=[AND(LIKE($1, 'bar'), >($9, 3))])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testRemoveSemiJoinWithFilter">
<Resource name="sql">
<![CDATA[select e.ename from emp e, dept d where e.deptno = d.deptno and e.ename = 'foo']]>