[CALCITE-1763] Recognize lossless casts in join/aggregate materialized view rewriting rule
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/9a691a7d Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/9a691a7d Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/9a691a7d Branch: refs/heads/master Commit: 9a691a7db88f96f930a4a4609f8aea6df601a909 Parents: a2bd49c Author: Jesus Camacho Rodriguez <[email protected]> Authored: Wed Apr 26 12:49:24 2017 +0100 Committer: Jesus Camacho Rodriguez <[email protected]> Committed: Wed Apr 26 20:05:03 2017 +0100 ---------------------------------------------------------------------- .../rel/rules/AbstractMaterializedViewRule.java | 52 ++++++++++++-------- .../calcite/test/MaterializationTest.java | 27 ++++++++++ 2 files changed, 58 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/9a691a7d/core/src/main/java/org/apache/calcite/rel/rules/AbstractMaterializedViewRule.java ---------------------------------------------------------------------- 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 071d9af..576c04c 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 @@ -422,7 +422,7 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule { RelBuilder builder = call.builder(); builder.push(materialization.tableRel); if (!compensationPred.isAlwaysTrue()) { - builder.filter(compensationPred); + builder.filter(simplify.simplify(compensationPred)); } RelNode result = unify(rexBuilder, builder, builder.build(), topProject, node, topViewProject, viewNode, tableMapping, @@ -1270,9 +1270,9 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule { Map<RexTableInputRef, Set<RexTableInputRef>> equivalenceClassesMap, RelMetadataQuery mq) { Map<String, Integer> exprsLineage = new HashMap<>(); + Map<String, Integer> exprsLineageLosslessCasts = new HashMap<>(); for (int i = 0; i < viewExprs.size(); i++) { - final RexNode e = viewExprs.get(i); - final Set<RexNode> s = mq.getExpressionLineage(viewNode, e); + final Set<RexNode> s = mq.getExpressionLineage(viewNode, viewExprs.get(i)); if (s == null) { // Next expression continue; @@ -1281,18 +1281,18 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule { // a single expression assert s.size() == 1; // Rewrite expr to be expressed on query tables - exprsLineage.put( - RexUtil.swapTableColumnReferences( - rexBuilder, - s.iterator().next(), - tableMapping.inverse(), - equivalenceClassesMap).toString(), - i); + final RexNode e = RexUtil.swapTableColumnReferences(rexBuilder, + s.iterator().next(), tableMapping.inverse(), equivalenceClassesMap); + exprsLineage.put(e.toString(), i); + if (RexUtil.isLosslessCast(e)) { + exprsLineageLosslessCasts.put(((RexCall) e).getOperands().get(0).toString(), i); + } } List<RexNode> rewrittenExprs = new ArrayList<>(exprs.size()); for (RexNode expr : exprs) { - RexNode rewrittenExpr = replaceWithOriginalReferences(rexBuilder, expr, exprsLineage); + RexNode rewrittenExpr = replaceWithOriginalReferences( + rexBuilder, viewExprs, expr, exprsLineage, exprsLineageLosslessCasts); if (RexUtil.containsTableInputRef(rewrittenExpr) != null) { // Some expressions were not present in view output return null; @@ -1367,28 +1367,38 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule { * point to. */ private static RexNode replaceWithOriginalReferences(final RexBuilder rexBuilder, - final RexNode expr, final Map<String, Integer> mapping) { + final List<RexNode> originalExprs, final RexNode expr, final Map<String, Integer> mapping, + final Map<String, Integer> mappingLosslessCasts) { // Currently we allow the following: // 1) compensation pred can be directly map to expression // 2) all references in compensation pred can be map to expressions + // We support bypassing lossless casts. RexShuttle visitor = new RexShuttle() { @Override public RexNode visitCall(RexCall call) { - Integer pos = mapping.get(call.toString()); - if (pos != null) { - // Found it - return rexBuilder.makeInputRef(call.getType(), pos); - } - return super.visitCall(call); + RexNode rw = replace(call); + return rw != null ? rw : super.visitCall(call); } @Override public RexNode visitTableInputRef(RexTableInputRef inputRef) { - Integer pos = mapping.get(inputRef.toString()); + RexNode rw = replace(inputRef); + return rw != null ? rw : super.visitTableInputRef(inputRef); + } + + private RexNode replace(RexNode e) { + Integer pos = mapping.get(e.toString()); if (pos != null) { // Found it - return rexBuilder.makeInputRef(inputRef.getType(), pos); + return rexBuilder.makeInputRef(e.getType(), pos); } - return super.visitTableInputRef(inputRef); + pos = mappingLosslessCasts.get(e.toString()); + if (pos != null) { + // Found it + return rexBuilder.makeCast( + e.getType(), rexBuilder.makeInputRef( + originalExprs.get(pos).getType(), pos)); + } + return null; } }; return visitor.apply(expr); http://git-wip-us.apache.org/repos/asf/calcite/blob/9a691a7d/core/src/test/java/org/apache/calcite/test/MaterializationTest.java ---------------------------------------------------------------------- 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 54ddaed..7e2c89c 100644 --- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java +++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java @@ -1355,6 +1355,33 @@ public class MaterializationTest { + " EnumerableTableScan(table=[[hr, m0]])")); } + @Test public void testJoinMaterialization5() { + checkMaterialize( + "select cast(\"empid\" as BIGINT) from \"emps\"\n" + + "join \"depts\" using (\"deptno\")", + "select \"empid\" \"deptno\" from \"emps\"\n" + + "join \"depts\" using (\"deptno\") where \"empid\" > 1", + HR_FKUK_MODEL, + CalciteAssert.checkResultContains( + "EnumerableCalc(expr#0=[{inputs}], expr#1=[CAST($t0):JavaType(int) NOT NULL], " + + "expr#2=[1], expr#3=[>($t1, $t2)], EXPR$0=[$t1], $condition=[$t3])\n" + + " EnumerableTableScan(table=[[hr, m0]])")); + } + + @Test public void testJoinMaterialization6() { + checkMaterialize( + "select cast(\"empid\" as BIGINT) from \"emps\"\n" + + "join \"depts\" using (\"deptno\")", + "select \"empid\" \"deptno\" from \"emps\"\n" + + "join \"depts\" using (\"deptno\") where \"empid\" = 1", + HR_FKUK_MODEL, + CalciteAssert.checkResultContains( + "EnumerableCalc(expr#0=[{inputs}], expr#1=[CAST($t0):JavaType(int) NOT NULL], " + + "expr#2=[CAST($t1):INTEGER NOT NULL], expr#3=[1], expr#4=[=($t2, $t3)], " + + "EXPR$0=[$t1], $condition=[$t4])\n" + + " EnumerableTableScan(table=[[hr, m0]])")); + } + @Test public void testJoinMaterializationUKFK1() { checkMaterialize( "select \"a\".\"empid\" \"deptno\" from\n"
