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 f26d92f  [CALCITE-3004] RexOver is incorrectly pushed down in 
ProjectSetOpTransposeRule and ProjectCorrelateTransposeRule (Chunwei Lei)
f26d92f is described below

commit f26d92f956c4f8b59bafbf7cfc7431f3d4d536f9
Author: Chunwei Lei <[email protected]>
AuthorDate: Tue Apr 16 13:24:51 2019 +0800

    [CALCITE-3004] RexOver is incorrectly pushed down in 
ProjectSetOpTransposeRule and ProjectCorrelateTransposeRule (Chunwei Lei)
---
 .../rel/rules/ProjectCorrelateTransposeRule.java   |  5 +-
 .../rel/rules/ProjectSetOpTransposeRule.java       | 45 +++++++++++------
 .../org/apache/calcite/test/RelOptRulesTest.java   | 21 ++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 59 ++++++++++++++++++++++
 4 files changed, 112 insertions(+), 18 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ProjectCorrelateTransposeRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/ProjectCorrelateTransposeRule.java
index adeac9e..56d572e 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/ProjectCorrelateTransposeRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/ProjectCorrelateTransposeRule.java
@@ -30,6 +30,7 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexCorrelVariable;
 import org.apache.calcite.rex.RexFieldAccess;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexOver;
 import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.BitSets;
@@ -43,10 +44,10 @@ import java.util.Map;
 /**
  * Push Project under Correlate to apply on Correlate's left and right child
  */
