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 2014/12/11 20:24:48 UTC
[1/2] incubator-calcite git commit: [CALCITE-502] Support for
grouping sets in AggregateUnionTransposeRule (Jesus Camacho Rodriguez)
Repository: incubator-calcite
Updated Branches:
refs/heads/master cfa1847bc -> 24258852f
[CALCITE-502] Support for grouping sets in AggregateUnionTransposeRule (Jesus Camacho Rodriguez)
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/478ca9de
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/478ca9de
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/478ca9de
Branch: refs/heads/master
Commit: 478ca9de3454d902cc01cb527d8fd74731cda02a
Parents: cfa1847
Author: Jesus Camacho Rodriguez <jc...@hortonworks.com>
Authored: Mon Dec 1 17:03:06 2014 +0000
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Dec 11 09:46:39 2014 -0800
----------------------------------------------------------------------
.../rel/rules/AggregateUnionTransposeRule.java | 31 +-
.../apache/calcite/test/RelOptRulesTest.java | 43 +++
.../org/apache/calcite/test/RelOptRulesTest.xml | 305 +++++++++++++++++++
3 files changed, 360 insertions(+), 19 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/478ca9de/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
index 3aae4ff..dfb0932 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java
@@ -20,9 +20,7 @@ import org.apache.calcite.linq4j.Ord;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.AggregateCall;
import org.apache.calcite.rel.logical.LogicalAggregate;
import org.apache.calcite.rel.logical.LogicalUnion;
@@ -67,7 +65,7 @@ public class AggregateUnionTransposeRule extends RelOptRule {
*/
private AggregateUnionTransposeRule() {
super(
- operand(LogicalAggregate.class, null, Aggregate.IS_SIMPLE,
+ operand(LogicalAggregate.class,
operand(LogicalUnion.class, any())));
}
@@ -90,10 +88,13 @@ public class AggregateUnionTransposeRule extends RelOptRule {
RelOptCluster cluster = union.getCluster();
+ int groupCount = aggRel.getGroupSet().cardinality();
+
List<AggregateCall> transformedAggCalls =
- transformAggCalls(aggRel,
- aggRel.getGroupSet().cardinality(),
- aggRel.getAggCallList());
+ transformAggCalls(
+ aggRel.copy(aggRel.getTraitSet(), aggRel.getInput(), false,
+ aggRel.getGroupSet(), null, aggRel.getAggCallList()),
+ groupCount, aggRel.getAggCallList());
if (transformedAggCalls == null) {
// we've detected the presence of something like AVG,
// which we can't handle
@@ -102,7 +103,7 @@ public class AggregateUnionTransposeRule extends RelOptRule {
boolean anyTransformed = false;
- // create corresponding aggs on top of each union child
+ // create corresponding aggregates on top of each union child
List<RelNode> newUnionInputs = new ArrayList<RelNode>();
for (RelNode input : union.getInputs()) {
boolean alreadyUnique =
@@ -131,18 +132,10 @@ public class AggregateUnionTransposeRule extends RelOptRule {
LogicalUnion newUnion = new LogicalUnion(cluster, newUnionInputs, true);
LogicalAggregate newTopAggRel =
- new LogicalAggregate(cluster, newUnion, false, aggRel.getGroupSet(),
- null, transformedAggCalls);
-
- // In case we transformed any COUNT (which is always NOT NULL)
- // to SUM (which is always NULLABLE), cast back to keep the
- // planner happy.
- RelNode castRel = RelOptUtil.createCastRel(
- newTopAggRel,
- aggRel.getRowType(),
- false);
-
- call.transformTo(castRel);
+ new LogicalAggregate(cluster, newUnion, aggRel.indicator,
+ aggRel.getGroupSet(), aggRel.getGroupSets(), transformedAggCalls);
+
+ call.transformTo(newTopAggRel);
}
private List<AggregateCall> transformAggCalls(RelNode input, int groupCount,
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/478ca9de/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 74235e8..7c78e36 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -921,6 +921,49 @@ public class RelOptRulesTest extends RelOptTestBase {
basePushAggThroughUnion();
}
+ @Test public void testPushSumConstantGroupingSetsThroughUnion() throws
+ Exception {
+ basePushAggThroughUnion();
+ }
+
+ @Test public void testPushSumNullConstantGroupingSetsThroughUnion() throws
+ Exception {
+ basePushAggThroughUnion();
+ }
+
+ @Test public void testPushSumNullableGroupingSetsThroughUnion() throws
+ Exception {
+ basePushAggThroughUnion();
+ }
+
+ @Test public void testPushCountStarGroupingSetsThroughUnion() throws
+ Exception {
+ basePushAggThroughUnion();
+ }
+
+ @Test public void testPushCountNullableGroupingSetsThroughUnion() throws
+ Exception {
+ basePushAggThroughUnion();
+ }
+
+ @Test public void testPushMaxNullableGroupingSetsThroughUnion() throws
+ Exception {
+ basePushAggThroughUnion();
+ }
+
+ @Test public void testPushMinGroupingSetsThroughUnion() throws Exception {
+ basePushAggThroughUnion();
+ }
+
+ @Test public void testPushAvgGroupingSetsThroughUnion() throws Exception {
+ basePushAggThroughUnion();
+ }
+
+ @Test public void testPushSumCountStarGroupingSetsThroughUnion() throws
+ Exception {
+ basePushAggThroughUnion();
+ }
+
private void basePullConstantTroughAggregate() throws Exception {
HepProgram program = new HepProgramBuilder()
.addRuleInstance(ProjectMergeRule.INSTANCE)
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/478ca9de/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 d4cd7d1..c725828 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1163,6 +1163,311 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)], EXPR$2=[$SUM0($2)], EXPR$3=[MIN(
]]>
</Resource>
</TestCase>
+ <TestCase name="testPushSumConstantGroupingSetsThroughUnion">
+ <Resource name="sql">
+ <![CDATA[select deptno, job, sum(u) from
+(select *, 2 u from emp as e1 union all
+ select *, 3 u from emp as e2)
+group by rollup(deptno,job)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], U=[$9])
+ LogicalUnion(all=[true])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], U=[2])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], U=[3])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[SUM($2)])
+ LogicalUnion(all=[true])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], U=[2])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], U=[3])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPushSumNullConstantGroupingSetsThroughUnion">
+ <Resource name="sql">
+ <![CDATA[select deptno, job, sum(u) from
+(select *, cast(null as integer) u from emp as e1 union all
+ select *, cast(null as integer) u from emp as e2)
+group by rollup(deptno,job)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], U=[$9])
+ LogicalUnion(all=[true])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], U=[null])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], U=[null])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[SUM($2)])
+ LogicalUnion(all=[true])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], U=[null])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], U=[null])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPushSumNullableGroupingSetsThroughUnion">
+ <Resource name="sql">
+ <![CDATA[select deptno, job, sum(mgr) from
+(select * from emp as e1 union all
+ select * from emp as e2)
+group by rollup(deptno, job)
+]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], MGR=[$3])
+ 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(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[SUM($2)])
+ LogicalUnion(all=[true])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], MGR=[$3])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], MGR=[$3])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPushCountStarGroupingSetsThroughUnion">
+ <Resource name="sql">
+ <![CDATA[select deptno, job, count(*) from
+(select * from emp as e1 union all
+ select * from emp as e2)
+group by rollup(deptno, job)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[COUNT()])
+ LogicalProject(DEPTNO=[$7], JOB=[$2])
+ 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(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[$SUM0($2)])
+ LogicalUnion(all=[true])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[COUNT()])
+ LogicalProject(DEPTNO=[$7], JOB=[$2])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[COUNT()])
+ LogicalProject(DEPTNO=[$7], JOB=[$2])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPushCountNullableGroupingSetsThroughUnion">
+ <Resource name="sql">
+ <![CDATA[select deptno, job, count(mgr) from
+(select * from emp as e1 union all
+ select * from emp as e2)
+group by rollup(deptno, job)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[COUNT($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], MGR=[$3])
+ 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(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[$SUM0($2)])
+ LogicalUnion(all=[true])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[COUNT($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], MGR=[$3])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[COUNT($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], MGR=[$3])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPushMaxNullableGroupingSetsThroughUnion">
+ <Resource name="sql">
+ <![CDATA[select deptno, job, max(mgr) from
+(select * from emp as e1 union all
+ select * from emp as e2)
+group by rollup(deptno, job)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[MAX($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], MGR=[$3])
+ 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(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[MAX($2)])
+ LogicalUnion(all=[true])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[MAX($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], MGR=[$3])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[MAX($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], MGR=[$3])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPushMinGroupingSetsThroughUnion">
+ <Resource name="sql">
+ <![CDATA[select deptno, job, min(empno) from
+ (select * from emp as e1 union all
+ select * from emp as e2)
+ group by rollup(deptno, job)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[MIN($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], EMPNO=[$0])
+ 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(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[MIN($2)])
+ LogicalUnion(all=[true])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[MIN($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], EMPNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[MIN($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], EMPNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPushAvgGroupingSetsThroughUnion">
+ <Resource name="sql">
+ <![CDATA[select deptno, job, avg(empno) from
+(select * from emp as e1 union all
+ select * from emp as e2)
+group by rollup(deptno, job)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[AVG($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], EMPNO=[$0])
+ 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(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[AVG($2)])
+ LogicalUnion(all=[true])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], EMPNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], EMPNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPushSumCountStarGroupingSetsThroughUnion">
+ <Resource name="sql">
+ <![CDATA[select deptno,job,sum(empno),count(*),min(deptno),max(empno) from
+(select * from emp as e1 union all
+ select * from emp as e2)
+group by rollup(deptno,job)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4], EXPR$3=[$5], EXPR$4=[$6], EXPR$5=[$7])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4], EXPR$3=[$5], EXPR$4=[$6], EXPR$5=[$7])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[SUM($2)], EXPR$3=[COUNT()], EXPR$4=[MIN($0)], EXPR$5=[MAX($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], EMPNO=[$0])
+ 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(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4], EXPR$3=[$5], EXPR$4=[$6], EXPR$5=[$7])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[SUM($2)], EXPR$3=[$SUM0($3)], EXPR$4=[MIN($4)], EXPR$5=[MAX($5)])
+ LogicalUnion(all=[true])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[SUM($2)], EXPR$3=[COUNT()], EXPR$4=[MIN($0)], EXPR$5=[MAX($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], EMPNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0, 1}], EXPR$2=[SUM($2)], EXPR$3=[COUNT()], EXPR$4=[MIN($0)], EXPR$5=[MAX($2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], EMPNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testPullConstantThroughConstLast">
<Resource name="sql">
<![CDATA[select deptno, max(mgr) from (
[2/2] incubator-calcite git commit: [CALCITE-510] Support for
grouping sets in AggregateExpandDistinctAggregatesRule (Jesus Camacho
Rodriguez)
Posted by jh...@apache.org.
[CALCITE-510] Support for grouping sets in AggregateExpandDistinctAggregatesRule (Jesus Camacho Rodriguez)
Close apache/incubator-calcite#27
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/24258852
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/24258852
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/24258852
Branch: refs/heads/master
Commit: 24258852fe70e22dd94dd2e625e7fd781da1b236
Parents: 478ca9d
Author: Jesus Camacho Rodriguez <jc...@hortonworks.com>
Authored: Tue Dec 9 13:16:16 2014 +0000
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Dec 11 10:26:07 2014 -0800
----------------------------------------------------------------------
.../adapter/enumerable/EnumerableAggregate.java | 10 +--
.../org/apache/calcite/rel/core/Aggregate.java | 15 ++++
.../AggregateExpandDistinctAggregatesRule.java | 32 +++++----
.../rel/rules/AggregateReduceFunctionsRule.java | 2 +-
.../apache/calcite/sql2rel/RelFieldTrimmer.java | 6 +-
.../apache/calcite/test/RelOptRulesTest.java | 32 ++++++++-
.../org/apache/calcite/test/RelOptRulesTest.xml | 76 +++++++++++++++++++-
7 files changed, 147 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/24258852/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
index fa945eb..39aaec9 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java
@@ -184,8 +184,8 @@ public class EnumerableAggregate extends Aggregate
final PhysType keyPhysType =
inputPhysType.project(groupSet.asList(), getGroupType() != Group.SIMPLE,
JavaRowFormat.LIST);
- final int keyArity = groupSet.cardinality();
- final int indicatorArity = indicator ? keyArity : 0;
+ final int groupCount = getGroupCount();
+ final int indicatorCount = getIndicatorCount();
final List<AggImpState> aggs =
new ArrayList<AggImpState>(aggCalls.size());
@@ -345,12 +345,12 @@ public class EnumerableAggregate extends Aggregate
final BlockBuilder resultBlock = new BlockBuilder();
final List<Expression> results = Expressions.list();
final ParameterExpression key_;
- if (keyArity == 0) {
+ if (groupCount == 0) {
key_ = null;
} else {
final Type keyType = keyPhysType.getJavaRowType();
key_ = Expressions.parameter(keyType, "key");
- for (int j = 0; j < keyArity + indicatorArity; j++) {
+ for (int j = 0; j < groupCount + indicatorCount; j++) {
results.add(
keyPhysType.fieldReference(key_, j));
}
@@ -388,7 +388,7 @@ public class EnumerableAggregate extends Aggregate
accumulatorAdder,
resultSelector)
.appendIfNotNull(keyPhysType.comparer()))));
- } else if (keyArity == 0) {
+ } else if (groupCount == 0) {
final Expression resultSelector =
builder.append(
"resultSelector",
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/24258852/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
index f6d7c8f..0072d4f 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
@@ -198,6 +198,21 @@ public abstract class Aggregate extends SingleRel {
}
/**
+ * Returns the number of indicator fields.
+ *
+ * <p>This is the same as {@link #getGroupCount()} if {@link #indicator} is
+ * true, zero if {@code indicator} is false.
+ *
+ * <p>The offset of the first aggregate call in the output record is always
+ * <i>groupCount + indicatorCount</i>.
+ *
+ * @return number of indicator fields
+ */
+ public int getIndicatorCount() {
+ return indicator ? getGroupCount() : 0;
+ }
+
+ /**
* Returns a bit set of the grouping fields.
*
* @return bit set of ordinals of grouping fields
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/24258852/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
index 4c017e0..d661727 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
@@ -77,7 +77,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
public AggregateExpandDistinctAggregatesRule(
Class<? extends LogicalAggregate> clazz,
RelFactories.JoinFactory joinFactory) {
- super(operand(clazz, null, Aggregate.IS_SIMPLE, any()));
+ super(operand(clazz, any()));
this.joinFactory = joinFactory;
}
@@ -124,14 +124,14 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
final List<RexInputRef> refs = new ArrayList<RexInputRef>();
final List<String> fieldNames = aggregate.getRowType().getFieldNames();
final ImmutableBitSet groupSet = aggregate.getGroupSet();
- for (int i : Util.range(groupSet.cardinality())) {
+ final int groupAndIndicatorCount =
+ aggregate.getGroupCount() + aggregate.getIndicatorCount();
+ for (int i : Util.range(groupAndIndicatorCount)) {
refs.add(RexInputRef.of(i, aggFields));
}
// Aggregate the original relation, including any non-distinct aggregates.
-
List<AggregateCall> newAggCallList = new ArrayList<AggregateCall>();
- final int groupCount = groupSet.cardinality();
int i = -1;
for (AggregateCall aggCall : aggregate.getAggCallList()) {
++i;
@@ -141,8 +141,8 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
}
refs.add(
new RexInputRef(
- groupCount + newAggCallList.size(),
- aggFields.get(groupCount + i).getType()));
+ groupAndIndicatorCount + newAggCallList.size(),
+ aggFields.get(groupAndIndicatorCount + i).getType()));
newAggCallList.add(aggCall);
}
@@ -155,7 +155,8 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
} else {
rel =
new LogicalAggregate(aggregate.getCluster(), aggregate.getInput(),
- false, groupSet, null, newAggCallList);
+ aggregate.indicator, groupSet, aggregate.getGroupSets(),
+ newAggCallList);
}
// For each set of operands, find and rewrite all calls which have that
@@ -294,8 +295,9 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
List<AggregateCall> aggCallList = new ArrayList<AggregateCall>();
final List<AggregateCall> aggCalls = aggregate.getAggCallList();
- final int groupCount = aggregate.getGroupSet().cardinality();
- int i = groupCount - 1;
+ final int groupAndIndicatorCount =
+ aggregate.getGroupCount() + aggregate.getIndicatorCount();
+ int i = groupAndIndicatorCount - 1;
for (AggregateCall aggCall : aggCalls) {
++i;
@@ -327,20 +329,20 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
assert refs.get(i) == null;
if (left == null) {
refs.set(i,
- new RexInputRef(groupCount + aggCallList.size(),
+ new RexInputRef(groupAndIndicatorCount + aggCallList.size(),
newAggCall.getType()));
} else {
refs.set(i,
- new RexInputRef(leftFields.size() + groupCount + aggCallList.size(),
- newAggCall.getType()));
+ new RexInputRef(leftFields.size() + groupAndIndicatorCount
+ + aggCallList.size(), newAggCall.getType()));
}
aggCallList.add(newAggCall);
}
Aggregate distinctAgg =
- aggregate.copy(aggregate.getTraitSet(), distinct, false,
+ aggregate.copy(aggregate.getTraitSet(), distinct, aggregate.indicator,
ImmutableBitSet.range(aggregate.getGroupSet().cardinality()),
- null, aggCallList);
+ aggregate.getGroupSets(), aggCallList);
// If there's no left child yet, no need to create the join
if (left == null) {
@@ -353,7 +355,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
final List<RelDataTypeField> distinctFields =
distinctAgg.getRowType().getFieldList();
final List<RexNode> conditions = Lists.newArrayList();
- for (i = 0; i < groupCount; ++i) {
+ for (i = 0; i < groupAndIndicatorCount; ++i) {
// null values form its own group
// use "is not distinct from" so that the join condition
// allows null values to match.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/24258852/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
index 4d2df21..93c9f09 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
@@ -134,7 +134,7 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
List<AggregateCall> oldCalls = oldAggRel.getAggCallList();
final int groupCount = oldAggRel.getGroupCount();
- final int indicatorCount = oldAggRel.indicator ? groupCount : 0;
+ final int indicatorCount = oldAggRel.getIndicatorCount();
final List<AggregateCall> newCalls = Lists.newArrayList();
final Map<AggregateCall, RexNode> aggCallMapping = Maps.newHashMap();
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/24258852/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 f2409ff..dbbfa3f 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -773,7 +773,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
// We have to return group keys and (if present) indicators.
// So, pretend that the consumer asked for them.
final int groupCount = aggregate.getGroupSet().cardinality();
- final int indicatorCount = aggregate.indicator ? groupCount : 0;
+ final int indicatorCount = aggregate.getIndicatorCount();
fieldsUsed =
fieldsUsed.union(ImmutableBitSet.range(groupCount + indicatorCount));
@@ -814,8 +814,8 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
}
}));
- // Populate mapping of where to find the fields. System and grouping
- // fields first.
+ // Populate mapping of where to find the fields. System, group key and
+ // indicator fields first.
for (IntPair pair : inputMapping) {
if (pair.source < groupCount) {
mapping.set(pair.source, pair.target);
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/24258852/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 7c78e36..9459a67 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -316,7 +316,7 @@ public class RelOptRulesTest extends RelOptTestBase {
+ " from sales.dept group by name");
}
- @Test public void testDistinctCount() {
+ @Test public void testDistinctCount1() {
final HepProgram program = HepProgram.builder()
.addRuleInstance(AggregateExpandDistinctAggregatesRule.INSTANCE)
.addRuleInstance(AggregateProjectMergeRule.INSTANCE)
@@ -326,6 +326,36 @@ public class RelOptRulesTest extends RelOptTestBase {
+ " from sales.emp group by deptno");
}
+ @Test public void testDistinctCount2() {
+ final HepProgram program = HepProgram.builder()
+ .addRuleInstance(AggregateExpandDistinctAggregatesRule.INSTANCE)
+ .addRuleInstance(AggregateProjectMergeRule.INSTANCE)
+ .build();
+ checkPlanning(program,
+ "select deptno, count(distinct ename), sum(sal)"
+ + " from sales.emp group by deptno");
+ }
+
+ @Test public void testDistinctCountGroupingSets1() {
+ final HepProgram program = HepProgram.builder()
+ .addRuleInstance(AggregateExpandDistinctAggregatesRule.INSTANCE)
+ .addRuleInstance(ProjectMergeRule.INSTANCE)
+ .build();
+ checkPlanning(program,
+ "select deptno, job, count(distinct ename)"
+ + " from sales.emp group by rollup(deptno,job)");
+ }
+
+ @Test public void testDistinctCountGroupingSets2() {
+ final HepProgram program = HepProgram.builder()
+ .addRuleInstance(AggregateExpandDistinctAggregatesRule.INSTANCE)
+ .addRuleInstance(ProjectMergeRule.INSTANCE)
+ .build();
+ checkPlanning(program,
+ "select deptno, job, count(distinct ename), sum(sal)"
+ + " from sales.emp group by rollup(deptno,job)");
+ }
+
@Test public void testPushProjectPastFilter() {
checkPlanning(ProjectFilterTransposeRule.INSTANCE,
"select empno + deptno from emp where sal = 10 * comm "
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/24258852/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 c725828..f80de19 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -2734,7 +2734,7 @@ LogicalProject(ENAME=[$0], R=[$1])
]]>
</Resource>
</TestCase>
- <TestCase name="testDistinctCount">
+ <TestCase name="testDistinctCount1">
<Resource name="sql">
<![CDATA[select deptno, count(distinct ename) from sales.emp group by deptno]]>
</Resource>
@@ -2753,6 +2753,80 @@ LogicalAggregate(group=[{1}], EXPR$1=[COUNT($0)])
]]>
</Resource>
</TestCase>
+ <TestCase name="testDistinctCount2">
+ <Resource name="sql">
+ <![CDATA[select deptno, count(distinct ename), sum(sal) from sales.emp group by deptno]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalAggregate(group=[{0}], EXPR$1=[COUNT(DISTINCT $1)], EXPR$2=[SUM($2)])
+ LogicalProject(DEPTNO=[$7], ENAME=[$1], SAL=[$5])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], EXPR$1=[$3], EXPR$2=[$1])
+ LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $2)], joinType=[inner])
+ LogicalAggregate(group=[{7}], EXPR$2=[SUM($5)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{1}], EXPR$1=[COUNT($0)])
+ LogicalAggregate(group=[{1, 7}])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testDistinctCountGroupingSets1">
+ <Resource name="sql">
+ <![CDATA[select deptno, job, count(distinct ename) from sales.emp group by rollup(deptno,job)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[COUNT(DISTINCT $2)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], ENAME=[$1])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$4])
+ LogicalAggregate(group=[{0, 1}], indicator=[true], EXPR$2=[COUNT($2)])
+ LogicalAggregate(group=[{0, 1, 2}])
+ LogicalProject(DEPTNO=[$0], JOB=[$1], ENAME=[$2])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], ENAME=[$1])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testDistinctCountGroupingSets2">
+ <Resource name="sql">
+ <![CDATA[select deptno, job, count(distinct ename), sum(sal) from sales.emp group by rollup(deptno,job)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$0], JOB=[$1], EXPR$2=[$4], EXPR$3=[$5])
+ LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], i$DEPTNO=[$2], i$JOB=[$3], EXPR$2=[$4], EXPR$3=[$5])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[COUNT(DISTINCT $2)], EXPR$3=[SUM($3)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], ENAME=[$1], SAL=[$5])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(DEPTNO=[CASE($2, null, $0)], JOB=[CASE($3, null, $1)], EXPR$2=[$9], EXPR$3=[$4])
+ LogicalJoin(condition=[AND(IS NOT DISTINCT FROM($0, $5), IS NOT DISTINCT FROM($1, $6), IS NOT DISTINCT FROM($2, $7), IS NOT DISTINCT FROM($3, $8))], joinType=[inner])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$3=[SUM($3)])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], ENAME=[$1], SAL=[$5])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}, {}]], indicator=[true], EXPR$2=[COUNT($2)])
+ LogicalAggregate(group=[{0, 1, 2}])
+ LogicalProject(DEPTNO=[$7], JOB=[$2], ENAME=[$1])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testConvertMultiJoinRuleOuterJoins2">
<Resource name="sql">
<![CDATA[select * from A right join B on a = b join C on b = c]]>