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/12/27 04:55:13 UTC
[3/3] incubator-calcite git commit: [CALCITE-545] When a projected
expression can only have one value, replace with that constant
[CALCITE-545] When a projected expression can only have one value, replace with that constant
Fix conversion of Character to char in generated Java code.
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/c9e58edf
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/c9e58edf
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/c9e58edf
Branch: refs/heads/master
Commit: c9e58edf0001af203ecd374d92fb82ed3d152e1d
Parents: 03c2583
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Dec 25 01:08:53 2014 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Dec 26 17:54:00 2014 -0800
----------------------------------------------------------------------
.../adapter/enumerable/RexToLixTranslator.java | 2 +-
.../calcite/plan/RelOptPredicateList.java | 16 ++
.../rel/rules/ReduceExpressionsRule.java | 154 ++++++++++++++-----
.../calcite/rel/rules/ValuesReduceRule.java | 4 +-
.../org/apache/calcite/rex/RexExecutorImpl.java | 1 +
.../org/apache/calcite/rex/RexInputRef.java | 10 ++
.../java/org/apache/calcite/rex/RexShuttle.java | 14 ++
.../java/org/apache/calcite/rex/RexUtil.java | 28 +++-
.../apache/calcite/test/RelOptRulesTest.java | 27 +++-
.../org/apache/calcite/test/RelOptRulesTest.xml | 108 ++++++++++++-
10 files changed, 309 insertions(+), 55 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9e58edf/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
index 5b140e5..92bd345 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
@@ -743,7 +743,7 @@ public class RexToLixTranslator {
return Expressions.convert_(
operand, toPrimitive.primitiveClass);
}
- if (fromNumber) {
+ if (fromNumber || fromBox == Primitive.CHAR) {
// Generate "x.shortValue()".
return Expressions.unbox(operand, toPrimitive);
} else {
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9e58edf/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java b/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java
index 2cfdf13..aad89b4 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java
@@ -17,8 +17,10 @@
package org.apache.calcite.plan;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
/**
* Predicates that are known to hold in the output of a particular relational
@@ -69,6 +71,20 @@ public class RelOptPredicateList {
return new RelOptPredicateList(pulledUpPredicatesList,
leftInferredPredicateList, rightInferredPredicatesList);
}
+
+ public RelOptPredicateList union(RelOptPredicateList list) {
+ return RelOptPredicateList.of(
+ Iterables.concat(pulledUpPredicates, list.pulledUpPredicates),
+ Iterables.concat(leftInferredPredicates, list.leftInferredPredicates),
+ Iterables.concat(rightInferredPredicates,
+ list.rightInferredPredicates));
+ }
+
+ public RelOptPredicateList shift(int offset) {
+ return RelOptPredicateList.of(RexUtil.shift(pulledUpPredicates, offset),
+ RexUtil.shift(leftInferredPredicates, offset),
+ RexUtil.shift(rightInferredPredicates, offset));
+ }
}
// End RelOptPredicateList.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9e58edf/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index f5a0ef7..862e629 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -17,6 +17,7 @@
package org.apache.calcite.rel.rules;
import org.apache.calcite.plan.RelOptPlanner;
+import org.apache.calcite.plan.RelOptPredicateList;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.plan.RelOptUtil;
@@ -26,6 +27,7 @@ import org.apache.calcite.rel.logical.LogicalCalc;
import org.apache.calcite.rel.logical.LogicalFilter;
import org.apache.calcite.rel.logical.LogicalProject;
import org.apache.calcite.rel.logical.LogicalValues;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rex.RexBuilder;
@@ -48,11 +50,16 @@ import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlRowOperator;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Stacks;
import org.apache.calcite.util.Util;
-import java.util.ArrayList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.regex.Pattern;
/**
@@ -87,12 +94,14 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
new ReduceExpressionsRule(LogicalFilter.class,
"ReduceExpressionsRule(Filter)") {
public void onMatch(RelOptRuleCall call) {
- LogicalFilter filter = call.rel(0);
- List<RexNode> expList = new ArrayList<RexNode>(1);
- expList.add(filter.getCondition());
+ final LogicalFilter filter = call.rel(0);
+ final List<RexNode> expList =
+ Lists.newArrayList(filter.getCondition());
RexNode newConditionExp;
boolean reduced;
- if (reduceExpressions(filter, expList)) {
+ final RelOptPredicateList predicates =
+ RelMetadataQuery.getPulledUpPredicates(filter.getInput());
+ if (reduceExpressions(filter, expList, predicates)) {
assert expList.size() == 1;
newConditionExp = expList.get(0);
reduced = true;
@@ -178,9 +187,11 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
"ReduceExpressionsRule(Project)") {
public void onMatch(RelOptRuleCall call) {
LogicalProject project = call.rel(0);
- List<RexNode> expList =
- new ArrayList<RexNode>(project.getProjects());
- if (reduceExpressions(project, expList)) {
+ final RelOptPredicateList predicates =
+ RelMetadataQuery.getPulledUpPredicates(project.getInput());
+ final List<RexNode> expList =
+ Lists.newArrayList(project.getProjects());
+ if (reduceExpressions(project, expList, predicates)) {
call.transformTo(
new LogicalProject(
project.getCluster(),
@@ -201,9 +212,15 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
"ReduceExpressionsRule(Join)") {
public void onMatch(RelOptRuleCall call) {
final Join join = call.rel(0);
- List<RexNode> expList = new ArrayList<RexNode>(1);
- expList.add(join.getCondition());
- if (reduceExpressions(join, expList)) {
+ final List<RexNode> expList = Lists.newArrayList(join.getCondition());
+ final int fieldCount = join.getLeft().getRowType().getFieldCount();
+ final RelOptPredicateList leftPredicates =
+ RelMetadataQuery.getPulledUpPredicates(join.getLeft());
+ final RelOptPredicateList rightPredicates =
+ RelMetadataQuery.getPulledUpPredicates(join.getRight());
+ final RelOptPredicateList predicates =
+ leftPredicates.union(rightPredicates.shift(fieldCount));
+ if (reduceExpressions(join, expList, predicates)) {
call.transformTo(
join.copy(
join.getTraitSet(),
@@ -228,8 +245,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
final List<RexNode> exprList = program.getExprList();
// Form a list of expressions with sub-expressions fully expanded.
- final List<RexNode> expandedExprList =
- new ArrayList<RexNode>(exprList.size());
+ final List<RexNode> expandedExprList = Lists.newArrayList();
final RexShuttle shuttle =
new RexShuttle() {
public RexNode visitLocalRef(RexLocalRef localRef) {
@@ -239,12 +255,13 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
for (RexNode expr : exprList) {
expandedExprList.add(expr.accept(shuttle));
}
- if (reduceExpressions(calc, expandedExprList)) {
+ final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
+ if (reduceExpressions(calc, expandedExprList, predicates)) {
final RexProgramBuilder builder =
new RexProgramBuilder(
calc.getInput().getRowType(),
calc.getCluster().getRexBuilder());
- List<RexLocalRef> list = new ArrayList<RexLocalRef>();
+ final List<RexLocalRef> list = Lists.newArrayList();
for (RexNode expr : expandedExprList) {
list.add(builder.registerInput(expr));
}
@@ -306,16 +323,20 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
*
* @param rel Relational expression
* @param expList List of expressions, modified in place
+ * @param predicates Constraints known to hold on input expressions
* @return whether reduction found something to change, and succeeded
*/
- static boolean reduceExpressions(RelNode rel, List<RexNode> expList) {
+ static boolean reduceExpressions(RelNode rel, List<RexNode> expList,
+ RelOptPredicateList predicates) {
RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
// Find reducible expressions.
- List<RexNode> constExps = new ArrayList<RexNode>();
- List<Boolean> addCasts = new ArrayList<Boolean>();
- List<RexNode> removableCasts = new ArrayList<RexNode>();
- findReducibleExps(rel.getCluster().getTypeFactory(), expList,
+ final List<RexNode> constExps = Lists.newArrayList();
+ List<Boolean> addCasts = Lists.newArrayList();
+ final List<RexNode> removableCasts = Lists.newArrayList();
+ final ImmutableMap<RexNode, RexLiteral> constants =
+ predicateConstants(predicates);
+ findReducibleExps(rel.getCluster().getTypeFactory(), expList, constants,
constExps, addCasts, removableCasts);
if (constExps.isEmpty() && removableCasts.isEmpty()) {
return false;
@@ -326,19 +347,17 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
// reducing that argument to a constant first will result in not being
// able to locate the original cast expression.
if (!removableCasts.isEmpty()) {
- List<RexNode> reducedExprs = new ArrayList<RexNode>();
- List<Boolean> noCasts = new ArrayList<Boolean>();
+ final List<RexNode> reducedExprs = Lists.newArrayList();
for (RexNode exp : removableCasts) {
RexCall call = (RexCall) exp;
reducedExprs.add(call.getOperands().get(0));
- noCasts.add(false);
}
RexReplacer replacer =
new RexReplacer(
rexBuilder,
removableCasts,
reducedExprs,
- noCasts);
+ Collections.nCopies(removableCasts.size(), false));
replacer.mutate(expList);
}
@@ -346,11 +365,26 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
return true;
}
+ final List<RexNode> constExps2 = Lists.newArrayList(constExps);
+ if (!constants.isEmpty()) {
+ //noinspection unchecked
+ final List<Map.Entry<RexNode, RexNode>> pairs =
+ (List<Map.Entry<RexNode, RexNode>>) (List)
+ Lists.newArrayList(constants.entrySet());
+ RexReplacer replacer =
+ new RexReplacer(
+ rexBuilder,
+ Pair.left(pairs),
+ Pair.right(pairs),
+ Collections.nCopies(pairs.size(), false));
+ replacer.mutate(constExps2);
+ }
+
// Compute the values they reduce to.
RelOptPlanner.Executor executor =
rel.getCluster().getPlanner().getExecutor();
- List<RexNode> reducedValues = new ArrayList<RexNode>();
- executor.reduce(rexBuilder, constExps, reducedValues);
+ final List<RexNode> reducedValues = Lists.newArrayList();
+ executor.reduce(rexBuilder, constExps2, reducedValues);
// For Project, we have to be sure to preserve the result
// types, so always cast regardless of the expression type.
@@ -360,9 +394,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
// like when the expression is a UDR argument, that need to be
// handled as special cases.
if (rel instanceof LogicalProject) {
- for (int i = 0; i < reducedValues.size(); i++) {
- addCasts.set(i, true);
- }
+ addCasts = Collections.nCopies(reducedValues.size(), true);
}
RexReplacer replacer =
@@ -382,6 +414,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
* @param typeFactory Type factory
* @param exps list of candidate expressions to be examined for
* reduction
+ * @param constants List of expressions known to be constant
* @param constExps returns the list of expressions that can be constant
* reduced
* @param addCasts indicator for each expression that can be constant
@@ -389,21 +422,35 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
* expression is potentially necessary
* @param removableCasts returns the list of cast expressions where the cast
*/
- private static void findReducibleExps(
- RelDataTypeFactory typeFactory,
- List<RexNode> exps,
- List<RexNode> constExps,
- List<Boolean> addCasts,
+ private static void findReducibleExps(RelDataTypeFactory typeFactory,
+ List<RexNode> exps, ImmutableMap<RexNode, RexLiteral> constants,
+ List<RexNode> constExps, List<Boolean> addCasts,
List<RexNode> removableCasts) {
ReducibleExprLocator gardener =
- new ReducibleExprLocator(typeFactory, constExps, addCasts,
- removableCasts);
+ new ReducibleExprLocator(typeFactory, constants, constExps,
+ addCasts, removableCasts);
for (RexNode exp : exps) {
gardener.analyze(exp);
}
assert constExps.size() == addCasts.size();
}
+ private static ImmutableMap<RexNode, RexLiteral> predicateConstants(
+ RelOptPredicateList predicates) {
+ final ImmutableMap.Builder<RexNode, RexLiteral> builder =
+ ImmutableMap.builder();
+ for (RexNode predicate : predicates.pulledUpPredicates) {
+ switch (predicate.getKind()) {
+ case EQUALS:
+ final List<RexNode> operands = ((RexCall) predicate).getOperands();
+ if (operands.get(1) instanceof RexLiteral) {
+ builder.put(operands.get(0), (RexLiteral) operands.get(1));
+ }
+ }
+ }
+ return builder.build();
+ }
+
//~ Inner Classes ----------------------------------------------------------
/**
@@ -427,10 +474,26 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
this.addCasts = addCasts;
}
- @Override public RexNode visitCall(final RexCall call) {
+ @Override public RexNode visitInputRef(RexInputRef inputRef) {
+ RexNode node = visit(inputRef);
+ if (node == null) {
+ return super.visitInputRef(inputRef);
+ }
+ return node;
+ }
+
+ @Override public RexNode visitCall(RexCall call) {
+ RexNode node = visit(call);
+ if (node == null) {
+ return super.visitCall(call);
+ }
+ return node;
+ }
+
+ private RexNode visit(final RexNode call) {
int i = reducibleExps.indexOf(call);
if (i == -1) {
- return super.visitCall(call);
+ return null;
}
RexNode replacement = reducedValues.get(i);
if (addCasts.get(i)
@@ -467,6 +530,8 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
private final List<Constancy> stack;
+ private final ImmutableMap<RexNode, RexLiteral> constants;
+
private final List<RexNode> constExprs;
private final List<Boolean> addCasts;
@@ -476,16 +541,17 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
private final List<SqlOperator> parentCallTypeStack;
ReducibleExprLocator(RelDataTypeFactory typeFactory,
- List<RexNode> constExprs, List<Boolean> addCasts,
- List<RexNode> removableCasts) {
+ ImmutableMap<RexNode, RexLiteral> constants, List<RexNode> constExprs,
+ List<Boolean> addCasts, List<RexNode> removableCasts) {
// go deep
super(true);
this.typeFactory = typeFactory;
+ this.constants = constants;
this.constExprs = constExprs;
this.addCasts = addCasts;
this.removableCasts = removableCasts;
- this.stack = new ArrayList<Constancy>();
- this.parentCallTypeStack = new ArrayList<SqlOperator>();
+ this.stack = Lists.newArrayList();
+ this.parentCallTypeStack = Lists.newArrayList();
}
public void analyze(RexNode exp) {
@@ -541,6 +607,10 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
}
public Void visitInputRef(RexInputRef inputRef) {
+ if (constants.containsKey(inputRef)) {
+ stack.add(Constancy.REDUCIBLE_CONSTANT);
+ return null;
+ }
return pushVariable();
}
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9e58edf/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
index 0f77897..18e0f92 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
@@ -16,6 +16,7 @@
*/
package org.apache.calcite.rel.rules;
+import org.apache.calcite.plan.RelOptPredicateList;
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.plan.RelOptRuleOperand;
@@ -172,7 +173,8 @@ public abstract class ValuesReduceRule extends RelOptRule {
assert reducibleExps.size() == (values.getTuples().size() * fieldsPerRow);
// Compute the values they reduce to.
- ReduceExpressionsRule.reduceExpressions(values, reducibleExps);
+ final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
+ ReduceExpressionsRule.reduceExpressions(values, reducibleExps, predicates);
int changeCount = 0;
final ImmutableList.Builder<ImmutableList<RexLiteral>> tuplesBuilder =
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9e58edf/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java b/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
index 9825367..51e0beb 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java
@@ -57,6 +57,7 @@ public class RexExecutorImpl implements RelOptPlanner.Executor {
final RelDataType emptyRowType = typeFactory.builder().build();
return compile(rexBuilder, constExps, getter, emptyRowType);
}
+
private String compile(RexBuilder rexBuilder, List<RexNode> constExps,
RexToLixTranslator.InputGetter getter, RelDataType rowType) {
final RexProgramBuilder programBuilder =
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9e58edf/core/src/main/java/org/apache/calcite/rex/RexInputRef.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexInputRef.java b/core/src/main/java/org/apache/calcite/rex/RexInputRef.java
index edc38da..0c475db 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexInputRef.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexInputRef.java
@@ -68,6 +68,16 @@ public class RexInputRef extends RexSlot {
//~ Methods ----------------------------------------------------------------
+ @Override public boolean equals(Object obj) {
+ return this == obj
+ || obj instanceof RexInputRef
+ && index == ((RexInputRef) obj).index;
+ }
+
+ @Override public int hashCode() {
+ return index;
+ }
+
/**
* Creates a reference to a given field in a row type.
*/
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9e58edf/core/src/main/java/org/apache/calcite/rex/RexShuttle.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexShuttle.java b/core/src/main/java/org/apache/calcite/rex/RexShuttle.java
index 9c6e46d..e3c0302 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexShuttle.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexShuttle.java
@@ -16,10 +16,13 @@
*/
package org.apache.calcite.rex;
+import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.List;
+import javax.annotation.Nullable;
/**
* Passes over a row-expression, calling a handler method for each node,
@@ -244,6 +247,17 @@ public class RexShuttle implements RexVisitor<RexNode> {
}
/**
+ * Applies this shuttle to each expression in an iterable.
+ */
+ public final Iterable<RexNode> apply(Iterable<? extends RexNode> iterable) {
+ return Iterables.transform(iterable, new Function<RexNode, RexNode>() {
+ public RexNode apply(@Nullable RexNode t) {
+ return t == null ? null : t.accept(RexShuttle.this);
+ }
+ });
+ }
+
+ /**
* Applies this shuttle to an expression, or returns null if the expression
* is null.
*/
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9e58edf/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index 286f8fb..dd06cb2 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -1007,12 +1007,14 @@ public class RexUtil {
* Shifts every {@link RexInputRef} in an expression by {@code offset}.
*/
public static RexNode shift(RexNode node, final int offset) {
- return node.accept(
- new RexShuttle() {
- @Override public RexNode visitInputRef(RexInputRef input) {
- return new RexInputRef(input.getIndex() + offset, input.getType());
- }
- });
+ return node.accept(new RexShiftShuttle(offset));
+ }
+
+ /**
+ * Shifts every {@link RexInputRef} in an expression by {@code offset}.
+ */
+ public static Iterable<RexNode> shift(Iterable<RexNode> nodes, int offset) {
+ return new RexShiftShuttle(offset).apply(nodes);
}
/**
@@ -1354,6 +1356,20 @@ public class RexUtil {
return composeDisjunction(rexBuilder, nodes, false);
}
}
+
+ /** Shuttle that adds {@code offset} to each {@link RexInputRef} in an
+ * expression. */
+ private static class RexShiftShuttle extends RexShuttle {
+ private final int offset;
+
+ public RexShiftShuttle(int offset) {
+ this.offset = offset;
+ }
+
+ @Override public RexNode visitInputRef(RexInputRef input) {
+ return new RexInputRef(input.getIndex() + offset, input.getType());
+ }
+ }
}
// End RexUtil.java
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9e58edf/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index cf78de9..a9c6c49 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.calcite.test;
+import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.plan.hep.HepMatchOrder;
import org.apache.calcite.plan.hep.HepPlanner;
@@ -76,6 +77,7 @@ import com.google.common.collect.Lists;
import org.junit.Ignore;
import org.junit.Test;
+import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertTrue;
@@ -1123,7 +1125,7 @@ public class RelOptRulesTest extends RelOptTestBase {
+ "group by rollup(x, y)");
}
- public void transitiveInference() throws Exception {
+ public void transitiveInference(RelOptRule... extraRules) throws Exception {
final DiffRepository diffRepos = getDiffRepos();
String sql = diffRepos.expand(null, "${sql}");
@@ -1161,6 +1163,7 @@ public class RelOptRulesTest extends RelOptTestBase {
.addRuleInstance(FilterProjectTransposeRule.INSTANCE)
.addRuleInstance(FilterSetOpTransposeRule.INSTANCE)
.addRuleInstance(JoinPushTransitivePredicatesRule.INSTANCE)
+ .addRuleCollection(Arrays.asList(extraRules))
.build();
HepPlanner planner2 = new HepPlanner(program2);
planner.registerMetadataProviders(list);
@@ -1207,12 +1210,12 @@ public class RelOptRulesTest extends RelOptTestBase {
transitiveInference();
}
- @Test public void testTransitiveInferencePreventProjectPullup()
+ @Test public void testTransitiveInferencePreventProjectPullUp()
throws Exception {
transitiveInference();
}
- @Test public void testTransitiveInferencePullupThruAlias() throws Exception {
+ @Test public void testTransitiveInferencePullUpThruAlias() throws Exception {
transitiveInference();
}
@@ -1249,6 +1252,24 @@ public class RelOptRulesTest extends RelOptTestBase {
transitiveInference();
}
+ @Test public void testPullConstantIntoProject() throws Exception {
+ transitiveInference(ReduceExpressionsRule.PROJECT_INSTANCE);
+ }
+
+ @Test public void testPullConstantIntoFilter() throws Exception {
+ transitiveInference(ReduceExpressionsRule.FILTER_INSTANCE);
+ }
+
+ @Test public void testPullConstantIntoJoin() throws Exception {
+ transitiveInference(ReduceExpressionsRule.JOIN_INSTANCE);
+ }
+
+ @Test public void testPullConstantIntoJoin2() throws Exception {
+ transitiveInference(ReduceExpressionsRule.JOIN_INSTANCE,
+ ReduceExpressionsRule.PROJECT_INSTANCE,
+ FilterProjectTransposeRule.INSTANCE);
+ }
+
@Test public void testPushFilterWithRank() throws Exception {
HepProgram program = new HepProgramBuilder().addRuleInstance(
FilterProjectTransposeRule.INSTANCE).build();
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c9e58edf/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 4ddefe1..23322b5 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -2379,7 +2379,7 @@ LogicalProject(EXPR$0=[1])
]]>
</Resource>
</TestCase>
- <TestCase name="testTransitiveInferencePreventProjectPullup">
+ <TestCase name="testTransitiveInferencePreventProjectPullUp">
<Resource name="sql">
<![CDATA[select 1 from (select comm as deptno from sales.emp where deptno > 7) d inner join sales.emp e on d.deptno = e.deptno ]]>
</Resource>
@@ -2404,7 +2404,7 @@ LogicalProject(EXPR$0=[1])
]]>
</Resource>
</TestCase>
- <TestCase name="testTransitiveInferencePullupThruAlias">
+ <TestCase name="testTransitiveInferencePullUpThruAlias">
<Resource name="sql">
<![CDATA[select 1 from (select comm as deptno from sales.emp where comm > 7) d inner join sales.emp e on d.deptno = e.deptno ]]>
</Resource>
@@ -2639,6 +2639,110 @@ LogicalProject(EXPR$0=[1])
]]>
</Resource>
</TestCase>
+ <TestCase name="testPullConstantIntoProject">
+ <Resource name="sql">
+ <![CDATA[select deptno, deptno + 1, empno + deptno from sales.emp where deptno = 10]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(DEPTNO=[$7], EXPR$1=[+($7, 1)], EXPR$2=[+($0, $7)])
+ LogicalFilter(condition=[=($7, 10)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(DEPTNO=[10], EXPR$1=[11], EXPR$2=[+($0, 10)])
+ LogicalFilter(condition=[=($7, 10)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPullConstantIntoFilter">
+ <Resource name="sql">
+ <![CDATA[select * from (select * from sales.emp where deptno = 10) where deptno + 5 > empno]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ LogicalFilter(condition=[>(+($7, 5), $0)])
+ LogicalFilter(condition=[=($7, 10)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ LogicalFilter(condition=[>(15, $0)])
+ LogicalFilter(condition=[=($7, 10)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPullConstantIntoJoin">
+ <Resource name="sql">
+ <![CDATA[select *
+ from (select * from sales.emp where empno = 10) as e
+ left join sales.dept as d on e.empno = d.deptno]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
+ LogicalJoin(condition=[=($0, $9)], joinType=[left])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ LogicalFilter(condition=[=($0, 10)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
+ LogicalJoin(condition=[true], joinType=[left])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ LogicalFilter(condition=[=($0, 10)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalFilter(condition=[=($0, 10)])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testPullConstantIntoJoin2">
+ <Resource name="sql">
+ <![CDATA[select *
+ from (select * from sales.emp where empno = 10) as e
+ join sales.dept as d on e.empno = d.deptno and e.deptno + e.empno = d.deptno + 5]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$10], NAME=[$11])
+ LogicalJoin(condition=[AND(=($0, $10), =($9, $12))], joinType=[inner])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f9=[+($7, $0)])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ LogicalFilter(condition=[=($0, 10)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(DEPTNO=[$0], NAME=[$1], $f2=[+($0, 5)])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
+ LogicalProject(EMPNO=[10], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$10], NAME=[$11])
+ LogicalJoin(condition=[AND(=(10, $10), =($9, $12))], joinType=[inner])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f9=[+($7, $0)])
+ LogicalProject(EMPNO=[10], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ LogicalFilter(condition=[=($0, 10)])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(DEPTNO=[10], NAME=[$1], $f2=[15])
+ LogicalFilter(condition=[=($0, 10)])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testStrengthenJoinType">
<Resource name="sql">
<![CDATA[select * from dept where exists (