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

jcamacho 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 7bc9258  [CALCITE-2976] Improve materialized view rewriting coverage 
with disjunctive predicates
7bc9258 is described below

commit 7bc925872e6ab213a9937a6a4c21cf8c31326910
Author: Jesus Camacho Rodriguez <[email protected]>
AuthorDate: Tue Apr 2 09:19:23 2019 -0700

    [CALCITE-2976] Improve materialized view rewriting coverage with 
disjunctive predicates
    
    Close apache/calcite#1144
---
 .../rel/rules/AbstractMaterializedViewRule.java    | 109 ++++++---------------
 .../apache/calcite/test/MaterializationTest.java   |  53 +++++++---
 2 files changed, 70 insertions(+), 92 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java
index 01bb2e3..101b42a 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java
@@ -72,9 +72,6 @@ import org.apache.calcite.util.mapping.MappingType;
 import org.apache.calcite.util.mapping.Mappings;
 import org.apache.calcite.util.trace.CalciteLogger;
 
-import org.apache.commons.lang3.tuple.ImmutableTriple;
-import org.apache.commons.lang3.tuple.Triple;
-
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.BiMap;
@@ -240,13 +237,12 @@ public abstract class AbstractMaterializedViewRule 
extends RelOptRule {
           simplify.simplifyUnknownAsFalse(
               RexUtil.composeConjunction(rexBuilder,
                   queryPredicateList.pulledUpPredicates));
-      final Triple<RexNode, RexNode, RexNode> queryPreds =
-          splitPredicates(rexBuilder, pred);
+      final Pair<RexNode, RexNode> queryPreds = splitPredicates(rexBuilder, 
pred);
 
       // Extract query equivalence classes. An equivalence class is a set
       // of columns in the query output that are known to be equal.
       final EquivalenceClasses qEC = new EquivalenceClasses();
-      for (RexNode conj : RelOptUtil.conjunctions(queryPreds.getLeft())) {
+      for (RexNode conj : RelOptUtil.conjunctions(queryPreds.left)) {
         assert conj.isA(SqlKind.EQUALS);
         RexCall equiCond = (RexCall) conj;
         qEC.addEquivalenceClass(
@@ -308,8 +304,7 @@ public abstract class AbstractMaterializedViewRule extends 
RelOptRule {
         final RexNode viewPred = simplify.simplifyUnknownAsFalse(
             RexUtil.composeConjunction(rexBuilder,
                 viewPredicateList.pulledUpPredicates));
-        final Triple<RexNode, RexNode, RexNode> viewPreds =
-            splitPredicates(rexBuilder, viewPred);
+        final Pair<RexNode, RexNode> viewPreds = splitPredicates(rexBuilder, 
viewPred);
 
         // Extract view tables
         MatchModality matchModality;
@@ -324,7 +319,7 @@ public abstract class AbstractMaterializedViewRule extends 
RelOptRule {
           if (viewTableRefs.containsAll(queryTableRefs)) {
             matchModality = MatchModality.QUERY_PARTIAL;
             final EquivalenceClasses vEC = new EquivalenceClasses();
-            for (RexNode conj : RelOptUtil.conjunctions(viewPreds.getLeft())) {
+            for (RexNode conj : RelOptUtil.conjunctions(viewPreds.left)) {
               assert conj.isA(SqlKind.EQUALS);
               RexCall equiCond = (RexCall) conj;
               vEC.addEquivalenceClass(
@@ -405,7 +400,7 @@ public abstract class AbstractMaterializedViewRule extends 
RelOptRule {
           // First, to establish relationship, we swap column references of 
the view
           // predicates to point to query tables and compute equivalence 
classes.
           final RexNode viewColumnsEquiPred = RexUtil.swapTableReferences(
-              rexBuilder, viewPreds.getLeft(), 
queryToViewTableMapping.inverse());
+              rexBuilder, viewPreds.left, queryToViewTableMapping.inverse());
           final EquivalenceClasses queryBasedVEC = new EquivalenceClasses();
           for (RexNode conj : RelOptUtil.conjunctions(viewColumnsEquiPred)) {
             assert conj.isA(SqlKind.EQUALS);
@@ -414,7 +409,7 @@ public abstract class AbstractMaterializedViewRule extends 
RelOptRule {
                 (RexTableInputRef) equiCond.getOperands().get(0),
                 (RexTableInputRef) equiCond.getOperands().get(1));
           }
-          Triple<RexNode, RexNode, RexNode> compensationPreds =
+          Pair<RexNode, RexNode> compensationPreds =
               computeCompensationPredicates(rexBuilder, simplify,
                   currQEC, queryPreds, queryBasedVEC, viewPreds,
                   queryToViewTableMapping);
@@ -430,11 +425,8 @@ public abstract class AbstractMaterializedViewRule extends 
RelOptRule {
               // This was our last chance to use the view, skip it
               continue;
             }
-            RexNode compensationColumnsEquiPred = compensationPreds.getLeft();
-            RexNode otherCompensationPred =
-                RexUtil.composeConjunction(rexBuilder,
-                    ImmutableList.of(compensationPreds.getMiddle(),
-                        compensationPreds.getRight()));
+            RexNode compensationColumnsEquiPred = compensationPreds.left;
+            RexNode otherCompensationPred = compensationPreds.right;
             assert !compensationColumnsEquiPred.isAlwaysTrue()
                 || !otherCompensationPred.isAlwaysTrue();
 
@@ -468,11 +460,8 @@ public abstract class AbstractMaterializedViewRule extends 
RelOptRule {
             }
             call.transformTo(result);
           } else if (compensationPreds != null) {
-            RexNode compensationColumnsEquiPred = compensationPreds.getLeft();
-            RexNode otherCompensationPred =
-                RexUtil.composeConjunction(rexBuilder,
-                    ImmutableList.of(compensationPreds.getMiddle(),
-                        compensationPreds.getRight()));
+            RexNode compensationColumnsEquiPred = compensationPreds.left;
+            RexNode otherCompensationPred = compensationPreds.right;
 
             // a. Compute final compensation predicate.
             if (!compensationColumnsEquiPred.isAlwaysTrue()
@@ -1895,24 +1884,20 @@ public abstract class AbstractMaterializedViewRule 
extends RelOptRule {
   }
 
   /**
-   * Classifies each of the predicates in the list into one of these three
+   * Classifies each of the predicates in the list into one of these two
    * categories:
    *
    * <ul>
    * <li> 1-l) column equality predicates, or
-   * <li> 2-m) range predicates, comprising &lt;, &le;, &gt;, &ge;, and =
-   *      between a reference and a constant, or
-   * <li> 3-r) residual predicates, all the rest
+   * <li> 2-r) residual predicates, all the rest
    * </ul>
    *
    * <p>For each category, it creates the conjunction of the predicates. The
-   * result is an array of three RexNode objects corresponding to each
-   * category.
+   * result is an pair of RexNode objects corresponding to each category.
    */
-  private static Triple<RexNode, RexNode, RexNode> splitPredicates(
+  private static Pair<RexNode, RexNode> splitPredicates(
       RexBuilder rexBuilder, RexNode pred) {
     List<RexNode> equiColumnsPreds = new ArrayList<>();
-    List<RexNode> rangePreds = new ArrayList<>();
     List<RexNode> residualPreds = new ArrayList<>();
     for (RexNode e : RelOptUtil.conjunctions(pred)) {
       switch (e.getKind()) {
@@ -1921,26 +1906,6 @@ public abstract class AbstractMaterializedViewRule 
extends RelOptRule {
         if (RexUtil.isReferenceOrAccess(eqCall.getOperands().get(0), false)
                 && RexUtil.isReferenceOrAccess(eqCall.getOperands().get(1), 
false)) {
           equiColumnsPreds.add(e);
-        } else if ((RexUtil.isReferenceOrAccess(eqCall.getOperands().get(0), 
false)
-                && RexUtil.isConstant(eqCall.getOperands().get(1)))
-            || (RexUtil.isReferenceOrAccess(eqCall.getOperands().get(1), false)
-                && RexUtil.isConstant(eqCall.getOperands().get(0)))) {
-          rangePreds.add(e);
-        } else {
-          residualPreds.add(e);
-        }
-        break;
-      case LESS_THAN:
-      case GREATER_THAN:
-      case LESS_THAN_OR_EQUAL:
-      case GREATER_THAN_OR_EQUAL:
-      case NOT_EQUALS:
-        RexCall rangeCall = (RexCall) e;
-        if ((RexUtil.isReferenceOrAccess(rangeCall.getOperands().get(0), false)
-                && RexUtil.isConstant(rangeCall.getOperands().get(1)))
-            || (RexUtil.isReferenceOrAccess(rangeCall.getOperands().get(1), 
false)
-                && RexUtil.isConstant(rangeCall.getOperands().get(0)))) {
-          rangePreds.add(e);
         } else {
           residualPreds.add(e);
         }
@@ -1949,9 +1914,8 @@ public abstract class AbstractMaterializedViewRule 
extends RelOptRule {
         residualPreds.add(e);
       }
     }
-    return ImmutableTriple.of(
+    return Pair.of(
         RexUtil.composeConjunction(rexBuilder, equiColumnsPreds),
-        RexUtil.composeConjunction(rexBuilder, rangePreds),
         RexUtil.composeConjunction(rexBuilder, residualPreds));
   }
 
@@ -2078,17 +2042,16 @@ public abstract class AbstractMaterializedViewRule 
extends RelOptRule {
    *
    * <p>In turn, if containment cannot be confirmed, the method returns null.
    */
-  private static Triple<RexNode, RexNode, RexNode> 
computeCompensationPredicates(
+  private static Pair<RexNode, RexNode> computeCompensationPredicates(
       RexBuilder rexBuilder,
       RexSimplify simplify,
       EquivalenceClasses sourceEC,
-      Triple<RexNode, RexNode, RexNode> sourcePreds,
+      Pair<RexNode, RexNode> sourcePreds,
       EquivalenceClasses targetEC,
-      Triple<RexNode, RexNode, RexNode> targetPreds,
+      Pair<RexNode, RexNode> targetPreds,
       BiMap<RelTableRef, RelTableRef> sourceToTargetTableMapping) {
     final RexNode compensationColumnsEquiPred;
-    final RexNode compensationRangePred;
-    final RexNode compensationResidualPred;
+    final RexNode compensationPred;
 
     // 1. Establish relationship between source and target equivalence classes.
     // If every target equivalence class is not a subset of a source
@@ -2100,37 +2063,21 @@ public abstract class AbstractMaterializedViewRule 
extends RelOptRule {
       return null;
     }
 
-    // 2. We check that range intervals for the source are contained in the 
target.
-    // Compute compensating predicates.
-    final RexNode queryRangePred = RexUtil.swapColumnReferences(
-        rexBuilder, sourcePreds.getMiddle(), 
sourceEC.getEquivalenceClassesMap());
-    final RexNode viewRangePred = RexUtil.swapTableColumnReferences(
-        rexBuilder, targetPreds.getMiddle(), 
sourceToTargetTableMapping.inverse(),
-        sourceEC.getEquivalenceClassesMap());
-    compensationRangePred = SubstitutionVisitor.splitFilter(
-        simplify, queryRangePred, viewRangePred);
-    if (compensationRangePred == null) {
-      // Cannot rewrite
-      return null;
-    }
-
-    // 3. Finally, we check that residual predicates of the source are 
satisfied
-    // within the target.
+    // 2. We check that that residual predicates of the source are satisfied 
within the target.
     // Compute compensating predicates.
-    final RexNode queryResidualPred = RexUtil.swapColumnReferences(
-        rexBuilder, sourcePreds.getRight(), 
sourceEC.getEquivalenceClassesMap());
-    final RexNode viewResidualPred = RexUtil.swapTableColumnReferences(
-        rexBuilder, targetPreds.getRight(), 
sourceToTargetTableMapping.inverse(),
+    final RexNode queryPred = RexUtil.swapColumnReferences(
+        rexBuilder, sourcePreds.right, sourceEC.getEquivalenceClassesMap());
+    final RexNode viewPred = RexUtil.swapTableColumnReferences(
+        rexBuilder, targetPreds.right, sourceToTargetTableMapping.inverse(),
         sourceEC.getEquivalenceClassesMap());
-    compensationResidualPred = SubstitutionVisitor.splitFilter(
-        simplify, queryResidualPred, viewResidualPred);
-    if (compensationResidualPred == null) {
+    compensationPred = SubstitutionVisitor.splitFilter(
+        simplify, queryPred, viewPred);
+    if (compensationPred == null) {
       // Cannot rewrite
       return null;
     }
 
-    return ImmutableTriple.of(compensationColumnsEquiPred,
-        compensationRangePred, compensationResidualPred);
+    return Pair.of(compensationColumnsEquiPred, compensationPred);
   }
 
   /**
diff --git 
a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java 
b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
index c99fd40..56795cc 100644
--- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
+++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
@@ -377,7 +377,6 @@ public class MaterializationTest {
 
   /** As {@link #testFilterQueryOnFilterView()} but condition is stronger in
    * query. */
-  @Ignore
   @Test public void testFilterQueryOnFilterView2() {
     checkMaterialize(
         "select \"deptno\", \"empid\", \"name\" from \"emps\" where \"deptno\" 
= 10",
@@ -387,7 +386,6 @@ public class MaterializationTest {
 
   /** As {@link #testFilterQueryOnFilterView()} but condition is weaker in
    * view. */
-  @Ignore("not implemented")
   @Test public void testFilterQueryOnFilterView3() {
     checkMaterialize(
         "select \"deptno\", \"empid\", \"name\" from \"emps\" "
@@ -395,8 +393,9 @@ public class MaterializationTest {
         "select \"empid\" + 1 as x, \"name\" from \"emps\" where \"deptno\" = 
10",
         HR_FKUK_MODEL,
         CalciteAssert.checkResultContains(
-            "EnumerableCalcRel(expr#0..2=[{inputs}], expr#3=[1], "
-                + "expr#4=[+($t1, $t3)], X=[$t4], name=[$t2], condition=?)\n"
+            "EnumerableCalc(expr#0..2=[{inputs}], expr#3=[1], expr#4=[+($t1, 
$t3)], expr#5=[10], "
+                + "expr#6=[CAST($t0):INTEGER NOT NULL], expr#7=[=($t5, $t6)], 
$f0=[$t4], "
+                + "name=[$t2], $condition=[$t7])\n"
                 + "  EnumerableTableScan(table=[[hr, m0]])"));
   }
 
@@ -586,7 +585,6 @@ public class MaterializationTest {
   }
 
   /** Aggregation materialization with a project. */
-  @Ignore("work in progress")
   @Test public void testAggregateProject() {
     // Note that materialization does not start with the GROUP BY columns.
     // Not a smart way to design a materialization, but people may do it.
@@ -595,15 +593,17 @@ public class MaterializationTest {
         "select count(*) + 1 as c, \"deptno\" from \"emps\" group by 
\"deptno\"",
         HR_FKUK_MODEL,
         CalciteAssert.checkResultContains(
-            "xxx"));
+            "EnumerableCalc(expr#0..1=[{inputs}], expr#2=[1], expr#3=[+($t1, 
$t2)], $f0=[$t3], deptno=[$t0])\n"
+                + "  EnumerableAggregate(group=[{0}], agg#0=[$SUM0($1)])\n"
+                + "    EnumerableTableScan(table=[[hr, m0]])"));
   }
 
-  @Ignore
   @Test public void testSwapJoin() {
-    String q1 =
-        "select count(*) as c from \"foodmart\".\"sales_fact_1997\" as s join 
\"foodmart\".\"time_by_day\" as t on s.\"time_id\" = t.\"time_id\"";
-    String q2 =
-        "select count(*) as c from \"foodmart\".\"time_by_day\" as t join 
\"foodmart\".\"sales_fact_1997\" as s on t.\"time_id\" = s.\"time_id\"";
+    checkMaterialize(
+        "select count(*) as c from \"foodmart\".\"sales_fact_1997\" as s join 
\"foodmart\".\"time_by_day\" as t on s.\"time_id\" = t.\"time_id\"",
+        "select count(*) as c from \"foodmart\".\"time_by_day\" as t join 
\"foodmart\".\"sales_fact_1997\" as s on t.\"time_id\" = s.\"time_id\"",
+        JdbcTest.FOODMART_MODEL,
+        CalciteAssert.checkResultContains("EnumerableTableScan(table=[[mat, 
m0]])"));
   }
 
   @Ignore
@@ -1727,6 +1727,22 @@ public class MaterializationTest {
         HR_FKUK_MODEL);
   }
 
+  @Test public void testJoinAggregateMaterializationAggregateFuncs14() {
+    checkMaterialize(
+        "select \"empid\", \"emps\".\"name\", \"emps\".\"deptno\", 
\"depts\".\"name\", "
+            + "count(*) as c, sum(\"empid\") as s\n"
+            + "from \"emps\" join \"depts\" using (\"deptno\")\n"
+            + "where (\"depts\".\"name\" is not null and \"emps\".\"name\" = 
'a') or "
+            + "(\"depts\".\"name\" is not null and \"emps\".\"name\" = 'b')\n"
+            + "group by \"empid\", \"emps\".\"name\", \"depts\".\"name\", 
\"emps\".\"deptno\"",
+        "select \"depts\".\"deptno\", sum(\"empid\") as s\n"
+            + "from \"emps\" join \"depts\" using (\"deptno\")\n"
+            + "where \"depts\".\"name\" is not null and \"emps\".\"name\" = 
'a'\n"
+            + "group by \"depts\".\"deptno\"",
+        HR_FKUK_MODEL,
+        CONTAINS_M0);
+  }
+
   @Test public void testJoinMaterialization4() {
     checkMaterialize(
         "select \"empid\" \"deptno\" from \"emps\"\n"
@@ -1847,6 +1863,21 @@ public class MaterializationTest {
         HR_FKUK_MODEL);
   }
 
+  @Test public void testJoinMaterialization12() {
+    checkMaterialize(
+        "select \"empid\", \"emps\".\"name\", \"emps\".\"deptno\", 
\"depts\".\"name\"\n"
+            + "from \"emps\" join \"depts\" using (\"deptno\")\n"
+            + "where (\"depts\".\"name\" is not null and \"emps\".\"name\" = 
'a') or "
+            + "(\"depts\".\"name\" is not null and \"emps\".\"name\" = 'b') or 
"
+            + "(\"depts\".\"name\" is not null and \"emps\".\"name\" = 'c')",
+        "select \"depts\".\"deptno\", \"depts\".\"name\"\n"
+            + "from \"emps\" join \"depts\" using (\"deptno\")\n"
+            + "where (\"depts\".\"name\" is not null and \"emps\".\"name\" = 
'a') or "
+            + "(\"depts\".\"name\" is not null and \"emps\".\"name\" = 'b')",
+        HR_FKUK_MODEL,
+        CONTAINS_M0);
+  }
+
   @Test public void testJoinMaterializationUKFK1() {
     checkMaterialize(
         "select \"a\".\"empid\" \"deptno\" from\n"

Reply via email to