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/01/29 05:42:55 UTC

[7/7] incubator-calcite git commit: [CALCITE-575] Variant of ProjectRemoveRule that considers a project trivial only if its field names are identical (John Pullokkaran)

[CALCITE-575] Variant of ProjectRemoveRule that considers a project trivial only if its field names are identical (John Pullokkaran)


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

Branch: refs/heads/master
Commit: 341bdd8e2e1a48165652bab1d6341ef4d09e2523
Parents: f036de8
Author: John Pullokkaran <jp...@hortonworks.com>
Authored: Wed Jan 28 12:45:58 2015 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Jan 28 14:46:43 2015 -0800

----------------------------------------------------------------------
 .../calcite/rel/rules/ProjectRemoveRule.java    | 68 ++++++++++++++++++--
 .../java/org/apache/calcite/rex/RexUtil.java    | 31 +++++++++
 .../apache/calcite/sql2rel/RelFieldTrimmer.java | 46 ++++++++++++-
 3 files changed, 136 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/341bdd8e/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
index 5e39853..2bc5d59 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectRemoveRule.java
@@ -41,29 +41,52 @@ import java.util.List;
  */
 public class ProjectRemoveRule extends RelOptRule {
   //~ Static fields/initializers ---------------------------------------------
+  private final boolean useNamesInIdentityProjCalc;
 
   private static final Predicate<Project> PREDICATE =
       new Predicate<Project>() {
         public boolean apply(Project input) {
-          return isTrivial(input);
+          return isTrivial(input, false);
         }
       };
 
-  public static final ProjectRemoveRule INSTANCE = new ProjectRemoveRule();
+  private static final Predicate<Project> NAME_CALC_PREDICATE =
+      new Predicate<Project>() {
+        public boolean apply(Project input) {
+          return isTrivial(input, true);
+        }
+      };
+
+  public static final ProjectRemoveRule INSTANCE = new ProjectRemoveRule(false);
+
+  /** @deprecated Remove before
+   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+  public static final ProjectRemoveRule NAME_CALC_INSTANCE =
+      new ProjectRemoveRule(true);
 
   //~ Constructors -----------------------------------------------------------
 
-  private ProjectRemoveRule() {
+  /**
+   * Creates a ProjectRemoveRule.
+   *
+   * @param useNamesInIdentityProjCalc If true consider names while determining
+   *                                   if two projects are same
+   */
+  private ProjectRemoveRule(boolean useNamesInIdentityProjCalc) {
     // Create a specialized operand to detect non-matches early. This keeps
     // the rule queue short.
-    super(operand(Project.class, null, PREDICATE, any()));
+    super(
+        operand(Project.class, null,
+            useNamesInIdentityProjCalc ? NAME_CALC_PREDICATE : PREDICATE,
+            any()));
+    this.useNamesInIdentityProjCalc = useNamesInIdentityProjCalc;
   }
 
   //~ Methods ----------------------------------------------------------------
 
   public void onMatch(RelOptRuleCall call) {
     Project project = call.rel(0);
-    assert isTrivial(project);
+    assert isTrivial(project, useNamesInIdentityProjCalc);
     RelNode stripped = project.getInput();
     if (stripped instanceof Project) {
       // Rename columns of child projection if desired field names are given.
@@ -84,10 +107,35 @@ public class ProjectRemoveRule extends RelOptRule {
     return isTrivial(project) ? project.getInput() : project;
   }
 
+  /**
+   * Returns the child of a project if the project is trivial
+   * otherwise the project itself. If useNamesInIdentityProjCalc is true
+   * then trivial comparison uses both names and types.
+   *
+   * @deprecated Remove before
+   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+  public static RelNode strip(Project project,
+      boolean useNamesInIdentityProjCalc) {
+    return isTrivial(project, useNamesInIdentityProjCalc)
+        ? project.getInput() : project;
+  }
+
   public static boolean isTrivial(Project project) {
+    return isTrivial(project, false);
+  }
+
+  /** @deprecated Remove before
+   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+  public static boolean isTrivial(Project project,
+    boolean useNamesInIdentityProjCalc) {
     RelNode child = project.getInput();
     final RelDataType childRowType = child.getRowType();
-    return isIdentity(project.getProjects(), childRowType);
+    if (useNamesInIdentityProjCalc) {
+      return isIdentity(project.getProjects(), project.getRowType(),
+          childRowType);
+    } else {
+      return isIdentity(project.getProjects(), childRowType);
+    }
   }
 
   public static boolean isIdentity(List<? extends RexNode> exps,
@@ -95,6 +143,14 @@ public class ProjectRemoveRule extends RelOptRule {
     return childRowType.getFieldCount() == exps.size()
         && RexUtil.containIdentity(exps, childRowType, false);
   }
+
+  /** @deprecated Remove before
+   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+  public static boolean isIdentity(List<? extends RexNode> exps,
+      RelDataType rowType, RelDataType childRowType) {
+    return childRowType.getFieldCount() == exps.size()
+        && RexUtil.containIdentity(exps, rowType, childRowType);
+  }
 }
 
 // End ProjectRemoveRule.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/341bdd8e/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index e70205c..f7712e1 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -614,6 +614,37 @@ public class RexUtil {
   }
 
   /**
+   * Returns whether the leading edge of a given array of expressions is
+   * wholly {@link RexInputRef} objects with types and names corresponding
+   * to the underlying row type.
+   *
+   * @deprecated Remove before
+   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+  public static boolean containIdentity(List<? extends RexNode> exps,
+      RelDataType rowType, RelDataType childRowType) {
+    List<RelDataTypeField> fields = rowType.getFieldList();
+    List<RelDataTypeField> childFields = childRowType.getFieldList();
+    int fieldCount = childFields.size();
+    if (exps.size() != fieldCount) {
+      return false;
+    }
+    for (int i = 0; i < exps.size(); i++) {
+      RexNode exp = exps.get(i);
+      if (!(exp instanceof RexInputRef)) {
+        return false;
+      }
+      RexInputRef var = (RexInputRef) exp;
+      if (var.getIndex() != i) {
+        return false;
+      }
+      if (!fields.get(i).getName().equals(childFields.get(i).getName())) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
    * Converts a collection of expressions into an AND.
    * If there are zero expressions, returns TRUE.
    * If there is one expression, returns just that expression.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/341bdd8e/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
index a41606e..e108c78 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -106,6 +106,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
   private final RelFactories.SortFactory sortFactory;
   private final RelFactories.AggregateFactory aggregateFactory;
   private final RelFactories.SetOpFactory setOpFactory;
+  private final boolean useNamesInIdentityProjCalc;
 
   //~ Constructors -----------------------------------------------------------
 
@@ -138,6 +139,36 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       RelFactories.SortFactory sortFactory,
       RelFactories.AggregateFactory aggregateFactory,
       RelFactories.SetOpFactory setOpFactory) {
+    this(validator, projectFactory, filterFactory, joinFactory,
+         semiJoinFactory, sortFactory, aggregateFactory, setOpFactory,
+         false);
+  }
+
+  /**
+   * Creates a RelFieldTrimmer.
+   *
+   * @param validator Validator
+   * @param projectFactory Project factory
+   * @param filterFactory Filter factory
+   * @param joinFactory Join factory
+   * @param semiJoinFactory SemiJoin factory
+   * @param sortFactory Sort factory
+   * @param aggregateFactory Aggregate factory
+   * @param setOpFactory SetOp factory
+   * @param useNamesInIdentityProjCalc
+   *            Include field names in identity project determination
+   *
+   * @deprecated Remove before
+   * {@link org.apache.calcite.util.Bug#upgrade Calcite-1.1}. */
+  public RelFieldTrimmer(SqlValidator validator,
+      RelFactories.ProjectFactory projectFactory,
+      RelFactories.FilterFactory filterFactory,
+      RelFactories.JoinFactory joinFactory,
+      RelFactories.SemiJoinFactory semiJoinFactory,
+      RelFactories.SortFactory sortFactory,
+      RelFactories.AggregateFactory aggregateFactory,
+      RelFactories.SetOpFactory setOpFactory,
+      boolean useNamesInIdentityProjCalc) {
     Util.discard(validator); // may be useful one day
     this.trimFieldsDispatcher =
         ReflectUtil.createMethodDispatcher(
@@ -154,6 +185,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     this.sortFactory = Preconditions.checkNotNull(sortFactory);
     this.aggregateFactory = Preconditions.checkNotNull(aggregateFactory);
     this.setOpFactory = Preconditions.checkNotNull(setOpFactory);
+    this.useNamesInIdentityProjCalc = useNamesInIdentityProjCalc;
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -378,9 +410,8 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
             mapping);
 
     final RelNode newProject;
-    if (ProjectRemoveRule.isIdentity(
-        newProjectExprList,
-        newInput.getRowType())) {
+    if (isIdentityProject(newProjectExprList, newRowType,
+                                   newInput.getRowType())) {
       // The new project would be the identity. It is equivalent to return
       // its child.
       newProject = newInput;
@@ -392,6 +423,15 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
     return new TrimResult(newProject, mapping);
   }
 
+  private boolean isIdentityProject(List<? extends RexNode> exps,
+    RelDataType rowType, RelDataType childRowType) {
+    if (this.useNamesInIdentityProjCalc) {
+      return ProjectRemoveRule.isIdentity(exps, rowType, childRowType);
+    } else {
+      return ProjectRemoveRule.isIdentity(exps, childRowType);
+    }
+  }
+
   /** Creates a project with a dummy column, to protect the parts of the system
    * that cannot handle a relational expression with no columns.
    *