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/06/28 00:27:50 UTC

[3/7] git commit: Reduce count(not null) to count()

Reduce count(not null) to count()


Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/4621db7e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/4621db7e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/4621db7e

Branch: refs/heads/master
Commit: 4621db7e4ee80dd84b14d448d05c093abb8a82f1
Parents: 347eabd
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Mon Jun 23 09:53:11 2014 +0400
Committer: Julian Hyde <ju...@gmail.com>
Committed: Sun Jun 22 23:54:38 2014 -0700

----------------------------------------------------------------------
 .../rel/rules/ReduceAggregatesRule.java         | 42 ++++++++++++++-----
 .../main/java/org/eigenbase/rex/RexBuilder.java | 44 ++++++++++++++++++++
 .../eigenbase/sql2rel/SqlToRelConverter.java    | 10 ++++-
 .../net/hydromatic/optiq/test/JdbcTest.java     | 23 ++++++++++
 .../org/eigenbase/test/RelMetadataTest.java     | 13 ++++--
 .../org/eigenbase/test/RelOptRulesTest.xml      |  2 +-
 .../eigenbase/test/SqlToRelConverterTest.xml    |  4 +-
 7 files changed, 119 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/main/java/org/eigenbase/rel/rules/ReduceAggregatesRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/ReduceAggregatesRule.java b/core/src/main/java/org/eigenbase/rel/rules/ReduceAggregatesRule.java
index 4dc29b9..be9020b 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/ReduceAggregatesRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/ReduceAggregatesRule.java
@@ -26,8 +26,11 @@ import org.eigenbase.reltype.*;
 import org.eigenbase.rex.*;
 import org.eigenbase.sql.*;
 import org.eigenbase.sql.fun.*;
+import org.eigenbase.sql.type.SqlTypeUtil;
 import org.eigenbase.util.*;
 
