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 be01394  [CALCITE-3239] Calc#accept(RexShuttle shuttle) does not 
update rowType. (Jin Xing)
be01394 is described below

commit be01394210102ea83dc83f95ce5a59c60525b8d3
Author: jinxing <[email protected]>
AuthorDate: Mon Aug 12 00:04:31 2019 +0800

    [CALCITE-3239] Calc#accept(RexShuttle shuttle) does not update rowType. 
(Jin Xing)
---
 .../java/org/apache/calcite/rel/core/Calc.java     | 22 ++++++--
 .../org/apache/calcite/test/RexShuttleTest.java    | 60 ++++++++++++++++++++++
 2 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/rel/core/Calc.java 
b/core/src/main/java/org/apache/calcite/rel/core/Calc.java
index 278fba8..27cd0df 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Calc.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Calc.java
@@ -27,10 +27,14 @@ import org.apache.calcite.rel.RelWriter;
 import org.apache.calcite.rel.SingleRel;
 import org.apache.calcite.rel.metadata.RelMdUtil;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.type.RelDataType;
+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.rex.RexShuttle;
+import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Util;
 
@@ -167,12 +171,20 @@ public abstract class Calc extends SingleRel {
         && condition == oldCondition) {
       return this;
     }
-    return copy(traitSet, getInput(),
-        new RexProgram(program.getInputRowType(),
-            exprs,
+
+    final RexBuilder rexBuilder = getCluster().getRexBuilder();
+    final RelDataType rowType =
+        RexUtil.createStructType(
+            rexBuilder.getTypeFactory(),
             projects,
-            (RexLocalRef) condition,
-            program.getOutputRowType()));
+            this.rowType.getFieldNames(),
+            null);
+    final RexProgram newProgram =
+        RexProgramBuilder.create(
+            rexBuilder, program.getInputRowType(), exprs, projects,
+            condition, rowType, true, null)
+        .getProgram(false);
+    return copy(traitSet, getInput(), newProgram);
   }
 }
 
diff --git a/core/src/test/java/org/apache/calcite/test/RexShuttleTest.java 
b/core/src/test/java/org/apache/calcite/test/RexShuttleTest.java
index da90d60..f3edfb6 100644
--- a/core/src/test/java/org/apache/calcite/test/RexShuttleTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexShuttleTest.java
@@ -16,11 +16,19 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.plan.hep.HepPlanner;
+import org.apache.calcite.plan.hep.HepProgram;
+import org.apache.calcite.plan.hep.HepProgramBuilder;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.logical.LogicalCalc;
+import org.apache.calcite.rel.rules.ProjectToCalcRule;
 import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexShuttle;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.tools.RelBuilder;
 
@@ -71,6 +79,58 @@ public class RexShuttleTest {
 
     assertThat(type, is(type2));
   }
+
+  @Test
+  public void testCalcUpdatesRowType() {
+    final RelBuilder builder = 
RelBuilder.create(RelBuilderTest.config().build());
+
+    // Equivalent SQL: SELECT deptno, sal, sal + 20 FROM emp
+    final RelNode root =
+        builder
+            .scan("EMP")
+            .project(
+                builder.field("DEPTNO"),
+                builder.field("SAL"),
+                builder.call(SqlStdOperatorTable.PLUS,
+                    builder.field("SAL"), builder.literal(20)))
+            .build();
+
+    HepProgram program = new HepProgramBuilder()
+        .addRuleInstance(ProjectToCalcRule.INSTANCE)
+        .build();
+    HepPlanner planner = new HepPlanner(program);
+    planner.setRoot(root);
+    LogicalCalc calc = (LogicalCalc) planner.findBestExp();
+
+    final RelNode calcWithCastViaRexShuttle = calc.accept(new RexShuttle() {
+      @Override public RexNode visitCall(RexCall call) {
+        return builder.cast(call, SqlTypeName.VARCHAR);
+      }
+
+      @Override public RexNode visitLocalRef(RexLocalRef localRef) {
+        if (calc.getProgram().getExprList().get(localRef.getIndex())
+            instanceof RexCall) {
+          return new RexLocalRef(localRef.getIndex(),
+              builder.getTypeFactory().createSqlType(SqlTypeName.VARCHAR));
+        } else {
+          return localRef;
+        }
+      }
+    });
+
+    // Equivalent SQL: SELECT deptno, sal, CAST(sal + 20 AS VARCHAR) FROM emp
+    final RelNode rootWithCast =
+        builder
+            .scan("EMP")
+            .project(
+                builder.field("DEPTNO"),
+                builder.field("SAL"),
+                builder.cast(
+                    builder.call(SqlStdOperatorTable.PLUS,
+                        builder.field("SAL"), builder.literal(20)), 
SqlTypeName.VARCHAR))
+            .build();
+    assertThat(calcWithCastViaRexShuttle.getRowType(), 
is(rootWithCast.getRowType()));
+  }
 }
 
 // End RexShuttleTest.java

Reply via email to