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 2015/07/21 21:53:12 UTC

[2/2] incubator-calcite git commit: [CALCITE-808] Optimize ProjectMergeRule

[CALCITE-808] Optimize ProjectMergeRule


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

Branch: refs/heads/master
Commit: b550ff887b41c51348f14c0dc10481fe18aadf0f
Parents: c9fe32b
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jul 21 11:12:46 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jul 21 12:29:15 2015 -0700

----------------------------------------------------------------------
 .../org/apache/calcite/plan/RelOptUtil.java     | 34 ++++++---
 .../calcite/rel/rules/ProjectMergeRule.java     | 73 +++++---------------
 .../org/apache/calcite/test/RelOptRulesTest.xml | 28 ++++----
 3 files changed, 57 insertions(+), 78 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b550ff88/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 6892dfd..d2686a0 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -2379,14 +2379,32 @@ public abstract class RelOptUtil {
    * @param project Project underneath the expression
    * @return converted expression
    */
-  public static RexNode pushPastProject(RexNode node,
-      final Project project) {
-    return node.accept(
-        new RexShuttle() {
-          @Override public RexNode visitInputRef(RexInputRef ref) {
-            return project.getProjects().get(ref.getIndex());
-          }
-        });
+  public static RexNode pushPastProject(RexNode node, Project project) {
+    return node.accept(pushShuttle(project));
+  }
+
+  /**
+   * Converts a list of expressions that are based on the output fields of a
+   * {@link Project} to equivalent expressions on the Project's
+   * input fields.
+   *
+   * @param nodes The expressions to be converted
+   * @param project Project underneath the expression
+   * @return converted expressions
+   */
+  public static List<RexNode> pushPastProject(List<? extends RexNode> nodes,
+      Project project) {
+    final List<RexNode> list = new ArrayList<>();
+    pushShuttle(project).visitList(nodes, list);
+    return list;
+  }
+
+  private static RexShuttle pushShuttle(final Project project) {
+    return new RexShuttle() {
+      @Override public RexNode visitInputRef(RexInputRef ref) {
+        return project.getProjects().get(ref.getIndex());
+      }
+    };
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b550ff88/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
index cef654e..89ed15f 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectMergeRule.java
@@ -23,14 +23,9 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.core.RelFactories.ProjectFactory;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexProgram;
-import org.apache.calcite.rex.RexProgramBuilder;
 import org.apache.calcite.util.Permutation;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -39,7 +34,8 @@ import java.util.List;
  * provided the projects aren't projecting identical sets of input references.
  */
 public class ProjectMergeRule extends RelOptRule {
-  public static final ProjectMergeRule INSTANCE = new ProjectMergeRule();
+  public static final ProjectMergeRule INSTANCE =
+      new ProjectMergeRule(true, RelFactories.DEFAULT_PROJECT_FACTORY);
 
   //~ Instance fields --------------------------------------------------------
 
@@ -51,13 +47,6 @@ public class ProjectMergeRule extends RelOptRule {
   //~ Constructors -----------------------------------------------------------
 
   /**
-   * Creates a ProjectMergeRule.
-   */
-  private ProjectMergeRule() {
-    this(false, RelFactories.DEFAULT_PROJECT_FACTORY);
-  }
-
-  /**
    * Creates a ProjectMergeRule, specifying whether to always merge projects.
    *
    * @param force Whether to always merge projects
@@ -66,7 +55,7 @@ public class ProjectMergeRule extends RelOptRule {
     super(
         operand(Project.class,
             operand(Project.class, any())),
-             "ProjectMergeRule" + (force ? ":force_mode" : ""));
+        "ProjectMergeRule" + (force ? ":force_mode" : ""));
     this.force = force;
     this.projectFactory = projectFactory;
   }
@@ -74,9 +63,8 @@ public class ProjectMergeRule extends RelOptRule {
   //~ Methods ----------------------------------------------------------------
 
   public void onMatch(RelOptRuleCall call) {
-    Project topProject = call.rel(0);
-    Project bottomProject = call.rel(1);
-    RexBuilder rexBuilder = topProject.getCluster().getRexBuilder();
+    final Project topProject = call.rel(0);
+    final Project bottomProject = call.rel(1);
 
     // If one or both projects are permutations, short-circuit the complex logic
     // of building a RexProgram.
@@ -101,48 +89,25 @@ public class ProjectMergeRule extends RelOptRule {
       }
     }
 
-    // if we're not in force mode and the two projects reference identical
-    // inputs, then return and either let FennelRenameRule or
-    // ProjectRemoveRule replace the projects
+    // If we're not in force mode and the two projects reference identical
+    // inputs, then return and let ProjectRemoveRule replace the projects.
     if (!force) {
-      if (RelOptUtil.checkProjAndChildInputs(topProject, false)) {
+      if (ProjectRemoveRule.isIdentity(topProject.getProjects(),
+          topProject.getInput().getRowType())) {
         return;
       }
     }
 
-    // create a RexProgram for the bottom project
-    RexProgram bottomProgram =
-        RexProgram.create(
-            bottomProject.getInput().getRowType(),
-            bottomProject.getProjects(),
-            null,
-            bottomProject.getRowType(),
-            rexBuilder);
-
-    // create a RexProgram for the topmost project
-    final List<RexNode> projects = topProject.getProjects();
-    RexProgram topProgram =
-        RexProgram.create(
-            bottomProject.getRowType(),
-            projects,
-            null,
-            topProject.getRowType(),
-            rexBuilder);
-
-    // combine the two RexPrograms
-    RexProgram mergedProgram =
-        RexProgramBuilder.mergePrograms(
-            topProgram,
-            bottomProgram,
-            rexBuilder);
-
-    // re-expand the topmost projection expressions, now that they
-    // reference the children of the bottom-most project
-    final int projectCount = projects.size();
-    final List<RexNode> newProjects = new ArrayList<>();
-    List<RexLocalRef> projectRefs = mergedProgram.getProjectList();
-    for (int i = 0; i < projectCount; i++) {
-      newProjects.add(mergedProgram.expandLocalRef(projectRefs.get(i)));
+    final List<RexNode> newProjects =
+        RelOptUtil.pushPastProject(topProject.getProjects(), bottomProject);
+    final RelNode input = bottomProject.getInput();
+    if (ProjectRemoveRule.isIdentity(newProjects, input.getRowType())) {
+      if (force
+          || input.getRowType().getFieldNames()
+              .equals(topProject.getRowType().getFieldNames())) {
+        call.transformTo(input);
+        return;
+      }
     }
 
     // replace the two projects with a combined projection

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b550ff88/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 eb9ed66..d01a8d1 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1636,10 +1636,9 @@ LogicalProject(DEPTNO=[$0], EXPR$1=[$2])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
-  LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
-    LogicalProject(DEPTNO=[$7], FOUR=[4], MGR=[$3])
-      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
+  LogicalProject(DEPTNO=[$7], FOUR=[4], MGR=[$3])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -1660,10 +1659,9 @@ LogicalProject(DEPTNO=[$0], EXPR$1=[$2])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
-  LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
-    LogicalProject(DEPTNO=[$7], FOUR=[4], ENAME=[$1])
-      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
+  LogicalProject(DEPTNO=[$7], FOUR=[4], ENAME=[$1])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -1708,10 +1706,9 @@ LogicalProject(DEPTNO=[$1], EXPR$1=[$2])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
-  LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
-    LogicalProject(DEPTNO=[$7], FOUR=[4], MGR=[$3])
-      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
+  LogicalProject(DEPTNO=[$7], FOUR=[4], MGR=[$3])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>
@@ -1732,10 +1729,9 @@ LogicalProject(DEPTNO=[$1], EXPR$1=[$2])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
-  LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
-    LogicalProject(DEPTNO=[$7], $f0=[+(42, 24)], MGR=[$3])
-      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+LogicalAggregate(group=[{0}], EXPR$1=[MAX($2)])
+  LogicalProject(DEPTNO=[$7], $f0=[+(42, 24)], MGR=[$3])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
     </TestCase>