+import com.google.common.collect.ImmutableList;
+
 /**
  * Rule to reduce aggregates to simpler forms. Currently only AVG(x) to
  * SUM(x)/COUNT(x), but eventually will handle others such as STDDEV.
@@ -49,11 +52,18 @@ public class ReduceAggregatesRule extends RelOptRule {
 
   //~ Methods ----------------------------------------------------------------
 
+  @Override
+  public boolean matches(RelOptRuleCall call) {
+    if (!super.matches(call)) {
+      return false;
+    }
+    AggregateRelBase oldAggRel = (AggregateRelBase) call.rels[0];
+    return containsAvgStddevVarCall(oldAggRel.getAggCallList());
+  }
+
   public void onMatch(RelOptRuleCall ruleCall) {
     AggregateRelBase oldAggRel = (AggregateRelBase) ruleCall.rels[0];
-    if (containsAvgStddevVarCall(oldAggRel.getAggCallList())) {
-      reduceAggs(ruleCall, oldAggRel);
-    }
+    reduceAggs(ruleCall, oldAggRel);
   }
 
   /**
@@ -200,11 +210,14 @@ public class ReduceAggregatesRule extends RelOptRule {
       // anything else:  preserve original call
       RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
       final int nGroups = oldAggRel.getGroupCount();
+      List<RelDataType> oldArgTypes = SqlTypeUtil
+          .projectTypes(oldAggRel.getRowType(), oldCall.getArgList());
       return rexBuilder.addAggCall(
           oldCall,
           nGroups,
           newCalls,
-          aggCallMapping);
+          aggCallMapping,
+          oldArgTypes);
     }
   }
 
@@ -251,13 +264,15 @@ public class ReduceAggregatesRule extends RelOptRule {
             sumCall,
             nGroups,
             newCalls,
-            aggCallMapping);
+            aggCallMapping,
+            ImmutableList.of(avgInputType));
     RexNode denominatorRef =
         rexBuilder.addAggCall(
             countCall,
             nGroups,
             newCalls,
-            aggCallMapping);
+            aggCallMapping,
+            ImmutableList.of(avgInputType));
     final RexNode divideRef =
         rexBuilder.makeCall(
             SqlStdOperatorTable.DIVIDE,
@@ -309,7 +324,8 @@ public class ReduceAggregatesRule extends RelOptRule {
             sumZeroCall,
             nGroups,
             newCalls,
-            aggCallMapping);
+            aggCallMapping,
+            ImmutableList.of(argType));
     if (!oldCall.getType().isNullable()) {
       // If SUM(x) is not nullable, the validator must have determined that
       // nulls are impossible (because the group is never empty and x is never
@@ -321,7 +337,8 @@ public class ReduceAggregatesRule extends RelOptRule {
             countCall,
             nGroups,
             newCalls,
-            aggCallMapping);
+            aggCallMapping,
+            ImmutableList.of(argType));
     return rexBuilder.makeCall(SqlStdOperatorTable.CASE,
         rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
             countRef, rexBuilder.makeExactLiteral(BigDecimal.ZERO)),
@@ -382,7 +399,8 @@ public class ReduceAggregatesRule extends RelOptRule {
             sumArgSquaredAggCall,
             nGroups,
             newCalls,
-            aggCallMapping);
+            aggCallMapping,
+            ImmutableList.of(argType));
 
     final AggregateCall sumArgAggCall =
         new AggregateCall(
@@ -396,7 +414,8 @@ public class ReduceAggregatesRule extends RelOptRule {
             sumArgAggCall,
             nGroups,
             newCalls,
-            aggCallMapping);
+            aggCallMapping,
+            ImmutableList.of(argType));
 
     final RexNode sumSquaredArg =
         rexBuilder.makeCall(
@@ -416,7 +435,8 @@ public class ReduceAggregatesRule extends RelOptRule {
             countArgAggCall,
             nGroups,
             newCalls,
-            aggCallMapping);
+            aggCallMapping,
+            ImmutableList.of(argType));
 
     final RexNode avgSumSquaredArg =
         rexBuilder.makeCall(

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/main/java/org/eigenbase/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rex/RexBuilder.java b/core/src/main/java/org/eigenbase/rex/RexBuilder.java
index 6a848bc..a05df07 100644
--- a/core/src/main/java/org/eigenbase/rex/RexBuilder.java
+++ b/core/src/main/java/org/eigenbase/rex/RexBuilder.java
@@ -262,12 +262,56 @@ public class RexBuilder {
 
   /**
    * Creates a reference to an aggregate call, checking for repeated calls.
+   * @param aggCall aggregate call to be added
+   * @param groupCount number of groups in the aggregate relation
+   * @param aggCalls destination list of aggregate calls
+   * @param aggCallMapping the dictionary of already added calls
+   * @return Rex expression for the given aggregate call
+   * @deprecated Use {@link #addAggCall(org.eigenbase.rel.AggregateCall, int, java.util.List, java.util.Map, java.util.List)}
+   * Will be removed before optiq-0.9.
    */
