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