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