+  @Deprecated
   public RexNode addAggCall(
       AggregateCall aggCall,
       int groupCount,
       List<AggregateCall> aggCalls,
       Map<AggregateCall, RexNode> aggCallMapping) {
+    Bug.upgrade("remove before optiq-0.9");
+    return addAggCall(aggCall, groupCount, aggCalls, aggCallMapping, null);
+  }
+
+  /**
+   * Creates a reference to an aggregate call, checking for repeated calls.
+   * Argument types help to optimize for repeated aggregates.
+   * For instance count(42) is equivalent to count(*)
+   * @param aggCall aggregate call to be added
+   * @param groupCount number of groups in the aggregate relation
+   * @param aggCalls destination list of aggregate calls
+   * @param aggCallMapping the dictionary of already added calls
+   * @return Rex expression for the given aggregate call
+   */
+  public RexNode addAggCall(
+      AggregateCall aggCall,
+      int groupCount,
+      List<AggregateCall> aggCalls,
+      Map<AggregateCall, RexNode> aggCallMapping,
+      List<RelDataType> aggArgTypes) {
+    if (aggCall.getAggregation() instanceof SqlCountAggFunction
+        && aggArgTypes != null && !aggArgTypes.isEmpty()
+        && !aggCall.isDistinct()) {
+      boolean hasNotNullArg = false;
+      for (RelDataType type : aggArgTypes) {
+        if (!type.isNullable()) {
+          hasNotNullArg = true;
+          break;
+        }
+      }
+      if (hasNotNullArg) {
+        aggCall = new AggregateCall(aggCall.getAggregation(),
+            aggCall.isDistinct(), ImmutableList.<Integer>of(),
+            aggCall.getType(), aggCall.getName());
+      }
+    }
     RexNode rex = aggCallMapping.get(aggCall);
     if (rex == null) {
       int index = aggCalls.size() + groupCount;

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
index 07f4650..682914d 100644
--- a/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
@@ -4556,6 +4556,10 @@ public class SqlToRelConverter {
       if (call.getOperator().isAggregator()) {
         assert bb.agg == this;
         List<Integer> args = new ArrayList<Integer>();
+        List<RelDataType> argTypes =
+            call.getOperator() instanceof SqlCountAggFunction
+            ? new ArrayList<RelDataType>(call.getOperandList().size())
+            : null;
         try {
           // switch out of agg mode
           bb.agg = null;
@@ -4573,6 +4577,9 @@ public class SqlToRelConverter {
             }
             convertedExpr = bb.convertExpression(operand);
             assert convertedExpr != null;
+            if (argTypes != null) {
+              argTypes.add(convertedExpr.getType());
+            }
             args.add(lookupOrCreateGroupExpr(convertedExpr));
           }
         } finally {
@@ -4601,7 +4608,8 @@ public class SqlToRelConverter {
                 aggCall,
                 groupExprs.size(),
                 aggCalls,
-                aggCallMapping);
+                aggCallMapping,
+                argTypes);
         aggMapping.put(call, rex);
       } else if (call instanceof SqlSelect) {
         // rchen 2006-10-17:

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
index 0fdf109..e02c19d 100644
--- a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
+++ b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
@@ -2800,9 +2800,32 @@ public class JdbcTest {
             + " avg(\"deptno\") as a\n"
             + "from \"hr\".\"emps\"\n"
             + "where \"deptno\" < 0")
+        .explainContains(
+            "PLAN=EnumerableCalcRel(expr#0..2=[{inputs}], expr#3=[0], expr#4=[=($t0, $t3)], expr#5=[null], expr#6=[CASE($t4, $t5, $t1)], expr#7=[/($t2, $t0)], expr#8=[CAST($t7):JavaType(class java.lang.Integer)], CS=[$t0], C=[$t0], S=[$t6], A=[$t8])\n"
+            + "  EnumerableAggregateRel(group=[{}], CS=[COUNT()], agg#1=[$SUM0($0)], agg#2=[SUM($0)])\n"
+            + "    EnumerableCalcRel(expr#0..4=[{inputs}], expr#5=[0], expr#6=[<($t1, $t5)], deptno=[$t1], $condition=[$t6])\n"
+            + "      EnumerableTableAccessRel(table=[[hr, emps]])\n")
         .returns("CS=0; C=0; S=null; A=null\n");
   }
 
+  /** Tests that count(deptno) is reduced to count(). */
+  @Test public void testReduceCountNotNullable() {
+    OptiqAssert.that()
+        .with(OptiqAssert.Config.REGULAR)
+        .query(
+            "select\n"
+            + " count(\"deptno\") as cs,\n"
+            + " count(*) as cs2\n"
+            + "from \"hr\".\"emps\"\n"
+            + "where \"deptno\" < 0")
+        .explainContains(
+            "PLAN=EnumerableCalcRel(expr#0=[{inputs}], CS=[$t0], CS2=[$t0])\n"
+            + "  EnumerableAggregateRel(group=[{}], CS=[COUNT()])\n"
+            + "    EnumerableCalcRel(expr#0..4=[{inputs}], expr#5=[0], expr#6=[<($t1, $t5)], DUMMY=[$t5], $condition=[$t6])\n"
+            + "      EnumerableTableAccessRel(table=[[hr, emps]])\n")
+        .returns("CS=0; CS2=0\n");
+  }
+
   /** Tests sorting by a column that is already sorted. */
   @Test public void testOrderByOnSortedTable() {
     OptiqAssert.that()

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/test/java/org/eigenbase/test/RelMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/eigenbase/test/RelMetadataTest.java b/core/src/test/java/org/eigenbase/test/RelMetadataTest.java
index 7b587fe..63be2f9 100644
--- a/core/src/test/java/org/eigenbase/test/RelMetadataTest.java
+++ b/core/src/test/java/org/eigenbase/test/RelMetadataTest.java
@@ -330,11 +330,16 @@ public class RelMetadataTest extends SqlToRelTestBase {
         false);
   }
 
-  @Test public void testColumnOriginsAggMeasure() {
+  @Test public void testColumnOriginsAggReduced() {
+    checkNoColumnOrigin(
+        "select count(deptno),name from dept group by name");
+  }
+
+  @Test public void testColumnOriginsAggCountNullable() {
     checkSingleColumnOrigin(
-        "select count(deptno),name from dept group by name",
-        "DEPT",
-        "DEPTNO",
+        "select count(mgr),ename from emp group by ename",
+        "EMP",
+        "MGR",
         true);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml b/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
index 5976cc7..68ba466 100644
--- a/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
@@ -107,7 +107,7 @@ AggregateRel(group=[{0}], EXPR$1=[MAX($0)], EXPR$2=[AVG($1)], EXPR$3=[MIN($0)])
             <![CDATA[
 ProjectRel(NAME=[$0], EXPR$1=[$1], EXPR$2=[CAST(/($2, $3)):INTEGER NOT NULL], EXPR$3=[$4])
   ProjectRel(NAME=[$0], EXPR$1=[$1], $f2=[$2], $f3=[$3], EXPR$3=[$4])
-    AggregateRel(group=[{0}], EXPR$1=[MAX($0)], agg#1=[$SUM0($1)], agg#2=[COUNT($1)], EXPR$3=[MIN($0)])
+    AggregateRel(group=[{0}], EXPR$1=[MAX($0)], agg#1=[$SUM0($1)], agg#2=[COUNT()], EXPR$3=[MIN($0)])
       ProjectRel(NAME=[$1], DEPTNO=[$0])
         TableAccessRel(table=[[CATALOG, SALES, DEPT]])
 ]]>

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
index c7bbdd5..c2cc97d 100644
--- a/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
@@ -63,7 +63,7 @@ ProjectRel(DEPTNO=[$0], EXPR$1=[$1])
         <Resource name="plan">
             <![CDATA[
 ProjectRel(EXPR$0=[+($0, 4)], EXPR$1=[$1], EXPR$2=[$2], EXPR$3=[*(2, $3)])
-  AggregateRel(group=[{0}], EXPR$1=[SUM($1)], EXPR$2=[SUM($2)], agg#2=[COUNT($1)])
+  AggregateRel(group=[{0}], EXPR$1=[SUM($1)], EXPR$2=[SUM($2)], agg#2=[COUNT()])
     ProjectRel(DEPTNO=[$7], SAL=[$5], $f2=[+(3, $5)])
       TableAccessRel(table=[[CATALOG, SALES, EMP]])
 ]]>
@@ -130,7 +130,7 @@ ProjectRel(NAME=[$0])
             <![CDATA[
 ProjectRel(NAME=[$1], FOO=[$2])
   ProjectRel(DEPTNO=[$1], NAME=[$0], FOO=[$2])
-    AggregateRel(group=[{0, 1}], FOO=[COUNT($1)])
+    AggregateRel(group=[{0, 1}], FOO=[COUNT()])
       ProjectRel(NAME=[$1], DEPTNO=[$0])
         TableAccessRel(table=[[CATALOG, SALES, DEPT]])
 ]]>