This is an automated email from the ASF dual-hosted git repository.

yanlin 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 8250798  [CALCITE-4182] Support mv recognition when query has constant 
filter for missing columns in group by list of mv (Wang Yanlin)
8250798 is described below

commit 8250798e4107c639dad122baf868137b35032001
Author: yanlin-Lynn <[email protected]>
AuthorDate: Thu Aug 20 17:00:40 2020 +0800

    [CALCITE-4182] Support mv recognition when query has constant filter for 
missing columns in group by list of mv (Wang Yanlin)
---
 .../apache/calcite/plan/SubstitutionVisitor.java   | 37 ++++++++++-
 .../MaterializedViewSubstitutionVisitorTest.java   | 71 ++++++++++++++++++++++
 2 files changed, 105 insertions(+), 3 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java 
b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index bcf7349..c27394a 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -1860,11 +1860,42 @@ public class SubstitutionVisitor {
       RexNode targetCond, MutableAggregate target) {
     MutableRel result;
     RexBuilder rexBuilder = query.cluster.getRexBuilder();
-    if (query.groupSets.equals(target.groupSets)) {
+    Map<RexNode, RexNode> targetCondConstantMap =
+        RexUtil.predicateConstants(RexNode.class, rexBuilder, 
RelOptUtil.conjunctions(targetCond));
+    // Collect rexInputRef in constant filter condition.
+    Set<Integer> constantCondInputRefs = new HashSet<>();
+    List<Integer> targetGroupByIndexList = target.groupSet.asList();
+    RexShuttle rexShuttle = new RexShuttle() {
+      public RexNode visitInputRef(RexInputRef inputRef) {
+        
constantCondInputRefs.add(targetGroupByIndexList.get(inputRef.getIndex()));
+        return super.visitInputRef(inputRef);
+      }
+    };
+    for (RexNode rexNode : targetCondConstantMap.keySet()) {
+      rexNode.accept(rexShuttle);
+    }
+    Set<Integer> compenGroupSet = null;
+    // Calc the missing group list of query, do not cover grouping sets cases.
+    if (query.groupSets.size() == 1 && target.groupSets.size() == 1) {
+      if (target.groupSet.contains(query.groupSet)) {
+        compenGroupSet = 
target.groupSets.get(0).except(query.groupSets.get(0)).asSet();
+      }
+    }
+    // If query and target have the same group list,
+    // or query has constant filter for missing columns in group by list.
+    if (query.groupSets.equals(target.groupSets)
+        || (compenGroupSet != null && 
constantCondInputRefs.containsAll(compenGroupSet))) {
+      int projOffset = 0;
+      if (!query.groupSets.equals(target.groupSets)) {
+        projOffset = compenGroupSet.size();
+      }
       // Same level of aggregation. Generate a project.
       final List<Integer> projects = new ArrayList<>();
       final int groupCount = query.groupSet.cardinality();
-      for (int i = 0; i < groupCount; i++) {
+      final List<Integer> targetGroupList = target.groupSet.asList();
+      for (Integer inputIndex : query.groupSet.asList()) {
+        // Use the index in target group by.
+        int i = targetGroupList.indexOf(inputIndex);
         projects.add(i);
       }
       for (AggregateCall aggregateCall : query.aggCalls) {
@@ -1872,7 +1903,7 @@ public class SubstitutionVisitor {
         if (i < 0) {
           return null;
         }
-        projects.add(groupCount + i);
+        projects.add(groupCount + i +  projOffset);
       }
 
       List<RexNode> compenProjs = MutableRels.createProjectExprs(target, 
projects);
diff --git 
a/core/src/test/java/org/apache/calcite/test/MaterializedViewSubstitutionVisitorTest.java
 
b/core/src/test/java/org/apache/calcite/test/MaterializedViewSubstitutionVisitorTest.java
index edb4dd8..dab21cd 100644
--- 
a/core/src/test/java/org/apache/calcite/test/MaterializedViewSubstitutionVisitorTest.java
+++ 
b/core/src/test/java/org/apache/calcite/test/MaterializedViewSubstitutionVisitorTest.java
@@ -970,6 +970,77 @@ public class MaterializedViewSubstitutionVisitorTest 
extends AbstractMaterialize
     sql(mv, query).ok();
   }
 
+  @Test void testConstantFilterInAgg() {
+    final String mv = ""
+        + "select \"name\", count(distinct \"deptno\") as cnt\n"
+        + "from \"emps\" group by \"name\"";
+    final String query = ""
+        + "select count(distinct \"deptno\") as cnt\n"
+        + "from \"emps\" where \"name\" = 'hello'";
+    sql(mv, query).withChecker(
+        resultContains(""
+            + "LogicalCalc(expr#0..1=[{inputs}], expr#2=['hello':VARCHAR], 
expr#3=[CAST($t0)"
+            + ":VARCHAR], expr#4=[=($t2, $t3)], CNT=[$t1], $condition=[$t4])\n"
+            + "  EnumerableTableScan(table=[[hr, MV0]])")).ok();
+  }
+
+  @Test void testConstantFilterInAgg2() {
+    final String mv = ""
+        + "select \"name\", \"deptno\", count(distinct \"commission\") as 
cnt\n"
+        + "from \"emps\"\n"
+        + " group by \"name\", \"deptno\"";
+    final String query = ""
+        + "select \"deptno\", count(distinct \"commission\") as cnt\n"
+        + "from \"emps\" where \"name\" = 'hello'\n"
+        + "group by \"deptno\"";
+    sql(mv, query).withChecker(
+        resultContains(""
+            + "LogicalCalc(expr#0..2=[{inputs}], expr#3=['hello':VARCHAR], 
expr#4=[CAST($t0)"
+            + ":VARCHAR], expr#5=[=($t3, $t4)], deptno=[$t1], CNT=[$t2], 
$condition=[$t5])\n"
+            + "  EnumerableTableScan(table=[[hr, MV0]])")).ok();
+  }
+
+  @Test void testConstantFilterInAgg3() {
+    final String mv = ""
+        + "select \"name\", \"deptno\", count(distinct \"commission\") as 
cnt\n"
+        + "from \"emps\"\n"
+        + " group by \"name\", \"deptno\"";
+    final String query = ""
+        + "select \"deptno\", count(distinct \"commission\") as cnt\n"
+        + "from \"emps\" where \"name\" = 'hello' and \"deptno\" = 1\n"
+        + "group by \"deptno\"";
+    sql(mv, query).withChecker(
+        resultContains(""
+            + "LogicalCalc(expr#0..2=[{inputs}], expr#3=['hello':VARCHAR], 
expr#4=[CAST($t0)"
+            + ":VARCHAR], expr#5=[=($t3, $t4)], expr#6=[1], 
expr#7=[CAST($t1):INTEGER NOT NULL], "
+            + "expr#8=[=($t6, $t7)], expr#9=[AND($t5, $t8)], deptno=[$t1], 
CNT=[$t2], "
+            + "$condition=[$t9])\n"
+            + "  EnumerableTableScan(table=[[hr, MV0]])")).ok();
+  }
+
+  @Test void testConstantFilterInAgg4() {
+    final String mv = ""
+        + "select \"name\", \"deptno\", count(distinct \"commission\") as 
cnt\n"
+        + "from \"emps\"\n"
+        + " group by \"name\", \"deptno\"";
+    final String query = ""
+        + "select \"deptno\", \"commission\", count(distinct \"commission\") 
as cnt\n"
+        + "from \"emps\" where \"name\" = 'hello' and \"deptno\" = 1\n"
+        + "group by \"deptno\", \"commission\"";
+    sql(mv, query).noMat();
+  }
+
+  @Test void testConstantFilterInAggUsingSubquery() {
+    final String mv = ""
+        + "select \"name\", count(distinct \"deptno\") as cnt "
+        + "from \"emps\" group by \"name\"";
+    final String query = ""
+        + "select cnt from(\n"
+        + " select \"name\", count(distinct \"deptno\") as cnt "
+        + " from \"emps\" group by \"name\") t\n"
+        + "where \"name\" = 'hello'";
+    sql(mv, query).ok();
+  }
 
   /** Unit test for logic functions
    * {@link org.apache.calcite.plan.SubstitutionVisitor#mayBeSatisfiable} and

Reply via email to