http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/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 2352809..f174f41 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java +++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java @@ -16,10 +16,8 @@ */ package org.apache.calcite.rex; -import org.apache.calcite.linq4j.Ord; import org.apache.calcite.linq4j.function.Predicate1; import org.apache.calcite.plan.RelOptUtil; -import org.apache.calcite.plan.Strong; import org.apache.calcite.rel.RelCollation; import org.apache.calcite.rel.RelCollations; import org.apache.calcite.rel.RelFieldCollation; @@ -48,26 +46,23 @@ import org.apache.calcite.util.mapping.Mappings; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; -import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import javax.annotation.Nonnull; /** * Utility methods concerning row-expressions. @@ -1038,6 +1033,16 @@ public class RexUtil { * Removes expressions that always evaluate to FALSE. * Flattens expressions that are ORs. */ + @Nonnull public static RexNode composeDisjunction(RexBuilder rexBuilder, + Iterable<? extends RexNode> nodes) { + final RexNode e = composeDisjunction(rexBuilder, nodes, false); + return Preconditions.checkNotNull(e); + } + + /** + * Converts a collection of expressions into an OR, + * optionally returning null if the list is empty. + */ public static RexNode composeDisjunction(RexBuilder rexBuilder, Iterable<? extends RexNode> nodes, boolean nullOnEmpty) { ImmutableList<RexNode> list = flattenOr(nodes); @@ -1565,39 +1570,33 @@ public class RexUtil { * nullability. * * <p>This is useful if you are simplifying expressions in a - * {@link Project}. */ + * {@link Project}. + * + * @deprecated Use {@link RexSimplify#simplifyPreservingType(RexNode)}, + * which allows you to specify an {@link RexExecutor}. */ + @Deprecated // to be removed before 2.0 public static RexNode simplifyPreservingType(RexBuilder rexBuilder, - RexNode e, RexExecutor executor) { - final RexNode e2 = simplify(rexBuilder, e, false, executor); - if (e2.getType() == e.getType()) { - return e2; - } - final RexNode e3 = rexBuilder.makeCast(e.getType(), e2, true); - if (e3.equals(e)) { - return e; - } - return e3; + RexNode e) { + return new RexSimplify(rexBuilder, false, EXECUTOR) + .simplifyPreservingType(e); } /** * Simplifies a boolean expression, leaving UNKNOWN values as UNKNOWN, and * using the default executor. + * + * @deprecated Use {@link RexSimplify#simplify(RexNode)}, + * which allows you to specify an {@link RexExecutor}. */ + @Deprecated // to be removed before 2.0 public static RexNode simplify(RexBuilder rexBuilder, RexNode e) { - return simplify(rexBuilder, e, false, EXECUTOR); + return new RexSimplify(rexBuilder, false, EXECUTOR) + .simplify(e); } /** * Simplifies a boolean expression, * using the default executor. - */ - public static RexNode simplify(RexBuilder rexBuilder, RexNode e, - boolean unknownAsFalse) { - return simplify(rexBuilder, e, unknownAsFalse, EXECUTOR); - } - - /** - * Simplifies a boolean expression. * * <p>In particular:</p> * <ul> @@ -1615,180 +1614,35 @@ public class RexUtil { * @param rexBuilder Rex builder * @param e Expression to simplify * @param unknownAsFalse Whether to convert UNKNOWN values to FALSE - * @param executor Executor for constant reduction, not null + * + * @deprecated Use {@link RexSimplify#simplify(RexNode)}, + * which allows you to specify an {@link RexExecutor}. */ + @Deprecated // to be removed before 2.0 public static RexNode simplify(RexBuilder rexBuilder, RexNode e, - boolean unknownAsFalse, RexExecutor executor) { - Preconditions.checkNotNull(executor); - switch (e.getKind()) { - case AND: - return simplifyAnd(rexBuilder, (RexCall) e, unknownAsFalse); - case OR: - return simplifyOr(rexBuilder, (RexCall) e); - case NOT: - return simplifyNot(rexBuilder, (RexCall) e); - case CASE: - return simplifyCase(rexBuilder, (RexCall) e, unknownAsFalse); - case CAST: - return simplifyCast(rexBuilder, (RexCall) e, executor); - case IS_NULL: - case IS_NOT_NULL: - case IS_TRUE: - case IS_NOT_TRUE: - case IS_FALSE: - case IS_NOT_FALSE: - assert e instanceof RexCall; - return simplifyIs(rexBuilder, (RexCall) e); - case EQUALS: - case GREATER_THAN: - case GREATER_THAN_OR_EQUAL: - case LESS_THAN: - case LESS_THAN_OR_EQUAL: - case NOT_EQUALS: - return simplifyComparison(rexBuilder, (RexCall) e, unknownAsFalse); - default: - return e; - } - } - - // e must be a comparison (=, >, >=, <, <=, !=) - private static RexNode simplifyComparison(RexBuilder rexBuilder, RexCall e, boolean unknownAsFalse) { - final List<RexNode> operands = new ArrayList<>(e.operands); - simplifyList(rexBuilder, operands); - - // Simplify "x <op> x" - final RexNode o0 = operands.get(0); - final RexNode o1 = operands.get(1); - if (RexUtil.eq(o0, o1) - && (unknownAsFalse - || (!o0.getType().isNullable() - && !o1.getType().isNullable()))) { - switch (e.getKind()) { - case EQUALS: - case GREATER_THAN_OR_EQUAL: - case LESS_THAN_OR_EQUAL: - // "x = x" simplifies to "x is not null" (similarly <= and >=) - return simplify(rexBuilder, - rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, o0)); - default: - // "x != x" simplifies to "false" (similarly < and >) - return rexBuilder.makeLiteral(false); - } - } - - // Simplify "<literal1> <op> <literal2>" - // For example, "1 = 2" becomes FALSE; - // "1 != 1" becomes FALSE; - // "1 != NULL" becomes UNKNOWN (or FALSE if unknownAsFalse); - // "1 != '1'" is unchanged because the types are not the same. - if (o0.isA(SqlKind.LITERAL) - && o1.isA(SqlKind.LITERAL) - && o0.getType().equals(o1.getType())) { - final Comparable v0 = ((RexLiteral) o0).getValue(); - final Comparable v1 = ((RexLiteral) o1).getValue(); - if (v0 == null || v1 == null) { - return unknownAsFalse - ? rexBuilder.makeLiteral(false) - : rexBuilder.makeNullLiteral(e.getType()); - } - @SuppressWarnings("unchecked") - final int comparisonResult = v0.compareTo(v1); - switch (e.getKind()) { - case EQUALS: - return rexBuilder.makeLiteral(comparisonResult == 0); - case GREATER_THAN: - return rexBuilder.makeLiteral(comparisonResult > 0); - case GREATER_THAN_OR_EQUAL: - return rexBuilder.makeLiteral(comparisonResult >= 0); - case LESS_THAN: - return rexBuilder.makeLiteral(comparisonResult < 0); - case LESS_THAN_OR_EQUAL: - return rexBuilder.makeLiteral(comparisonResult <= 0); - case NOT_EQUALS: - return rexBuilder.makeLiteral(comparisonResult != 0); - default: - throw new AssertionError(); - } - } - - // If none of the arguments were simplified, return the call unchanged. - if (operands.equals(e.operands)) { - return e; - } - return rexBuilder.makeCall(e.op, operands); + return new RexSimplify(rexBuilder, unknownAsFalse, EXECUTOR) + .simplify(e); } /** * Simplifies a conjunction of boolean expressions. + * + * @deprecated Use {@link RexSimplify#simplifyAnds(Iterable)}, + * which allows you to specify an {@link RexExecutor}. */ + @Deprecated // to be removed before 2.0 public static RexNode simplifyAnds(RexBuilder rexBuilder, Iterable<? extends RexNode> nodes) { - return simplifyAnds(rexBuilder, nodes, false); + return new RexSimplify(rexBuilder, false, EXECUTOR) + .simplifyAnds(nodes); } + @Deprecated // to be removed before 2.0 public static RexNode simplifyAnds(RexBuilder rexBuilder, Iterable<? extends RexNode> nodes, boolean unknownAsFalse) { - final List<RexNode> terms = new ArrayList<>(); - final List<RexNode> notTerms = new ArrayList<>(); - for (RexNode e : nodes) { - RelOptUtil.decomposeConjunction(e, terms, notTerms); - } - simplifyList(rexBuilder, terms); - simplifyList(rexBuilder, notTerms); - if (unknownAsFalse) { - return simplifyAnd2ForUnknownAsFalse(rexBuilder, terms, notTerms); - } - return simplifyAnd2(rexBuilder, terms, notTerms); - } - - private static void simplifyList(RexBuilder rexBuilder, List<RexNode> terms) { - for (int i = 0; i < terms.size(); i++) { - terms.set(i, simplify(rexBuilder, terms.get(i))); - } - } - - private static RexNode simplifyNot(RexBuilder rexBuilder, RexCall call) { - final RexNode a = call.getOperands().get(0); - switch (a.getKind()) { - case NOT: - // NOT NOT x ==> x - return simplify(rexBuilder, ((RexCall) a).getOperands().get(0)); - } - final SqlKind negateKind = a.getKind().negate(); - if (a.getKind() != negateKind) { - return simplify(rexBuilder, - rexBuilder.makeCall(op(negateKind), - ImmutableList.of(((RexCall) a).getOperands().get(0)))); - } - final SqlKind negateKind2 = a.getKind().negateNullSafe(); - if (a.getKind() != negateKind2) { - return simplify(rexBuilder, - rexBuilder.makeCall(op(negateKind2), ((RexCall) a).getOperands())); - } - if (a.getKind() == SqlKind.AND) { - // NOT distributivity for AND - final List<RexNode> newOperands = new ArrayList<>(); - for (RexNode operand : ((RexCall) a).getOperands()) { - newOperands.add( - simplify(rexBuilder, - rexBuilder.makeCall(SqlStdOperatorTable.NOT, operand))); - } - return simplify(rexBuilder, - rexBuilder.makeCall(SqlStdOperatorTable.OR, newOperands)); - } - if (a.getKind() == SqlKind.OR) { - // NOT distributivity for OR - final List<RexNode> newOperands = new ArrayList<>(); - for (RexNode operand : ((RexCall) a).getOperands()) { - newOperands.add( - simplify(rexBuilder, - rexBuilder.makeCall(SqlStdOperatorTable.NOT, operand))); - } - return simplify(rexBuilder, - rexBuilder.makeCall(SqlStdOperatorTable.AND, newOperands)); - } - return call; + return new RexSimplify(rexBuilder, unknownAsFalse, EXECUTOR) + .simplifyAnds(nodes); } /** Negates a logical expression by adding or removing a NOT. */ @@ -1802,103 +1656,7 @@ public class RexUtil { } } - private static RexNode simplifyIs(RexBuilder rexBuilder, RexCall call) { - final SqlKind kind = call.getKind(); - final RexNode a = call.getOperands().get(0); - final RexNode simplified = simplifyIs2(rexBuilder, kind, a); - if (simplified != null) { - return simplified; - } - return call; - } - - private static RexNode simplifyIs2(RexBuilder rexBuilder, SqlKind kind, - RexNode a) { - switch (kind) { - case IS_NULL: - // x IS NULL ==> FALSE (if x is not nullable) - if (!a.getType().isNullable()) { - return rexBuilder.makeLiteral(false); - } - break; - case IS_NOT_NULL: - // x IS NOT NULL ==> TRUE (if x is not nullable) - RexNode simplified = simplifyIsNotNull(rexBuilder, a); - if (simplified != null) { - return simplified; - } - break; - case IS_TRUE: - case IS_NOT_FALSE: - // x IS TRUE ==> x (if x is not nullable) - // x IS NOT FALSE ==> x (if x is not nullable) - if (!a.getType().isNullable()) { - return simplify(rexBuilder, a); - } - break; - case IS_FALSE: - case IS_NOT_TRUE: - // x IS NOT TRUE ==> NOT x (if x is not nullable) - // x IS FALSE ==> NOT x (if x is not nullable) - if (!a.getType().isNullable()) { - return simplify(rexBuilder, - rexBuilder.makeCall(SqlStdOperatorTable.NOT, a)); - } - break; - } - switch (a.getKind()) { - case NOT: - // (NOT x) IS TRUE ==> x IS FALSE - // Similarly for IS NOT TRUE, IS FALSE, etc. - // - // Note that - // (NOT x) IS TRUE !=> x IS FALSE - // because of null values. - return simplify(rexBuilder, - rexBuilder.makeCall(op(kind.negate()), - ((RexCall) a).getOperands().get(0))); - } - RexNode a2 = simplify(rexBuilder, a); - if (a != a2) { - return rexBuilder.makeCall(op(kind), ImmutableList.of(a2)); - } - return null; // cannot be simplified - } - - private static RexNode simplifyIsNotNull(RexBuilder rexBuilder, RexNode a) { - if (!a.getType().isNullable()) { - return rexBuilder.makeLiteral(true); - } - switch (Strong.policy(a.getKind())) { - case ANY: - final List<RexNode> operands = new ArrayList<>(); - for (RexNode operand : ((RexCall) a).getOperands()) { - final RexNode simplified = simplifyIsNotNull(rexBuilder, operand); - if (simplified == null) { - operands.add( - rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, operand)); - } else if (simplified.isAlwaysFalse()) { - return rexBuilder.makeLiteral(false); - } else { - operands.add(simplified); - } - } - return composeConjunction(rexBuilder, operands, false); - case CUSTOM: - switch (a.getKind()) { - case LITERAL: - return rexBuilder.makeLiteral(((RexLiteral) a).getValue() != null); - default: - throw new AssertionError("every CUSTOM policy needs a handler, " - + a.getKind()); - } - case AS_IS: - default: - return null; - } - } - - private static SqlOperator op(SqlKind kind) { + static SqlOperator op(SqlKind kind) { switch (kind) { case IS_FALSE: return SqlStdOperatorTable.IS_FALSE; @@ -1931,371 +1689,25 @@ public class RexUtil { } } - private static RexNode simplifyCase(RexBuilder rexBuilder, RexCall call, - boolean unknownAsFalse) { - final List<RexNode> operands = call.getOperands(); - final List<RexNode> newOperands = new ArrayList<>(); - final Set<String> values = new HashSet<>(); - for (int i = 0; i < operands.size(); i++) { - RexNode operand = operands.get(i); - if (isCasePredicate(call, i)) { - if (operand.isAlwaysTrue()) { - // Predicate is always TRUE. Make value the ELSE and quit. - newOperands.add(operands.get(++i)); - if (unknownAsFalse && isNull(operands.get(i))) { - values.add(rexBuilder.makeLiteral(false).toString()); - } else { - values.add(operands.get(i).toString()); - } - break; - } else if (operand.isAlwaysFalse() || isNull(operand)) { - // Predicate is always FALSE or NULL. Skip predicate and value. - ++i; - continue; - } - } else { - if (unknownAsFalse && isNull(operand)) { - values.add(rexBuilder.makeLiteral(false).toString()); - } else { - values.add(operand.toString()); - } - } - newOperands.add(operand); - } - assert newOperands.size() % 2 == 1; - if (newOperands.size() == 1 || values.size() == 1) { - final RexNode last = Util.last(newOperands); - if (!call.getType().equals(last.getType())) { - return rexBuilder.makeAbstractCast(call.getType(), last); - } - return last; - } - trueFalse: - if (call.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) { - // Optimize CASE where every branch returns constant true or constant - // false. - final List<Pair<RexNode, RexNode>> pairs = - casePairs(rexBuilder, newOperands); - // 1) Possible simplification if unknown is treated as false: - // CASE - // WHEN p1 THEN TRUE - // WHEN p2 THEN TRUE - // ELSE FALSE - // END - // can be rewritten to: (p1 or p2) - if (unknownAsFalse) { - final List<RexNode> terms = new ArrayList<>(); - int pos = 0; - for (; pos < pairs.size(); pos++) { - // True block - Pair<RexNode, RexNode> pair = pairs.get(pos); - if (!pair.getValue().isAlwaysTrue()) { - break; - } - terms.add(pair.getKey()); - } - for (; pos < pairs.size(); pos++) { - // False block - Pair<RexNode, RexNode> pair = pairs.get(pos); - if (!pair.getValue().isAlwaysFalse() && !isNull(pair.getValue())) { - break; - } - } - if (pos == pairs.size()) { - final RexNode disjunction = composeDisjunction(rexBuilder, terms, false); - if (!call.getType().equals(disjunction.getType())) { - return rexBuilder.makeCast(call.getType(), disjunction); - } - return disjunction; - } - } - // 2) Another simplification - // CASE - // WHEN p1 THEN TRUE - // WHEN p2 THEN FALSE - // WHEN p3 THEN TRUE - // ELSE FALSE - // END - // if p1...pn cannot be nullable - for (Ord<Pair<RexNode, RexNode>> pair : Ord.zip(pairs)) { - if (pair.e.getKey().getType().isNullable()) { - break trueFalse; - } - if (!pair.e.getValue().isAlwaysTrue() - && !pair.e.getValue().isAlwaysFalse() - && (!unknownAsFalse || !isNull(pair.e.getValue()))) { - break trueFalse; - } - } - final List<RexNode> terms = new ArrayList<>(); - final List<RexNode> notTerms = new ArrayList<>(); - for (Ord<Pair<RexNode, RexNode>> pair : Ord.zip(pairs)) { - if (pair.e.getValue().isAlwaysTrue()) { - terms.add(andNot(rexBuilder, pair.e.getKey(), notTerms)); - } else { - notTerms.add(pair.e.getKey()); - } - } - final RexNode disjunction = composeDisjunction(rexBuilder, terms, false); - if (!call.getType().equals(disjunction.getType())) { - return rexBuilder.makeCast(call.getType(), disjunction); - } - return disjunction; - } - if (newOperands.equals(operands)) { - return call; - } - return call.clone(call.getType(), newOperands); - } - - /** Given "CASE WHEN p1 THEN v1 ... ELSE e END" - * returns [(p1, v1), ..., (true, e)]. */ - private static List<Pair<RexNode, RexNode>> casePairs(RexBuilder rexBuilder, - List<RexNode> operands) { - final ImmutableList.Builder<Pair<RexNode, RexNode>> builder = - ImmutableList.builder(); - for (int i = 0; i < operands.size() - 1; i += 2) { - builder.add(Pair.of(operands.get(i), operands.get(i + 1))); - } - builder.add( - Pair.of((RexNode) rexBuilder.makeLiteral(true), Util.last(operands))); - return builder.build(); - } - + @Deprecated // to be removed before 2.0 public static RexNode simplifyAnd(RexBuilder rexBuilder, RexCall e, boolean unknownAsFalse) { - final List<RexNode> terms = new ArrayList<>(); - final List<RexNode> notTerms = new ArrayList<>(); - RelOptUtil.decomposeConjunction(e, terms, notTerms); - simplifyList(rexBuilder, terms); - simplifyList(rexBuilder, notTerms); - if (unknownAsFalse) { - return simplifyAnd2ForUnknownAsFalse(rexBuilder, terms, notTerms); - } - return simplifyAnd2(rexBuilder, terms, notTerms); + return new RexSimplify(rexBuilder, unknownAsFalse, EXECUTOR) + .simplifyAnd(e); } + @Deprecated // to be removed before 2.0 public static RexNode simplifyAnd2(RexBuilder rexBuilder, List<RexNode> terms, List<RexNode> notTerms) { - for (RexNode term : terms) { - if (term.isAlwaysFalse()) { - return rexBuilder.makeLiteral(false); - } - } - if (terms.isEmpty() && notTerms.isEmpty()) { - return rexBuilder.makeLiteral(true); - } - if (terms.size() == 1 && notTerms.isEmpty()) { - // Make sure "x OR y OR x" (a single-term conjunction) gets simplified. - return simplify(rexBuilder, terms.get(0)); - } - // If one of the not-disjunctions is a disjunction that is wholly - // contained in the disjunctions list, the expression is not - // satisfiable. - // - // Example #1. x AND y AND z AND NOT (x AND y) - not satisfiable - // Example #2. x AND y AND NOT (x AND y) - not satisfiable - // Example #3. x AND y AND NOT (x AND y AND z) - may be satisfiable - for (RexNode notDisjunction : notTerms) { - final List<RexNode> terms2 = RelOptUtil.conjunctions(notDisjunction); - if (terms.containsAll(terms2)) { - return rexBuilder.makeLiteral(false); - } - } - // Add the NOT disjunctions back in. - for (RexNode notDisjunction : notTerms) { - terms.add( - simplify(rexBuilder, - rexBuilder.makeCall(SqlStdOperatorTable.NOT, notDisjunction))); - } - return composeConjunction(rexBuilder, terms, false); + return new RexSimplify(rexBuilder, false, EXECUTOR) + .simplifyAnd2(terms, notTerms); } - /** As {@link #simplifyAnd2(RexBuilder, List, List)} but we assume that if the expression returns - * UNKNOWN it will be interpreted as FALSE. */ + @Deprecated // to be removed before 2.0 public static RexNode simplifyAnd2ForUnknownAsFalse(RexBuilder rexBuilder, List<RexNode> terms, List<RexNode> notTerms) { - final RexExecutor executor = EXECUTOR; - for (RexNode term : terms) { - if (term.isAlwaysFalse()) { - return rexBuilder.makeLiteral(false); - } - } - if (terms.isEmpty() && notTerms.isEmpty()) { - return rexBuilder.makeLiteral(true); - } - if (terms.size() == 1 && notTerms.isEmpty()) { - // Make sure "x OR y OR x" (a single-term conjunction) gets simplified. - return simplify(rexBuilder, terms.get(0), true); - } - // Try to simplify the expression - final Multimap<String, Pair<String, RexNode>> equalityTerms = ArrayListMultimap.create(); - final Map<String, String> equalityConstantTerms = new HashMap<>(); - final Set<String> negatedTerms = new HashSet<>(); - final Set<String> nullOperands = new HashSet<>(); - final Set<RexNode> notNullOperands = new LinkedHashSet<>(); - final Set<String> comparedOperands = new HashSet<>(); - for (int i = 0; i < terms.size(); i++) { - RexNode term = terms.get(i); - if (!isDeterministic(term)) { - continue; - } - // Simplify BOOLEAN expressions if possible - while (term.getKind() == SqlKind.EQUALS) { - RexCall call = (RexCall) term; - if (call.getOperands().get(0).isAlwaysTrue()) { - term = call.getOperands().get(1); - terms.set(i, term); - continue; - } else if (call.getOperands().get(1).isAlwaysTrue()) { - term = call.getOperands().get(0); - terms.set(i, term); - continue; - } - break; - } - switch (term.getKind()) { - case EQUALS: - case NOT_EQUALS: - case LESS_THAN: - case GREATER_THAN: - case LESS_THAN_OR_EQUAL: - case GREATER_THAN_OR_EQUAL: - RexCall call = (RexCall) term; - RexNode left = call.getOperands().get(0); - comparedOperands.add(left.toString()); - // if it is a cast, we include the inner reference - if (left.getKind() == SqlKind.CAST) { - RexCall leftCast = (RexCall) left; - comparedOperands.add(leftCast.getOperands().get(0).toString()); - } - RexNode right = call.getOperands().get(1); - comparedOperands.add(right.toString()); - // if it is a cast, we include the inner reference - if (right.getKind() == SqlKind.CAST) { - RexCall rightCast = (RexCall) right; - comparedOperands.add(rightCast.getOperands().get(0).toString()); - } - // Check for equality on different constants. If the same ref or CAST(ref) - // is equal to different constants, this condition cannot be satisfied, - // and hence it can be evaluated to FALSE - if (term.getKind() == SqlKind.EQUALS) { - final boolean leftRef = isReferenceOrAccess(left, true); - final boolean rightRef = isReferenceOrAccess(right, true); - if (right instanceof RexLiteral && leftRef) { - final String literal = right.toString(); - final String prevLiteral = equalityConstantTerms.put(left.toString(), literal); - if (prevLiteral != null && !literal.equals(prevLiteral)) { - return rexBuilder.makeLiteral(false); - } - } else if (left instanceof RexLiteral && rightRef) { - final String literal = left.toString(); - final String prevLiteral = equalityConstantTerms.put(right.toString(), literal); - if (prevLiteral != null && !literal.equals(prevLiteral)) { - return rexBuilder.makeLiteral(false); - } - } else if (leftRef && rightRef) { - equalityTerms.put(left.toString(), Pair.of(right.toString(), term)); - } - } - // Assume the expression a > 5 is part of a Filter condition. - // Then we can derive the negated term: a <= 5. - // But as the comparison is string based and thus operands order dependent, - // we should also add the inverted negated term: 5 >= a. - // Observe that for creating the inverted term we invert the list of operands. - RexNode negatedTerm = negate(rexBuilder, call); - if (negatedTerm != null) { - negatedTerms.add(negatedTerm.toString()); - RexNode invertNegatedTerm = invert(rexBuilder, (RexCall) negatedTerm); - if (invertNegatedTerm != null) { - negatedTerms.add(invertNegatedTerm.toString()); - } - } - break; - case IN: - comparedOperands.add(((RexCall) term).operands.get(0).toString()); - break; - case BETWEEN: - comparedOperands.add(((RexCall) term).operands.get(1).toString()); - break; - case IS_NOT_NULL: - notNullOperands.add(((RexCall) term).getOperands().get(0)); - terms.remove(i); - --i; - break; - case IS_NULL: - nullOperands.add(((RexCall) term).getOperands().get(0).toString()); - } - } - // If one column should be null and is in a comparison predicate, - // it is not satisfiable. - // Example. IS NULL(x) AND x < 5 - not satisfiable - if (!Collections.disjoint(nullOperands, comparedOperands)) { - return rexBuilder.makeLiteral(false); - } - // Check for equality of two refs wrt equality with constants - // Example #1. x=5 AND y=5 AND x=y : x=5 AND y=5 - // Example #2. x=5 AND y=6 AND x=y - not satisfiable - for (String ref1 : equalityTerms.keySet()) { - final String literal1 = equalityConstantTerms.get(ref1); - if (literal1 == null) { - continue; - } - Collection<Pair<String, RexNode>> references = equalityTerms.get(ref1); - for (Pair<String, RexNode> ref2 : references) { - final String literal2 = equalityConstantTerms.get(ref2.left); - if (literal2 == null) { - continue; - } - if (!literal1.equals(literal2)) { - // If an expression is equal to two different constants, - // it is not satisfiable - return rexBuilder.makeLiteral(false); - } - // Otherwise we can remove the term, as we already know that - // the expression is equal to two constants - terms.remove(ref2.right); - } - } - // Remove not necessary IS NOT NULL expressions. - // - // Example. IS NOT NULL(x) AND x < 5 : x < 5 - for (RexNode operand : notNullOperands) { - if (!comparedOperands.contains(operand.toString())) { - terms.add( - rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, operand)); - } - } - // If one of the not-disjunctions is a disjunction that is wholly - // contained in the disjunctions list, the expression is not - // satisfiable. - // - // Example #1. x AND y AND z AND NOT (x AND y) - not satisfiable - // Example #2. x AND y AND NOT (x AND y) - not satisfiable - // Example #3. x AND y AND NOT (x AND y AND z) - may be satisfiable - final Set<String> termsSet = new HashSet<String>(strings(terms)); - for (RexNode notDisjunction : notTerms) { - if (!isDeterministic(notDisjunction)) { - continue; - } - final List<String> terms2Set = strings(RelOptUtil.conjunctions(notDisjunction)); - if (termsSet.containsAll(terms2Set)) { - return rexBuilder.makeLiteral(false); - } - } - // Add the NOT disjunctions back in. - for (RexNode notDisjunction : notTerms) { - final RexNode call = - rexBuilder.makeCall(SqlStdOperatorTable.NOT, notDisjunction); - terms.add(simplify(rexBuilder, call, true, executor)); - } - // The negated terms: only deterministic expressions - for (String negatedTerm : negatedTerms) { - if (termsSet.contains(negatedTerm)) { - return rexBuilder.makeLiteral(false); - } - } - return composeConjunction(rexBuilder, terms, false); + return new RexSimplify(rexBuilder, true, EXECUTOR) + .simplifyAnd2ForUnknownAsFalse(terms, notTerms); } public static RexNode negate(RexBuilder rexBuilder, RexCall call) { @@ -2326,34 +1738,17 @@ public class RexUtil { return null; } - /** Simplifies OR(x, x) into x, and similar. */ + @Deprecated // to be removed before 2.0 public static RexNode simplifyOr(RexBuilder rexBuilder, RexCall call) { - assert call.getKind() == SqlKind.OR; - final List<RexNode> terms = RelOptUtil.disjunctions(call); - return simplifyOrs(rexBuilder, terms); + return new RexSimplify(rexBuilder, false, EXECUTOR) + .simplifyOr(call); } - /** Simplifies a list of terms and combines them into an OR. - * Modifies the list in place. */ + @Deprecated // to be removed before 2.0 public static RexNode simplifyOrs(RexBuilder rexBuilder, List<RexNode> terms) { - for (int i = 0; i < terms.size(); i++) { - final RexNode term = simplify(rexBuilder, terms.get(i)); - switch (term.getKind()) { - case LITERAL: - if (!RexLiteral.isNullLiteral(term)) { - if (RexLiteral.booleanValue(term)) { - return term; // true - } else { - terms.remove(i); - --i; - continue; - } - } - } - terms.set(i, term); - } - return composeDisjunction(rexBuilder, terms, false); + return new RexSimplify(rexBuilder, false, EXECUTOR) + .simplifyOrs(terms); } /** @@ -2420,41 +1815,6 @@ public class RexUtil { && (call.operands.size() - i) % 2 == 1; } - private static RexNode simplifyCast(RexBuilder rexBuilder, RexCall e, - RexExecutor executor) { - Preconditions.checkNotNull(executor); - final RexNode operand = e.getOperands().get(0); - switch (operand.getKind()) { - case LITERAL: - final RexLiteral literal = (RexLiteral) operand; - final Comparable value = literal.getValue(); - final SqlTypeName typeName = literal.getTypeName(); - - // First, try to remove the cast without changing the value. - // makeCast and canRemoveCastFromLiteral have the same logic, so we are - // sure to be able to remove the cast. - if (rexBuilder.canRemoveCastFromLiteral(e.getType(), value, typeName)) { - return rexBuilder.makeCast(e.getType(), operand); - } - - // Next, try to convert the value to a different type, - // e.g. CAST('123' as integer) - switch (literal.getTypeName()) { - case TIME: - switch (e.getType().getSqlTypeName()) { - case TIMESTAMP: - return e; - } - } - final List<RexNode> reducedValues = new ArrayList<>(); - executor.reduce(rexBuilder, ImmutableList.<RexNode>of(e), reducedValues); - return Preconditions.checkNotNull( - Iterables.getOnlyElement(reducedValues)); - default: - return e; - } - } - /** Returns a function that applies NOT to its argument. */ public static Function<RexNode, RexNode> notFn(final RexBuilder rexBuilder) { return new Function<RexNode, RexNode>() { @@ -2799,7 +2159,7 @@ public class RexUtil { } private RexNode or(Iterable<? extends RexNode> nodes) { - return composeDisjunction(rexBuilder, nodes, false); + return composeDisjunction(rexBuilder, nodes); } } @@ -2876,7 +2236,7 @@ public class RexUtil { } private RexNode or(Iterable<? extends RexNode> nodes) { - return composeDisjunction(rexBuilder, nodes, false); + return composeDisjunction(rexBuilder, nodes); } } @@ -3014,29 +2374,26 @@ public class RexUtil { /** Deep expressions simplifier. */ public static class ExprSimplifier extends RexShuttle { - private final RexBuilder rexBuilder; - private final RexExecutor executor; - private final boolean unknownAsFalse; + private final RexSimplify simplify; private final Map<RexNode, Boolean> unknownAsFalseMap; - public ExprSimplifier(RexBuilder rexBuilder, boolean unknownAsFalse, - RexExecutor executor) { - this.rexBuilder = Preconditions.checkNotNull(rexBuilder); - this.executor = Preconditions.checkNotNull(executor); - this.unknownAsFalse = unknownAsFalse; + public ExprSimplifier(RexSimplify simplify) { + this.simplify = simplify; this.unknownAsFalseMap = new HashMap<>(); } @Override public RexNode visitCall(RexCall call) { - Boolean unknownAsFalseCall = unknownAsFalse; + boolean unknownAsFalseCall = simplify.unknownAsFalse; if (unknownAsFalseCall) { switch (call.getKind()) { case AND: case CASE: - unknownAsFalseCall = this.unknownAsFalseMap.get(call); - if (unknownAsFalseCall == null) { + final Boolean b = this.unknownAsFalseMap.get(call); + if (b == null) { // Top operator unknownAsFalseCall = true; + } else { + unknownAsFalseCall = b; } break; default: @@ -3048,14 +2405,15 @@ public class RexUtil { } RexNode node = super.visitCall(call); RexNode simplifiedNode = - simplify(rexBuilder, node, unknownAsFalseCall, executor); + simplify.withUnknownAsFalse(unknownAsFalseCall) + .simplify(node); if (node == simplifiedNode) { return node; } if (simplifiedNode.getType().equals(call.getType())) { return simplifiedNode; } - return rexBuilder.makeCast(call.getType(), simplifiedNode, true); + return simplify.rexBuilder.makeCast(call.getType(), simplifiedNode, true); } } }
http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java index 33856d5..079e8e4 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java @@ -1445,7 +1445,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { for (RexNode expr : exprs) { orList.add(rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, expr)); } - list.add(RexUtil.composeDisjunction(rexBuilder, orList, false)); + list.add(RexUtil.composeDisjunction(rexBuilder, orList)); list.add(rexBuilder.makeNullLiteral(type)); for (int i = 0; i < exprs.size() - 1; i++) { RexNode expr = exprs.get(i); http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/main/java/org/apache/calcite/tools/RelBuilder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java index ddc0c43..c2d76f0 100644 --- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java +++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java @@ -49,6 +49,7 @@ import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; import org.apache.calcite.rex.RexShuttle; +import org.apache.calcite.rex.RexSimplify; import org.apache.calcite.rex.RexUtil; import org.apache.calcite.runtime.Hook; import org.apache.calcite.schema.SchemaPlus; @@ -133,7 +134,8 @@ public class RelBuilder { private final RelFactories.TableScanFactory scanFactory; private final Deque<Frame> stack = new ArrayDeque<>(); private final boolean simplify; - private final RexExecutor executor; + private final RexSimplify simplifier; + private final RexSimplify simplifierUnknownAsFalse; protected RelBuilder(Context context, RelOptCluster cluster, RelOptSchema relOptSchema) { @@ -173,9 +175,12 @@ public class RelBuilder { this.scanFactory = Util.first(context.unwrap(RelFactories.TableScanFactory.class), RelFactories.DEFAULT_TABLE_SCAN_FACTORY); - this.executor = + final RexExecutor executor = Util.first(context.unwrap(RexExecutor.class), Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR)); + this.simplifier = new RexSimplify(cluster.getRexBuilder(), false, executor); + this.simplifierUnknownAsFalse = + new RexSimplify(cluster.getRexBuilder(), true, executor); } /** Creates a RelBuilder. */ @@ -552,7 +557,7 @@ public class RelBuilder { * {@code e AND TRUE} becomes {@code e}; * {@code e AND e2 AND NOT e} becomes {@code e2}. */ public RexNode and(Iterable<? extends RexNode> operands) { - return RexUtil.simplifyAnds(cluster.getRexBuilder(), operands); + return simplifier.simplifyAnds(operands); } /** Creates an OR. */ @@ -562,7 +567,7 @@ public class RelBuilder { /** Creates an OR. */ public RexNode or(Iterable<? extends RexNode> operands) { - return RexUtil.composeDisjunction(cluster.getRexBuilder(), operands, false); + return RexUtil.composeDisjunction(cluster.getRexBuilder(), operands); } /** Creates a NOT. */ @@ -803,7 +808,7 @@ public class RelBuilder { * and optimized in a similar way to the {@link #and} method. * If the result is TRUE no filter is created. */ public RelBuilder filter(Iterable<? extends RexNode> predicates) { - final RexNode x = RexUtil.simplifyAnds(cluster.getRexBuilder(), predicates, true); + final RexNode x = simplifierUnknownAsFalse.simplifyAnds(predicates); if (x.isAlwaysFalse()) { return empty(); } @@ -870,7 +875,7 @@ public class RelBuilder { final Iterator<String> nameIterator = fieldNames.iterator(); for (RexNode node : nodes) { if (simplify) { - node = RexUtil.simplifyPreservingType(getRexBuilder(), node, executor); + node = simplifier.simplifyPreservingType(node); } exprList.add(node); String name = nameIterator.hasNext() ? nameIterator.next() : null; http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java b/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java index 63a84f1..ea7b58b 100644 --- a/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java @@ -18,7 +18,6 @@ package org.apache.calcite.rel.rules; import org.apache.calcite.avatica.util.TimeUnitRange; import org.apache.calcite.rex.RexNode; -import org.apache.calcite.rex.RexUtil; import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.test.RexImplicationCheckerTest.Fixture; @@ -204,7 +203,7 @@ public class DateRangeRulesTest { operandRanges)); } assertThat(e.toString(), matcher); - final RexNode e2 = RexUtil.simplify(f.rexBuilder, e); + final RexNode e2 = f.simplify.simplify(e); assertThat(e2.toString(), simplifyMatcher); } http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/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 9a5d605..4ad07d4 100644 --- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java +++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java @@ -33,6 +33,7 @@ import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexSimplify; import org.apache.calcite.rex.RexUtil; import org.apache.calcite.runtime.Hook; import org.apache.calcite.sql.fun.SqlStdOperatorTable; @@ -86,7 +87,9 @@ public class MaterializationTest { final JavaTypeFactoryImpl typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT); - final RexBuilder rexBuilder = new RexBuilder(typeFactory); + private final RexBuilder rexBuilder = new RexBuilder(typeFactory); + private final RexSimplify simplify = + new RexSimplify(rexBuilder, false, RexUtil.EXECUTOR); @Test public void testScan() { CalciteAssert.that() @@ -716,13 +719,13 @@ public class MaterializationTest { private void checkNotSatisfiable(RexNode e) { assertFalse(SubstitutionVisitor.mayBeSatisfiable(e)); - final RexNode simple = RexUtil.simplify(rexBuilder, e); + final RexNode simple = simplify.simplify(e); assertFalse(RexLiteral.booleanValue(simple)); } private void checkSatisfiable(RexNode e, String s) { assertTrue(SubstitutionVisitor.mayBeSatisfiable(e)); - final RexNode simple = RexUtil.simplify(rexBuilder, e); + final RexNode simple = simplify.simplify(e); assertEquals(s, simple.toString()); } @@ -755,7 +758,7 @@ public class MaterializationTest { // target: x = 1 or z = 3 // yields // residue: not (z = 3) - newFilter = SubstitutionVisitor.splitFilter(rexBuilder, + newFilter = SubstitutionVisitor.splitFilter(simplify, x_eq_1, rexBuilder.makeCall(SqlStdOperatorTable.OR, x_eq_1, z_eq_3)); assertThat(newFilter.toString(), equalTo("NOT(=($2, 3))")); @@ -765,7 +768,7 @@ public class MaterializationTest { // target: x = 1 or y = 2 or z = 3 // yields // residue: not (z = 3) - newFilter = SubstitutionVisitor.splitFilter(rexBuilder, + newFilter = SubstitutionVisitor.splitFilter(simplify, rexBuilder.makeCall(SqlStdOperatorTable.OR, x_eq_1, y_eq_2), rexBuilder.makeCall(SqlStdOperatorTable.OR, x_eq_1, y_eq_2, z_eq_3)); assertThat(newFilter.toString(), equalTo("NOT(=($2, 3))")); @@ -775,7 +778,7 @@ public class MaterializationTest { // target: x = 1 or y = 2 or z = 3 // yields // residue: not (y = 2) and not (z = 3) - newFilter = SubstitutionVisitor.splitFilter(rexBuilder, + newFilter = SubstitutionVisitor.splitFilter(simplify, x_eq_1, rexBuilder.makeCall(SqlStdOperatorTable.OR, x_eq_1, y_eq_2, z_eq_3)); assertThat(newFilter.toString(), @@ -786,7 +789,7 @@ public class MaterializationTest { // target: y = 2 or x = 1 // yields // residue: true - newFilter = SubstitutionVisitor.splitFilter(rexBuilder, + newFilter = SubstitutionVisitor.splitFilter(simplify, rexBuilder.makeCall(SqlStdOperatorTable.OR, x_eq_1, y_eq_2), rexBuilder.makeCall(SqlStdOperatorTable.OR, y_eq_2, x_eq_1)); assertThat(newFilter.isAlwaysTrue(), equalTo(true)); @@ -796,7 +799,7 @@ public class MaterializationTest { // target: x = 1 (different object) // yields // residue: true - newFilter = SubstitutionVisitor.splitFilter(rexBuilder, x_eq_1, x_eq_1_b); + newFilter = SubstitutionVisitor.splitFilter(simplify, x_eq_1, x_eq_1_b); assertThat(newFilter.isAlwaysTrue(), equalTo(true)); // 2f. http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java index 84deb87..f321551 100644 --- a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java +++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java @@ -29,6 +29,7 @@ import org.apache.calcite.rex.RexExecutorImpl; import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexSimplify; import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.schema.Schemas; import org.apache.calcite.server.CalciteServerStatement; @@ -357,6 +358,7 @@ public class RexImplicationCheckerTest { public final RexImplicationChecker checker; public final RelDataType rowType; public final RexExecutorImpl executor; + public final RexSimplify simplify; public Fixture() { typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT); @@ -417,6 +419,7 @@ public class RexImplicationCheckerTest { }); executor = holder.get(); + simplify = new RexSimplify(rexBuilder, false, executor); checker = new RexImplicationChecker(rexBuilder, executor, rowType); } http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/test/java/org/apache/calcite/test/RexProgramTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java index c1f567c..671b685 100644 --- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java +++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java @@ -32,6 +32,7 @@ import org.apache.calcite.rex.RexLocalRef; import org.apache.calcite.rex.RexNode; import org.apache.calcite.rex.RexProgram; import org.apache.calcite.rex.RexProgramBuilder; +import org.apache.calcite.rex.RexSimplify; import org.apache.calcite.rex.RexUtil; import org.apache.calcite.sql.SqlOperator; import org.apache.calcite.sql.fun.SqlStdOperatorTable; @@ -75,6 +76,7 @@ public class RexProgramTest { private RexLiteral falseLiteral; private RexNode nullLiteral; private RexNode unknownLiteral; + private RexSimplify simplify; //~ Methods ---------------------------------------------------------------- @@ -89,6 +91,7 @@ public class RexProgramTest { public void setUp() { typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT); rexBuilder = new RexBuilder(typeFactory); + simplify = new RexSimplify(rexBuilder, false, RexUtil.EXECUTOR); trueLiteral = rexBuilder.makeLiteral(true); falseLiteral = rexBuilder.makeLiteral(false); final RelDataType intType = typeFactory.createSqlType(SqlTypeName.INTEGER); @@ -135,16 +138,16 @@ public class RexProgramTest { */ private void checkSimplify2(RexNode node, String expected, String expectedFalse) { - assertThat(RexUtil.simplify(rexBuilder, node).toString(), + assertThat(simplify.simplify(node).toString(), equalTo(expected)); if (node.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) { - assertThat(RexUtil.simplify(rexBuilder, node, true).toString(), + assertThat(simplify.withUnknownAsFalse(true).simplify(node).toString(), equalTo(expectedFalse)); } } private void checkSimplifyFilter(RexNode node, String expected) { - assertThat(RexUtil.simplify(rexBuilder, node, true).toString(), + assertThat(simplify.withUnknownAsFalse(true).simplify(node).toString(), equalTo(expected)); } @@ -239,7 +242,7 @@ public class RexProgramTest { // Normalize the program using the RexProgramBuilder.normalize API. // Note that unused expression '77' is eliminated, input refs (e.g. $0) // become local refs (e.g. $t0), and constants are assigned to locals. - final RexProgram normalizedProgram = program.normalize(rexBuilder, false); + final RexProgram normalizedProgram = program.normalize(rexBuilder, null); final String normalizedProgramString = normalizedProgram.toString(); TestUtil.assertEqualsVerbose( "(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], " @@ -296,7 +299,7 @@ public class RexProgramTest { + "expr#13=[null], expr#14=[CASE($t9, $t10, $t11, $t12, $t13)], " + "expr#15=[NOT($t14)], a=[$t7], b=[$t6], $condition=[$t15])")); - assertThat(program.normalize(rexBuilder, true).toString(), + assertThat(program.normalize(rexBuilder, simplify).toString(), is("(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], " + "expr#4=[+($t0, $t3)], expr#5=[+($t2, $t4)], " + "expr#6=[+($t0, $t4)], expr#7=[5], expr#8=[>($t4, $t7)], " @@ -318,7 +321,7 @@ public class RexProgramTest { + "expr#15=[NOT($t14)], expr#16=[IS TRUE($t15)], a=[$t7], b=[$t6], " + "$condition=[$t16])")); - assertThat(program.normalize(rexBuilder, true).toString(), + assertThat(program.normalize(rexBuilder, simplify).toString(), is("(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], " + "expr#4=[+($t0, $t3)], expr#5=[+($t2, $t4)], " + "expr#6=[+($t0, $t4)], expr#7=[5], expr#8=[>($t4, $t7)], " @@ -1104,7 +1107,7 @@ public class RexProgramTest { rexBuilder.makeLiteral("S")); RexCall caseNode = (RexCall) case_(condition, trueLiteral, falseLiteral); - RexCall result = (RexCall) RexUtil.simplify(rexBuilder, caseNode, false); + RexCall result = (RexCall) simplify.simplify(caseNode); assertThat(result.getType().isNullable(), is(false)); assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN)); assertThat(result.getOperator(), is((SqlOperator) SqlStdOperatorTable.CASE)); @@ -1123,7 +1126,7 @@ public class RexProgramTest { rexBuilder.makeLiteral("S")); RexCall caseNode = (RexCall) case_(condition, trueLiteral, falseLiteral); - RexCall result = (RexCall) RexUtil.simplify(rexBuilder, caseNode, false); + RexCall result = (RexCall) simplify.simplify(caseNode); assertThat(result.getType().isNullable(), is(false)); assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN)); assertThat(result, is(condition)); @@ -1141,7 +1144,7 @@ public class RexProgramTest { RexCall caseNode = (RexCall) case_(condition, aLiteral, bLiteral); - RexCall result = (RexCall) RexUtil.simplify(rexBuilder, caseNode, false); + RexCall result = (RexCall) simplify.simplify(caseNode); assertThat(result.getType().isNullable(), is(false)); assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.CHAR)); assertThat(result, is(caseNode)); @@ -1158,7 +1161,7 @@ public class RexProgramTest { and(rexBuilder.makeInputRef(booleanNotNullableType, 0), rexBuilder.makeInputRef(booleanNullableType, 1), rexBuilder.makeInputRef(booleanNotNullableType, 2)); - RexNode result = RexUtil.simplify(rexBuilder, andCondition, false); + RexNode result = simplify.simplify(andCondition); assertThat(result.getType().isNullable(), is(true)); assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN)); } @@ -1261,7 +1264,7 @@ public class RexProgramTest { assertThat(cast.getType(), is(toType)); continue; // makeCast already simplified } - final RexNode simplified = RexUtil.simplify(rexBuilder, cast); + final RexNode simplified = simplify.simplify(cast); boolean expectedSimplify = literal.getTypeName() != toType.getSqlTypeName() || (literal.getTypeName() == SqlTypeName.CHAR http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/druid/src/main/java/org/apache/calcite/adapter/druid/DruidRules.java ---------------------------------------------------------------------- diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidRules.java b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidRules.java index 91a29ab..bb15921 100644 --- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidRules.java +++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidRules.java @@ -40,10 +40,12 @@ import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexCall; +import org.apache.calcite.rex.RexExecutor; import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; import org.apache.calcite.rex.RexShuttle; +import org.apache.calcite.rex.RexSimplify; import org.apache.calcite.rex.RexUtil; import org.apache.calcite.runtime.PredicateImpl; import org.apache.calcite.sql.type.SqlTypeFamily; @@ -159,10 +161,12 @@ public class DruidRules { break; } } + final RexExecutor executor = + Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR); + final RexSimplify simplify = new RexSimplify(rexBuilder, true, executor); final Pair<List<RexNode>, List<RexNode>> pair = splitFilters(rexBuilder, query, - RexUtil.simplify(rexBuilder, filter.getCondition(), true), - timestampFieldIdx); + simplify.simplify(filter.getCondition()), timestampFieldIdx); if (pair == null) { // We can't push anything useful to Druid. return; @@ -170,8 +174,8 @@ public class DruidRules { List<LocalInterval> intervals = null; if (!pair.left.isEmpty()) { intervals = DruidDateTimeUtils.createInterval( - query.getRowType().getFieldList().get(timestampFieldIdx).getType(), - RexUtil.composeConjunction(rexBuilder, pair.left, false)); + query.getRowType().getFieldList().get(timestampFieldIdx).getType(), + RexUtil.composeConjunction(rexBuilder, pair.left, false)); if (intervals == null) { // We can't push anything useful to Druid. return; http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java ---------------------------------------------------------------------- diff --git a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java index 0cf7a95..8273130 100644 --- a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java +++ b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java @@ -21,7 +21,6 @@ import org.apache.calcite.adapter.druid.LocalInterval; import org.apache.calcite.avatica.util.TimeUnitRange; import org.apache.calcite.rel.rules.DateRangeRules; import org.apache.calcite.rex.RexNode; -import org.apache.calcite.rex.RexUtil; import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.test.RexImplicationCheckerTest.Fixture; @@ -130,7 +129,7 @@ public class DruidDateRangeRulesTest { new DateRangeRules.ExtractShuttle(f.rexBuilder, timeUnit, operandRanges)); } - final RexNode e2 = RexUtil.simplify(f.rexBuilder, e); + final RexNode e2 = f.simplify.simplify(e); List<LocalInterval> intervals = DruidDateTimeUtils.createInterval(f.timeStampDataType, e2); if (intervals == null) {
