This is an automated email from the ASF dual-hosted git repository.

hyuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new 0115bd1  [CALCITE-3348] AssertionError while determining distribution 
of Calc (Wang Yanlin)
0115bd1 is described below

commit 0115bd102fdbab66a2a7447b96b9f7bf49f14308
Author: yanzhi <[email protected]>
AuthorDate: Sat Sep 14 19:42:03 2019 +0800

    [CALCITE-3348] AssertionError while determining distribution of Calc (Wang 
Yanlin)
---
 .../calcite/rel/metadata/RelMdDistribution.java    | 11 +++++--
 .../java/org/apache/calcite/rex/RexProgram.java    | 28 +++++++++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.java   | 35 ++++++++++++++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 21 ++++++++++++-
 4 files changed, 92 insertions(+), 3 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java 
b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java
index 91b9185..6aac9ab 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java
@@ -141,10 +141,17 @@ public class RelMdDistribution
    * {@link org.apache.calcite.rel.core.Calc}'s distribution. */
   public static RelDistribution calc(RelMetadataQuery mq, RelNode input,
       RexProgram program) {
-    throw new AssertionError(); // TODO:
+    assert program.getCondition() != null || 
!program.getProjectList().isEmpty();
+    final RelDistribution inputDistribution = mq.distribution(input);
+    if (!program.getProjectList().isEmpty()) {
+      final Mappings.TargetMapping mapping = program.getPartialMapping(
+          input.getRowType().getFieldCount());
+      return inputDistribution.apply(mapping);
+    }
+    return inputDistribution;
   }
 
-  /** Helper method to determine a {@link Project}'s collation. */
+  /** Helper method to determine a {@link Project}'s distribution. */
   public static RelDistribution project(RelMetadataQuery mq, RelNode input,
       List<? extends RexNode> projects) {
     final RelDistribution inputDistribution = mq.distribution(input);
diff --git a/core/src/main/java/org/apache/calcite/rex/RexProgram.java 
b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
index 7aafac0..13e4d7f 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexProgram.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.rex;
 
+import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelCollation;
@@ -34,6 +35,8 @@ import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Permutation;
+import org.apache.calcite.util.mapping.MappingType;
+import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Ordering;
@@ -821,6 +824,31 @@ public class RexProgram {
         : null);
   }
 
+  /**
+   * Returns a partial mapping of a set of project expressions.
+   *
+   * <p>The mapping is an inverse function.
+   * Every target has a source field, but
+   * a source might have 0, 1 or more targets.
+   * Project expressions that do not consist of
+   * a mapping are ignored.
+   *
+   * @param inputFieldCount Number of input fields
+   * @return Mapping of a set of project expressions, never null
+   */
+  public Mappings.TargetMapping getPartialMapping(int inputFieldCount) {
+    Mappings.TargetMapping mapping =
+        Mappings.create(MappingType.INVERSE_FUNCTION,
+            inputFieldCount, projects.size());
+    for (Ord<RexLocalRef> exp : Ord.zip(projects)) {
+      RexNode rexNode = expandLocalRef(exp.e);
+      if (rexNode instanceof RexInputRef) {
+        mapping.set(((RexInputRef) rexNode).getIndex(), exp.i);
+      }
+    }
+    return mapping;
+  }
+
   //~ Inner Classes ----------------------------------------------------------
 
   /**
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 ed063f7..4720fca 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -38,6 +38,7 @@ import org.apache.calcite.prepare.Prepare;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelDistributionTraitDef;
 import org.apache.calcite.rel.RelDistributions;
 import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.RelNode;
@@ -6314,6 +6315,40 @@ public class RelOptRulesTest extends RelOptTestBase {
         .build();
     checkPlanning(program, "select ename from emp where sal > cast (100.0 as 
decimal(4, 1))");
   }
+
+  @Test public void testEnumerableCalcRule() {
+    final String sql = "select FNAME, LNAME from SALES.CUSTOMER where 
CONTACTNO > 10";
+    VolcanoPlanner planner = new VolcanoPlanner(null, null);
+    planner.addRelTraitDef(ConventionTraitDef.INSTANCE);
+    planner.addRelTraitDef(RelDistributionTraitDef.INSTANCE);
+
+    Tester dynamicTester = createDynamicTester().withDecorrelation(true)
+        .withClusterFactory(
+            relOptCluster -> RelOptCluster.create(planner, 
relOptCluster.getRexBuilder()));
+
+    RelRoot root = dynamicTester.convertSqlToRel(sql);
+
+    String planBefore = NL + RelOptUtil.toString(root.rel);
+    getDiffRepos().assertEquals("planBefore", "${planBefore}", planBefore);
+
+    RuleSet ruleSet =
+        RuleSets.ofList(
+            FilterToCalcRule.INSTANCE,
+            EnumerableRules.ENUMERABLE_PROJECT_RULE,
+            EnumerableRules.ENUMERABLE_TABLE_SCAN_RULE,
+            EnumerableRules.ENUMERABLE_CALC_RULE);
+    Program program = Programs.of(ruleSet);
+
+    RelTraitSet toTraits =
+        root.rel.getCluster().traitSet()
+            .replace(0, EnumerableConvention.INSTANCE);
+
+    RelNode relAfter = program.run(planner, root.rel, toTraits,
+        Collections.emptyList(), Collections.emptyList());
+
+    String planAfter = NL + RelOptUtil.toString(relAfter);
+    getDiffRepos().assertEquals("planAfter", "${planAfter}", planAfter);
+  }
 }
 
 // End RelOptRulesTest.java
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 fd445c5..4762ecb 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -11647,7 +11647,7 @@ LogicalSort(sort0=[$0], dir0=[ASC])
     </TestCase>
     <TestCase name="testReduceDecimal">
         <Resource name="sql">
-            <![CDATA[select ename from emp where sal > 100]]]>
+            <![CDATA[select ename from emp where sal > cast (100.0 as 
decimal(4, 1))]]]>
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
@@ -11664,4 +11664,23 @@ LogicalProject(ENAME=[$1])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testEnumerableCalcRule">
+        <Resource name="sql">
+            <![CDATA[select ename from emp where sal > 10.0]]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(FNAME=[$1], LNAME=[$2])
+  LogicalFilter(condition=[>($0, 10)])
+    LogicalTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+EnumerableProject(FNAME=[$1], LNAME=[$2])
+  EnumerableCalc(expr#0..2=[{inputs}], expr#3=[10], expr#4=[>($t0, $t3)], 
proj#0..2=[{exprs}], $condition=[$t4])
+    EnumerableTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+]]>
+        </Resource>
+    </TestCase>
 </Root>

Reply via email to