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 2015/09/28 22:19:38 UTC
[7/7] incubator-calcite git commit: Improve [CALCITE-895] fix,
visiting the whole expression via a shuttle
Improve [CALCITE-895] fix, visiting the whole expression via a shuttle
Project: http://git-wip-us.apache.org/repos/asf/incubator-calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/d697ca16
Tree: http://git-wip-us.apache.org/repos/asf/incubator-calcite/tree/d697ca16
Diff: http://git-wip-us.apache.org/repos/asf/incubator-calcite/diff/d697ca16
Branch: refs/heads/master
Commit: d697ca16456424f04ad81e550ee19f677c7520b2
Parents: 2fa63dd
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Sep 22 13:05:00 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Sep 28 12:10:22 2015 -0700
----------------------------------------------------------------------
.../rel/rules/ReduceExpressionsRule.java | 125 ++++++++-----------
1 file changed, 50 insertions(+), 75 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/d697ca16/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 61c64a8..8a56928 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
@@ -335,15 +335,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
// Replace predicates on CASE to CASE on predicates.
- for (int i = 0; i < expList.size(); i++) {
- RexNode exp = expList.get(i);
- if (exp instanceof RexCall) {
- RexNode exp2 = pushPredicateIntoCase((RexCall) exp);
- if (exp2 != exp) {
- expList.set(i, exp2);
- }
- }
- }
+ new CaseShuttle().mutate(expList);
// Find reducible expressions.
final List<RexNode> constExps = Lists.newArrayList();
@@ -479,77 +471,47 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
return ImmutableMap.copyOf(builder);
}
- /** Return if a given operator can be pushed into Case */
- private static boolean isPushableIntoCase(RexNode node) {
- if (!(node instanceof RexCall)) {
- return false;
- }
-
- final RexCall call = (RexCall) node;
- return call.getType().getSqlTypeName() == SqlTypeName.BOOLEAN
- && (SqlKind.COMPARISON.contains(call.getKind()) || call.getOperands().size() == 1);
- }
-
+ /** Pushes predicates into a CASE.
+ *
+ * <p>We have a loose definition of 'predicate': any boolean expression will
+ * do, except CASE. For example '(CASE ...) = 5' or '(CASE ...) IS NULL'.
+ */
private static RexCall pushPredicateIntoCase(RexCall call) {
if (call.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) {
return call;
}
- final RexShuttle rexShuttle = new RexShuttle() {
- @Override
- public RexNode visitCall(RexCall call) {
- final List<RexNode> newOperands = new ArrayList<>();
- for (RexNode operand : call.getOperands()) {
- newOperands.add(operand.accept(this));
- }
-
- call = call.clone(call.getType(), newOperands);
- if (!isPushableIntoCase(call)) {
- return call;
- }
-
- final List<RexNode> operands = call.getOperands();
- int caseOrdinal = -1;
- for (int i = 0; i < operands.size(); i++) {
- RexNode operand = operands.get(i);
- switch (operand.getKind()) {
- case CASE:
- caseOrdinal = i;
- }
- }
- if (caseOrdinal < 0) {
- return call;
- }
-
- // Convert
- // f(CASE WHEN p1 THEN v1 ... END, arg)
- // to
- // CASE WHEN p1 THEN f(v1, arg) ... END
- final RexCall case_ = (RexCall) operands.get(caseOrdinal);
- final List<RexNode> nodes = new ArrayList<>();
- for (int i = 0; i < case_.getOperands().size(); i++) {
- RexNode node = case_.getOperands().get(i);
- if (!RexUtil.isCasePredicate(case_, i)) {
- node = substitute(call, caseOrdinal, node);
-
- // For nested Case-When, the function should be pushed further deeper
- // For example,
- // Convert
- // f(CASE WHEN p1 THEN (CASE WHEN p2 THEN v2 ... END) ... END, arg)
- // to
- // CASE WHEN p1 THEN f((CASE WHEN p2 THEN v2 ... END), arg) ... END
- // further to
- // CASE WHEN p1 THEN (CASE WHEN p2 THEN f(v2, arg) ... END) ... END
- if (isPushableIntoCase(node)) {
- node = node.accept(this);
- }
- }
- nodes.add(node);
- }
- return case_.clone(call.getType(), nodes);
+ switch (call.getKind()) {
+ case CASE:
+ case AND:
+ case OR:
+ return call; // don't push CASE into CASE!
+ }
+ int caseOrdinal = -1;
+ final List<RexNode> operands = call.getOperands();
+ for (int i = 0; i < operands.size(); i++) {
+ RexNode operand = operands.get(i);
+ switch (operand.getKind()) {
+ case CASE:
+ caseOrdinal = i;
}
- };
-
- return (RexCall) call.accept(rexShuttle);
+ }
+ if (caseOrdinal < 0) {
+ return call;
+ }
+ // Convert
+ // f(CASE WHEN p1 THEN v1 ... END, arg)
+ // to
+ // CASE WHEN p1 THEN f(v1, arg) ... END
+ final RexCall case_ = (RexCall) operands.get(caseOrdinal);
+ final List<RexNode> nodes = new ArrayList<>();
+ for (int i = 0; i < case_.getOperands().size(); i++) {
+ RexNode node = case_.getOperands().get(i);
+ if (!RexUtil.isCasePredicate(case_, i)) {
+ node = substitute(call, caseOrdinal, node);
+ }
+ nodes.add(node);
+ }
+ return case_.clone(call.getType(), nodes);
}
/** Converts op(arg0, ..., argOrdinal, ..., argN) to op(arg0,..., node, ..., argN). */
@@ -860,6 +822,19 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
}
}
+ /** Shuttle that pushes predicates into a CASE. */
+ private static class CaseShuttle extends RexShuttle {
+ @Override public RexNode visitCall(RexCall call) {
+ for (;;) {
+ call = (RexCall) super.visitCall(call);
+ final RexCall old = call;
+ call = pushPredicateIntoCase(call);
+ if (call == old) {
+ return call;
+ }
+ }
+ }
+ }
}
// End ReduceExpressionsRule.java