-public class ProjectCorrelateTransposeRule  extends RelOptRule {
+public class ProjectCorrelateTransposeRule extends RelOptRule {
 
   public static final ProjectCorrelateTransposeRule INSTANCE =
-      new ProjectCorrelateTransposeRule(expr -> true,
+      new ProjectCorrelateTransposeRule(expr -> !(expr instanceof RexOver),
           RelFactories.LOGICAL_BUILDER);
 
   //~ Instance fields --------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ProjectSetOpTransposeRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/ProjectSetOpTransposeRule.java
index 6190556..ce5adf9 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/ProjectSetOpTransposeRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/ProjectSetOpTransposeRule.java
@@ -24,6 +24,7 @@ import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.core.SetOp;
 import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexOver;
 import org.apache.calcite.tools.RelBuilderFactory;
 
 import java.util.ArrayList;
@@ -40,7 +41,7 @@ import java.util.List;
  */
 public class ProjectSetOpTransposeRule extends RelOptRule {
   public static final ProjectSetOpTransposeRule INSTANCE =
-      new ProjectSetOpTransposeRule(expr -> false,
+      new ProjectSetOpTransposeRule(expr -> !(expr instanceof RexOver),
           RelFactories.LOGICAL_BUILDER);
 
   //~ Instance fields --------------------------------------------------------
@@ -90,23 +91,35 @@ public class ProjectSetOpTransposeRule extends RelOptRule {
     List<RelNode> newSetOpInputs = new ArrayList<>();
     int[] adjustments = pushProject.getAdjustments();
 
-    // push the projects completely below the setop; this
-    // is different from pushing below a join, where we decompose
-    // to try to keep expensive expressions above the join,
-    // because UNION ALL does not have any filtering effect,
-    // and it is the only operator this rule currently acts on
-    for (RelNode input : setOp.getInputs()) {
-      // be lazy:  produce two ProjectRels, and let another rule
-      // merge them (could probably just clone origProj instead?)
-      Project p = pushProject.createProjectRefsAndExprs(input, true, false);
-      newSetOpInputs.add(pushProject.createNewProject(p, adjustments));
+    final RelNode node;
+    if (RexOver.containsOver(origProj.getProjects(), null)) {
+      // should not push over past setop but can push its operand down.
+      for (RelNode input : setOp.getInputs()) {
+        Project p = pushProject.createProjectRefsAndExprs(input, true, false);
+        // make sure that it is not a trivial project to avoid infinite loop.
+        if (p.getRowType().equals(input.getRowType())) {
+          return;
+        }
+        newSetOpInputs.add(p);
+      }
+      SetOp newSetOp =
+          setOp.copy(setOp.getTraitSet(), newSetOpInputs);
+      node = pushProject.createNewProject(newSetOp, adjustments);
+    } else {
+      // push some expressions below the setop; this
+      // is different from pushing below a join, where we decompose
+      // to try to keep expensive expressions above the join,
+      // because UNION ALL does not have any filtering effect,
+      // and it is the only operator this rule currently acts on
+      setOp.getInputs().forEach(input ->
+          newSetOpInputs.add(
+              pushProject.createNewProject(
+                  pushProject.createProjectRefsAndExprs(
+                      input, true, false), adjustments)));
+      node = setOp.copy(setOp.getTraitSet(), newSetOpInputs);
     }
 
-    // create a new setop whose children are the ProjectRels created above
-    SetOp newSetOp =
-        setOp.copy(setOp.getTraitSet(), newSetOpInputs);
-
-    call.transformTo(newSetOp);
+    call.transformTo(node);
   }
 }
 
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 664a2e5..2516f72 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -1205,6 +1205,16 @@ public class RelOptRulesTest extends RelOptTestBase {
             + "on e.ename = b.ename and e.deptno = 10");
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-3004";>[CALCITE-3004]
+   * Should not push over past union but its operands can since setop
+   * will affect row count</a>. */
+  @Test public void testProjectSetOpTranspose() {
+    checkPlanning(ProjectSetOpTransposeRule.INSTANCE,
+        "select job, sum(sal + 100) over (partition by deptno) from\n"
+            + "(select * from emp e1 union all select * from emp e2)");
+  }
+
   @Test public void testProjectCorrelateTransposeDynamic() {
     ProjectCorrelateTransposeRule customPCTrans =
         new ProjectCorrelateTransposeRule(skipItem, 
RelFactories.LOGICAL_BUILDER);
@@ -1337,6 +1347,17 @@ public class RelOptRulesTest extends RelOptTestBase {
             + "unnest(t1.employees) as t2");
   }
 
+  /** As {@link #testProjectSetOpTranspose()};
+   * should not push over past correlate but its operands can since correlate
+   * will affect row count. */
+  @Test public void testProjectCorrelateTransposeWithOver() {
+    checkPlanning(ProjectCorrelateTransposeRule.INSTANCE,
+        "select sum(t1.deptno + 1) over (partition by t1.name),\n"
+            + "count(t2.empno) over ()\n"
+            + "from DEPT_NESTED as t1, "
+            + "unnest(t1.employees) as t2");
+  }
+
   /** Tests that the default instance of {@link FilterProjectTransposeRule}
    * does not push a Filter that contains a correlating variable.
    *
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 53f19e2..e90f1b0 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -9778,6 +9778,35 @@ LogicalProject(NAME=[$0], ENAME=[$2])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testProjectSetOpTranspose">
+        <Resource name="sql">
+            <![CDATA[select job, sum(sal + 100) over (partition by deptno) from
+(select * from emp e1 union all select * from emp e2)
+]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(JOB=[$2], EXPR$1=[SUM(+($5, 100)) OVER (PARTITION BY $7 RANGE 
BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)])
+  LogicalUnion(all=[true])
+    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], 
SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+    LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], 
SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(JOB=[$0], EXPR$1=[SUM($2) OVER (PARTITION BY $1 RANGE BETWEEN 
UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)])
+  LogicalUnion(all=[true])
+    LogicalProject(JOB=[$2], DEPTNO=[$7], +=[+($5, 100)])
+      LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], 
HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+    LogicalProject(JOB=[$2], DEPTNO=[$7], +=[+($5, 100)])
+      LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], 
HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testProjectCorrelateTransposeDynamic">
         <Resource name="sql">
             <![CDATA[select t1.c_nationkey, t2.a as fake_col2 from 
SALES.CUSTOMER as t1, unnest(t1.fake_col) as t2(a)]]>
@@ -9832,6 +9861,36 @@ LogicalProject(NAME=[$0], ENAME=[$2])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testProjectCorrelateTransposeWithOver">
+        <Resource name="sql">
+            <![CDATA[select sum(t1.deptno + 1) over (partition by t1.name),
+count(t2.empno) over ()
+from DEPT_NESTED as t1, unnest(t1.employees) as t2
+]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(EXPR$0=[SUM(+($0, 1)) OVER (PARTITION BY $1 RANGE BETWEEN 
UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)], EXPR$1=[COUNT($4) OVER (RANGE 
BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)])
+  LogicalCorrelate(correlation=[$cor0], joinType=[inner], 
requiredColumns=[{3}])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT_NESTED]])
+    Uncollect
+      LogicalProject(EMPLOYEES=[$cor0.EMPLOYEES])
+        LogicalValues(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(EXPR$0=[SUM($2) OVER (PARTITION BY $0 RANGE BETWEEN UNBOUNDED 
PRECEDING AND UNBOUNDED FOLLOWING)], EXPR$1=[COUNT($3) OVER (RANGE BETWEEN 
UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)])
+  LogicalCorrelate(correlation=[$cor1], joinType=[inner], 
requiredColumns=[{1}])
+    LogicalProject(NAME=[$1], EMPLOYEES=[$3], +=[+($0, 1)])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT_NESTED]])
+    LogicalProject(EMPNO=[$0])
+      Uncollect
+        LogicalProject(EMPLOYEES=[$cor1.EMPLOYEES])
+          LogicalValues(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testProjectCorrelateTransposeRuleLeftCorrelate">
         <Resource name="planBefore">
             <![CDATA[

Reply via email to