[CALCITE-2078] Aggregate functions in OVER clause (Liao Xintao)

Close apache/calcite#578


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

Branch: refs/heads/master
Commit: c7d9b3d561243c3cb97595f4fe9a0ccf05ce85ac
Parents: d116649
Author: chiyou <[email protected]>
Authored: Tue Dec 5 19:57:19 2017 +0800
Committer: Julian Hyde <[email protected]>
Committed: Tue Dec 5 20:40:53 2017 -0800

----------------------------------------------------------------------
 .../calcite/sql2rel/SqlToRelConverter.java      | 11 ++++++++
 .../apache/calcite/test/RelOptRulesTest.java    | 17 ++++++++++++
 .../apache/calcite/test/SqlValidatorTest.java   | 11 ++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml | 28 ++++++++++++++++++++
 core/src/test/resources/sql/winagg.iq           | 23 ++++++++++++++++
 5 files changed, 90 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/c7d9b3d5/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java 
b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 0672dbe..ede2daf 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -4902,7 +4902,18 @@ public class SqlToRelConverter {
       // operator). However, do not ignore nested window aggregates.
       if (call.getOperator().getKind() == SqlKind.OVER) {
         // Track aggregate nesting levels only within an OVER operator.
+        List<SqlNode> operandList = call.getOperandList();
+        assert operandList.size() == 2;
+
+        // Ignore the top level window aggregates and ranking functions
+        // positioned as the first operand of a OVER operator
         inOver = true;
+        operandList.get(0).accept(this);
+
+        // Normal translation for the second operand of a OVER operator
+        inOver = false;
+        operandList.get(1).accept(this);
+        return null;
       }
 
       // Do not translate the top level window aggregate. Only do so for

http://git-wip-us.apache.org/repos/asf/calcite/blob/c7d9b3d5/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
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 3f1158f..7e1d1ec 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -2780,6 +2780,23 @@ public class RelOptRulesTest extends RelOptTestBase {
     checkPlanning(program, sql);
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2078";>[CALCITE-2078]
+   * Aggregate functions in OVER clause</a>. */
+  @Test public void testWindowFunctionOnAggregations() {
+    final HepProgram program = HepProgram.builder()
+        .addRuleInstance(ProjectToWindowRule.PROJECT)
+        .build();
+    final String sql = "SELECT\n"
+        + "  min(empno),\n"
+        + "  sum(sal),\n"
+        + "  sum(sum(sal))\n"
+        + "    over (partition by min(empno) order by sum(sal))\n"
+        + "from emp\n"
+        + "group by deptno";
+    checkPlanning(program, sql);
+  }
+
   @Test public void testPushAggregateThroughJoin1() throws Exception {
     final HepProgram preProgram = new HepProgramBuilder()
         .addRuleInstance(AggregateProjectMergeRule.INSTANCE)

http://git-wip-us.apache.org/repos/asf/calcite/blob/c7d9b3d5/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index c8b9d46..f62b0aa 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -3952,6 +3952,17 @@ public class SqlValidatorTest extends 
SqlValidatorTestCase {
         .fails("ORDER BY expression should not contain OVER clause");
   }
 
+  @Test public void testAggregateFunctionInOver() {
+    final String sql = "select sum(deptno) over (order by count(empno))\n"
+        + "from emp\n"
+        + "group by deptno";
+    winSql(sql).ok();
+    final String sql2 = "select sum(^empno^) over (order by count(empno))\n"
+        + "from emp\n"
+        + "group by deptno";
+    winSql(sql2).fails("Expression 'EMPNO' is not being grouped");
+  }
+
   @Test public void testWindowFunctions() {
     // SQL 03 Section 6.10
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/c7d9b3d5/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 b1c4852..8061eac 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -2849,6 +2849,34 @@ LogicalProject(EXPR$0=[CAST(/($0, $1)):INTEGER NOT NULL])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testWindowFunctionOnAggregations">
+        <Resource name="sql">
+            <![CDATA[SELECT
+  min(empno),
+  sum(sal),
+  sum(sum(sal))
+    over (partition by min(empno) order by sum(sal))
+from emp
+group by deptno]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(EXPR$0=[$1], EXPR$1=[$2], EXPR$2=[SUM($2) OVER (PARTITION BY $1 
ORDER BY $2 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)])
+  LogicalAggregate(group=[{0}], EXPR$0=[MIN($1)], EXPR$1=[SUM($2)])
+    LogicalProject(DEPTNO=[$7], EMPNO=[$0], SAL=[$5])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(EXPR$0=[$1], EXPR$1=[$2], $2=[$3])
+  LogicalWindow(window#0=[window(partition {1} order by [2] range between 
UNBOUNDED PRECEDING and CURRENT ROW aggs [SUM($2)])])
+    LogicalAggregate(group=[{0}], EXPR$0=[MIN($1)], EXPR$1=[SUM($2)])
+      LogicalProject(DEPTNO=[$7], EMPNO=[$0], SAL=[$5])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testPushSumConstantThroughUnion">
         <Resource name="sql">
             <![CDATA[select ename, sum(u) from

http://git-wip-us.apache.org/repos/asf/calcite/blob/c7d9b3d5/core/src/test/resources/sql/winagg.iq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/winagg.iq 
b/core/src/test/resources/sql/winagg.iq
index 40ef65f..e755670 100644
--- a/core/src/test/resources/sql/winagg.iq
+++ b/core/src/test/resources/sql/winagg.iq
@@ -381,4 +381,27 @@ group by deptno, ename;
 
 !ok
 
+# Window function on top of regular aggregate in partitioning or order clause.
+select deptno, gender, min(ename) as x, sum(deptno) as y,
+  rank() over (partition by gender order by min(ename)) as r,
+  sum(sum(deptno)) over (partition by gender order by min(ename)) as s
+from emp
+group by deptno, gender
+order by gender, r;
++--------+--------+-------+----+---+-----+
+| DEPTNO | GENDER | X     | Y  | R | S   |
++--------+--------+-------+----+---+-----+
+|     30 | F      | Alice | 60 | 1 |  60 |
+|     50 | F      | Eve   | 50 | 2 | 110 |
+|     60 | F      | Grace | 60 | 3 | 170 |
+|     10 | F      | Jane  | 10 | 4 | 180 |
+|        | F      | Wilma |    | 5 | 180 |
+|     50 | M      | Adam  | 50 | 1 |  50 |
+|     10 | M      | Bob   | 10 | 2 |  60 |
+|     20 | M      | Eric  | 20 | 3 |  80 |
++--------+--------+-------+----+---+-----+
+(8 rows)
+
+!ok
+
 # End winagg.iq

Reply via email to