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 2018/10/08 06:21:27 UTC
[1/2] calcite git commit: [CALCITE-2604] When simplifying an
expression, say whether an UNKNOWN value will be interpreted as is,
or as TRUE or FALSE
Repository: calcite
Updated Branches:
refs/heads/master be1769bcc -> 6b3844c06
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/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 0e44c25..2eed8d2 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -1010,10 +1010,19 @@ public class RexUtil {
&& containIdentity(exps, inputRowType, Litmus.IGNORE);
}
+ /** As {@link #composeConjunction(RexBuilder, Iterable, boolean)} but never
+ * returns null. */
+ public static @Nonnull RexNode composeConjunction(RexBuilder rexBuilder,
+ Iterable<? extends RexNode> nodes) {
+ final RexNode e = composeConjunction(rexBuilder, nodes, false);
+ return Objects.requireNonNull(e);
+ }
+
/**
* Converts a collection of expressions into an AND.
* If there are zero expressions, returns TRUE.
* If there is one expression, returns just that expression.
+ * If any of the expressions are FALSE, returns FALSE.
* Removes expressions that always evaluate to TRUE.
* Returns null only if {@code nullOnEmpty} and expression is TRUE.
*/
@@ -1028,6 +1037,9 @@ public class RexUtil {
case 1:
return list.get(0);
default:
+ if (containsFalse(list)) {
+ return rexBuilder.makeLiteral(false);
+ }
return rexBuilder.makeCall(SqlStdOperatorTable.AND, list);
}
}
@@ -1070,6 +1082,7 @@ public class RexUtil {
* Converts a collection of expressions into an OR.
* If there are zero expressions, returns FALSE.
* If there is one expression, returns just that expression.
+ * If any of the expressions are TRUE, returns TRUE.
* Removes expressions that always evaluate to FALSE.
* Flattens expressions that are ORs.
*/
@@ -1094,6 +1107,9 @@ public class RexUtil {
case 1:
return list.get(0);
default:
+ if (containsTrue(list)) {
+ return rexBuilder.makeLiteral(true);
+ }
return rexBuilder.makeCall(SqlStdOperatorTable.OR, list);
}
}
@@ -1649,21 +1665,21 @@ public class RexUtil {
@Deprecated // to be removed before 2.0
public static RexNode simplifyPreservingType(RexBuilder rexBuilder,
RexNode e) {
- return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
- EXECUTOR).simplifyPreservingType(e);
+ return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, 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 Create a {@link RexSimplify}, then call its
+ * {@link RexSimplify#simplify(RexNode, RexUnknownAs)} method.
*/
@Deprecated // to be removed before 2.0
public static RexNode simplify(RexBuilder rexBuilder, RexNode e) {
- return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
- EXECUTOR).simplify(e);
+ return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, EXECUTOR)
+ .simplify(e);
}
/**
@@ -1687,34 +1703,34 @@ public class RexUtil {
* @param e Expression to simplify
* @param unknownAsFalse Whether to convert UNKNOWN values to FALSE
*
- * @deprecated Use {@link RexSimplify#simplify(RexNode)},
- * which allows you to specify an {@link RexExecutor}.
+ * @deprecated Create a {@link RexSimplify}, then call its
+ * {@link RexSimplify#simplify(RexNode, RexUnknownAs)} method.
*/
@Deprecated // to be removed before 2.0
public static RexNode simplify(RexBuilder rexBuilder, RexNode e,
boolean unknownAsFalse) {
- return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY,
- unknownAsFalse, EXECUTOR).simplify(e);
+ return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, EXECUTOR)
+ .simplifyUnknownAs(e, RexUnknownAs.falseIf(unknownAsFalse));
}
/**
* Simplifies a conjunction of boolean expressions.
*
- * @deprecated Use {@link RexSimplify#simplifyAnds(Iterable)},
- * which allows you to specify an {@link RexExecutor}.
+ * @deprecated Use
+ * {@link RexSimplify#simplifyAnds(Iterable, RexUnknownAs)}.
*/
@Deprecated // to be removed before 2.0
public static RexNode simplifyAnds(RexBuilder rexBuilder,
Iterable<? extends RexNode> nodes) {
- return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
- EXECUTOR).simplifyAnds(nodes);
+ return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, EXECUTOR)
+ .simplifyAnds(nodes, RexUnknownAs.UNKNOWN);
}
@Deprecated // to be removed before 2.0
public static RexNode simplifyAnds(RexBuilder rexBuilder,
Iterable<? extends RexNode> nodes, boolean unknownAsFalse) {
- return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY,
- unknownAsFalse, EXECUTOR).simplifyAnds(nodes);
+ return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, EXECUTOR)
+ .simplifyAnds(nodes, RexUnknownAs.falseIf(unknownAsFalse));
}
/** Negates a logical expression by adding or removing a NOT. */
@@ -1778,23 +1794,22 @@ public class RexUtil {
@Deprecated // to be removed before 2.0
public static RexNode simplifyAnd(RexBuilder rexBuilder, RexCall e,
boolean unknownAsFalse) {
- return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY,
- unknownAsFalse, EXECUTOR).simplifyAnd(e);
+ return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, EXECUTOR)
+ .simplifyAnd(e, RexUnknownAs.falseIf(unknownAsFalse));
}
@Deprecated // to be removed before 2.0
public static RexNode simplifyAnd2(RexBuilder rexBuilder,
List<RexNode> terms, List<RexNode> notTerms) {
- return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
- EXECUTOR).simplifyAnd2(terms, notTerms);
+ return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, EXECUTOR)
+ .simplifyAnd2(terms, notTerms);
}
@Deprecated // to be removed before 2.0
public static RexNode simplifyAnd2ForUnknownAsFalse(RexBuilder rexBuilder,
List<RexNode> terms, List<RexNode> notTerms) {
- final Class<Comparable> clazz = Comparable.class;
- return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, true,
- EXECUTOR).simplifyAnd2ForUnknownAsFalse(terms, notTerms);
+ return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, EXECUTOR)
+ .simplifyAnd2ForUnknownAsFalse(terms, notTerms);
}
public static RexNode negate(RexBuilder rexBuilder, RexCall call) {
@@ -1827,15 +1842,15 @@ public class RexUtil {
@Deprecated // to be removed before 2.0
public static RexNode simplifyOr(RexBuilder rexBuilder, RexCall call) {
- return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
- EXECUTOR).simplifyOr(call);
+ return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, EXECUTOR)
+ .simplifyOr(call);
}
@Deprecated // to be removed before 2.0
public static RexNode simplifyOrs(RexBuilder rexBuilder,
List<RexNode> terms) {
- return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
- EXECUTOR).simplifyOrs(terms);
+ return new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, EXECUTOR)
+ .simplifyOrs(terms);
}
/**
@@ -1857,7 +1872,7 @@ public class RexUtil {
* returns "x = 10 AND NOT (y = 30)"
* </ul>
*/
- public static RexNode andNot(final RexBuilder rexBuilder, RexNode e,
+ public static @Nonnull RexNode andNot(final RexBuilder rexBuilder, RexNode e,
Iterable<? extends RexNode> notTerms) {
// If "e" is of the form "x = literal", remove all "x = otherLiteral"
// terms from notTerms.
@@ -1884,8 +1899,7 @@ public class RexUtil {
}
return composeConjunction(rexBuilder,
Iterables.concat(ImmutableList.of(e),
- Iterables.transform(notTerms, e2 -> not(rexBuilder, e2))),
- false);
+ Iterables.transform(notTerms, e2 -> not(rexBuilder, e2))));
}
/** Returns whether a given operand of a CASE expression is a predicate.
@@ -1902,6 +1916,24 @@ public class RexUtil {
&& (call.operands.size() - i) % 2 == 1;
}
+ private static boolean containsFalse(Iterable<RexNode> nodes) {
+ for (RexNode node : nodes) {
+ if (node.isAlwaysFalse()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean containsTrue(Iterable<RexNode> nodes) {
+ for (RexNode node : nodes) {
+ if (node.isAlwaysTrue()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/** Returns a function that applies NOT to its argument.
*
* @deprecated Use {@link #not} */
@@ -2350,7 +2382,7 @@ public class RexUtil {
}
private RexNode and(Iterable<? extends RexNode> nodes) {
- return composeConjunction(rexBuilder, nodes, false);
+ return composeConjunction(rexBuilder, nodes);
}
private RexNode or(Iterable<? extends RexNode> nodes) {
@@ -2429,7 +2461,7 @@ public class RexUtil {
}
private RexNode and(Iterable<? extends RexNode> nodes) {
- return composeConjunction(rexBuilder, nodes, false);
+ return composeConjunction(rexBuilder, nodes);
}
private RexNode or(Iterable<? extends RexNode> nodes) {
@@ -2578,45 +2610,47 @@ public class RexUtil {
/** Deep expressions simplifier. */
public static class ExprSimplifier extends RexShuttle {
private final RexSimplify simplify;
- private final Map<RexNode, Boolean> unknownAsFalseMap;
+ private final Map<RexNode, RexUnknownAs> unknownAsMap =
+ new HashMap<>();
+ private final RexUnknownAs unknownAs;
private final boolean matchNullability;
@Deprecated // to be removed before 2.0
public ExprSimplifier(RexSimplify simplify) {
- this(simplify, true);
+ this(simplify, RexUnknownAs.UNKNOWN, true);
}
+ @Deprecated // to be removed before 2.0
public ExprSimplifier(RexSimplify simplify, boolean matchNullability) {
+ this(simplify, RexUnknownAs.UNKNOWN, matchNullability);
+ }
+
+ public ExprSimplifier(RexSimplify simplify, RexUnknownAs unknownAs,
+ boolean matchNullability) {
this.simplify = simplify;
- this.unknownAsFalseMap = new HashMap<>();
+ this.unknownAs = unknownAs;
this.matchNullability = matchNullability;
}
@Override public RexNode visitCall(RexCall call) {
- boolean unknownAsFalseCall = simplify.unknownAsFalse;
- if (unknownAsFalseCall) {
+ RexUnknownAs unknownAs = this.unknownAs;
+ switch (unknownAs) {
+ case FALSE:
switch (call.getKind()) {
case AND:
case CASE:
- final Boolean b = this.unknownAsFalseMap.get(call);
- if (b == null) {
- // Top operator
- unknownAsFalseCall = true;
- } else {
- unknownAsFalseCall = b;
- }
+ // Default value is used for top operator
+ unknownAs = unknownAsMap.getOrDefault(call, RexUnknownAs.FALSE);
break;
default:
- unknownAsFalseCall = false;
+ unknownAs = RexUnknownAs.FALSE;
}
for (RexNode operand : call.operands) {
- this.unknownAsFalseMap.put(operand, unknownAsFalseCall);
+ this.unknownAsMap.put(operand, unknownAs);
}
}
RexNode node = super.visitCall(call);
- RexNode simplifiedNode =
- simplify.withUnknownAsFalse(unknownAsFalseCall)
- .simplify(node);
+ RexNode simplifiedNode = simplify.simplify(node, unknownAs);
if (node == simplifiedNode) {
return node;
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index c347b64..e694d19 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -1135,8 +1135,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
}
final RexNode condition =
- RexUtil.composeConjunction(relBuilder.getRexBuilder(), conditions,
- false);
+ RexUtil.composeConjunction(relBuilder.getRexBuilder(), conditions);
RelNode newJoin =
LogicalJoin.create(leftFrame.r, rightFrame.r, condition,
ImmutableSet.of(), rel.getJoinType().toJoinType());
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index dff1d4f..6c8cb15 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -198,6 +198,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Supplier;
+import javax.annotation.Nonnull;
import static org.apache.calcite.sql.SqlUtil.stripAs;
@@ -1437,14 +1438,12 @@ public class SqlToRelConverter {
assert (call.getOperator() instanceof SqlRowOperator)
&& call.operandCount() == leftKeys.size();
rexComparison =
- RexUtil.composeConjunction(
- rexBuilder,
+ RexUtil.composeConjunction(rexBuilder,
Iterables.transform(
Pair.zip(leftKeys, call.getOperandList()),
pair -> rexBuilder.makeCall(comparisonOp, pair.left,
ensureSqlType(pair.left.getType(),
- bb.convertExpression(pair.right)))),
- false);
+ bb.convertExpression(pair.right)))));
}
comparisons.add(rexComparison);
}
@@ -2634,7 +2633,7 @@ public class SqlToRelConverter {
* @return Expression to match columns from name list, or true if name list
* is empty
*/
- private RexNode convertUsing(SqlValidatorNamespace leftNamespace,
+ private @Nonnull RexNode convertUsing(SqlValidatorNamespace leftNamespace,
SqlValidatorNamespace rightNamespace,
List<String> nameList) {
final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
@@ -2653,7 +2652,7 @@ public class SqlToRelConverter {
}
list.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, operands));
}
- return RexUtil.composeConjunction(rexBuilder, list, false);
+ return RexUtil.composeConjunction(rexBuilder, list);
}
private static JoinRelType convertJoinType(JoinType joinType) {
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/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 470a602..983f74b 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -1403,7 +1403,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
final RexNode expr2 = exprs.get(j);
andList.add(rexBuilder.makeCall(op, expr, expr2));
}
- list.add(RexUtil.composeConjunction(rexBuilder, andList, false));
+ list.add(RexUtil.composeConjunction(rexBuilder, andList));
list.add(expr);
}
list.add(exprs.get(exprs.size() - 1));
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/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 64ae6cb..749fb9c 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -140,7 +140,6 @@ public class RelBuilder {
private final Deque<Frame> stack = new ArrayDeque<>();
private final boolean simplify;
private final RexSimplify simplifier;
- private final RexSimplify simplifierUnknownAsFalse;
protected RelBuilder(Context context, RelOptCluster cluster,
RelOptSchema relOptSchema) {
@@ -188,9 +187,7 @@ public class RelBuilder {
Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR));
final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
this.simplifier =
- new RexSimplify(cluster.getRexBuilder(), predicates, false, executor);
- this.simplifierUnknownAsFalse =
- new RexSimplify(cluster.getRexBuilder(), predicates, true, executor);
+ new RexSimplify(cluster.getRexBuilder(), predicates, executor);
}
/** Creates a RelBuilder. */
@@ -928,7 +925,7 @@ public class RelBuilder {
* If the result is TRUE no filter is created. */
public RelBuilder filter(Iterable<? extends RexNode> predicates) {
final RexNode simplifiedPredicates =
- simplifierUnknownAsFalse.simplifyFilterPredicates(predicates);
+ simplifier.simplifyFilterPredicates(predicates);
if (simplifiedPredicates == null) {
return empty();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/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 4b465f1..1193664 100644
--- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
+++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
@@ -37,6 +37,7 @@ 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.RexUnknownAs;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.runtime.Hook;
import org.apache.calcite.schema.QueryableTable;
@@ -121,8 +122,8 @@ public class MaterializationTest {
new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
private final RexBuilder rexBuilder = new RexBuilder(typeFactory);
private final RexSimplify simplify =
- new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
- RexUtil.EXECUTOR).withParanoid(true);
+ new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, RexUtil.EXECUTOR)
+ .withParanoid(true);
@Test public void testScan() {
CalciteAssert.that()
@@ -756,13 +757,13 @@ public class MaterializationTest {
private void checkNotSatisfiable(RexNode e) {
assertFalse(SubstitutionVisitor.mayBeSatisfiable(e));
- final RexNode simple = simplify.simplify(e);
+ final RexNode simple = simplify.simplifyUnknownAs(e, RexUnknownAs.UNKNOWN);
assertFalse(RexLiteral.booleanValue(simple));
}
private void checkSatisfiable(RexNode e, String s) {
assertTrue(SubstitutionVisitor.mayBeSatisfiable(e));
- final RexNode simple = simplify.simplify(e);
+ final RexNode simple = simplify.simplifyUnknownAs(e, RexUnknownAs.UNKNOWN);
assertEquals(s, simple.toString());
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/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 52d8d78..207a819 100644
--- a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
@@ -33,6 +33,7 @@ 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.RexUnknownAs;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.Schemas;
@@ -349,9 +350,9 @@ public class RexImplicationCheckerTest {
@Test public void testSimplifyCastMatchNullability() {
final Fixture f = new Fixture();
final RexUtil.ExprSimplifier defaultSimplifier =
- new RexUtil.ExprSimplifier(f.simplify, true);
+ new RexUtil.ExprSimplifier(f.simplify, RexUnknownAs.UNKNOWN, true);
final RexUtil.ExprSimplifier nonMatchingNullabilitySimplifier =
- new RexUtil.ExprSimplifier(f.simplify, false);
+ new RexUtil.ExprSimplifier(f.simplify, RexUnknownAs.UNKNOWN, false);
// The cast is nullable, while the literal is not nullable. When we simplify
// it, we end up with the literal. If defaultSimplifier is used, a CAST is
@@ -385,7 +386,7 @@ public class RexImplicationCheckerTest {
ImmutableList.of(TimeUnitRange.YEAR, TimeUnitRange.MONTH);
final Fixture f = new Fixture();
final RexUtil.ExprSimplifier defaultSimplifier =
- new RexUtil.ExprSimplifier(f.simplify, true);
+ new RexUtil.ExprSimplifier(f.simplify, RexUnknownAs.UNKNOWN, true);
final RexNode literalTs =
f.timestampLiteral(new TimestampString("2010-10-10 00:00:00"));
@@ -539,8 +540,8 @@ public class RexImplicationCheckerTest {
executor = holder.get();
simplify =
- new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
- executor).withParanoid(true);
+ new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, executor)
+ .withParanoid(true);
checker = new RexImplicationChecker(rexBuilder, executor, rowType);
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/test/java/org/apache/calcite/test/RexProgramBuilderBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexProgramBuilderBase.java b/core/src/test/java/org/apache/calcite/test/RexProgramBuilderBase.java
index 750c899..14755e0 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramBuilderBase.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramBuilderBase.java
@@ -116,7 +116,7 @@ public abstract class RexProgramBuilderBase {
executor =
new RexExecutorImpl(new DummyTestDataContext());
simplify =
- new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false, executor)
+ new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, executor)
.withParanoid(true);
trueLiteral = rexBuilder.makeLiteral(true);
falseLiteral = rexBuilder.makeLiteral(false);
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/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 64c9459..ceb07a0 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
@@ -33,6 +33,7 @@ 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.RexUnknownAs;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlOperator;
@@ -146,24 +147,39 @@ public class RexProgramTest extends RexProgramBuilderBase {
*/
private void checkSimplify2(RexNode node, String expected,
String expectedFalse) {
- assertThat(simplify.simplify(node).toString(),
- equalTo(expected));
+ checkSimplify3(node, expected, expectedFalse, expected);
+ }
+
+ private void checkSimplify3(RexNode node, String expected,
+ String expectedFalse, String expectedTrue) {
+ final RexNode simplified =
+ simplify.simplifyUnknownAs(node, RexUnknownAs.UNKNOWN);
+ assertThat(simplified.toString(), equalTo(expected));
if (node.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
- assertThat(simplify.withUnknownAsFalse(true).simplify(node).toString(),
- equalTo(expectedFalse));
+ final RexNode simplified2 =
+ simplify.simplifyUnknownAs(node, RexUnknownAs.FALSE);
+ assertThat(simplified2.toString(), equalTo(expectedFalse));
+ final RexNode simplified3 =
+ simplify.simplifyUnknownAs(node, RexUnknownAs.TRUE);
+ assertThat(simplified3.toString(), equalTo(expectedTrue));
+ } else {
+ assertThat(expectedFalse, is(expected));
+ assertThat(expectedTrue, is(expected));
}
}
private void checkSimplifyFilter(RexNode node, String expected) {
- assertThat(simplify.withUnknownAsFalse(true).simplify(node).toString(),
- equalTo(expected));
+ final RexNode simplified =
+ this.simplify.simplifyUnknownAs(node, RexUnknownAs.FALSE);
+ assertThat(simplified.toString(), equalTo(expected));
}
private void checkSimplifyFilter(RexNode node, RelOptPredicateList predicates,
String expected) {
- assertThat(simplify.withUnknownAsFalse(true).withPredicates(predicates)
- .simplify(node).toString(),
- equalTo(expected));
+ final RexNode simplified =
+ simplify.withPredicates(predicates)
+ .simplifyUnknownAs(node, RexUnknownAs.FALSE);
+ assertThat(simplified.toString(), equalTo(expected));
}
/** Returns the number of nodes (including leaves) in a Rex tree. */
@@ -1099,9 +1115,10 @@ public class RexProgramTest extends RexProgramBuilderBase {
case_(aRef, literal1, bRef, literal1, cRef, literal1, dRef, literal1, literal1), "1");
// case: trailing false and null, no simplification
- checkSimplify2(
+ checkSimplify3(
case_(aRef, trueLiteral, bRef, trueLiteral, cRef, falseLiteral, nullBool),
"CASE(?0.a, true, ?0.b, true, ?0.c, false, null)",
+ "CAST(OR(?0.a, ?0.b)):BOOLEAN",
"CAST(OR(?0.a, ?0.b)):BOOLEAN");
// case: form an AND of branches that return true
@@ -1229,21 +1246,21 @@ public class RexProgramTest extends RexProgramBuilderBase {
}
@Test public void simplifyStrong() {
- checkSimplify2(ge(trueLiteral, falseLiteral), "true", "true");
- checkSimplify2(ge(trueLiteral, nullBool), "null", "false");
- checkSimplify2(ge(nullBool, nullBool), "null", "false");
- checkSimplify2(gt(trueLiteral, nullBool), "null", "false");
- checkSimplify2(le(trueLiteral, nullBool), "null", "false");
- checkSimplify2(lt(trueLiteral, nullBool), "null", "false");
+ checkSimplify(ge(trueLiteral, falseLiteral), "true");
+ checkSimplify3(ge(trueLiteral, nullBool), "null", "false", "true");
+ checkSimplify3(ge(nullBool, nullBool), "null", "false", "true");
+ checkSimplify3(gt(trueLiteral, nullBool), "null", "false", "true");
+ checkSimplify3(le(trueLiteral, nullBool), "null", "false", "true");
+ checkSimplify3(lt(trueLiteral, nullBool), "null", "false", "true");
- checkSimplify2(not(nullBool), "null", "false");
- checkSimplify2(ne(vInt(), nullBool), "null", "false");
- checkSimplify2(eq(vInt(), nullBool), "null", "false");
+ checkSimplify3(not(nullBool), "null", "false", "true");
+ checkSimplify3(ne(vInt(), nullBool), "null", "false", "true");
+ checkSimplify3(eq(vInt(), nullBool), "null", "false", "true");
- checkSimplify2(plus(vInt(), nullInt), "null", "false");
- checkSimplify2(sub(vInt(), nullInt), "null", "false");
- checkSimplify2(mul(vInt(), nullInt), "null", "false");
- checkSimplify2(div(vInt(), nullInt), "null", "false");
+ checkSimplify(plus(vInt(), nullInt), "null");
+ checkSimplify(sub(vInt(), nullInt), "null");
+ checkSimplify(mul(vInt(), nullInt), "null");
+ checkSimplify(div(vInt(), nullInt), "null");
}
@Test public void testSimplifyFilter() {
@@ -1290,7 +1307,7 @@ public class RexProgramTest extends RexProgramBuilderBase {
"AND(=(?0.a, 1), =(?0.b, 1))");
// as previous, using simplifyFilterPredicates
- assertThat(simplify.withUnknownAsFalse(true)
+ assertThat(simplify
.simplifyFilterPredicates(args)
.toString(),
equalTo("AND(=(?0.a, 1), =(?0.b, 1))"));
@@ -1300,7 +1317,7 @@ public class RexProgramTest extends RexProgramBuilderBase {
ImmutableList.of(eq(aRef, literal1), eq(aRef, literal10));
checkSimplifyFilter(and(args2), "false");
- assertThat(simplify.withUnknownAsFalse(true)
+ assertThat(simplify
.simplifyFilterPredicates(args2),
nullValue());
@@ -1547,7 +1564,9 @@ public class RexProgramTest extends RexProgramBuilderBase {
// We cannot simplify "b != 1 or b = 1" to "true" because if b is null, the
// result is unknown.
// TODO: "b is not unknown" would be the best simplification.
- assertThat(simplify.withUnknownAsFalse(false).simplify(neOrEq).toString(),
+ final RexNode simplified =
+ this.simplify.simplifyUnknownAs(neOrEq, RexUnknownAs.UNKNOWN);
+ assertThat(simplified.toString(),
equalTo("OR(<>(?0.b, 1), IS NOT NULL(?0.b))"));
// "a is null or a is not null" ==> "true"
@@ -1592,11 +1611,12 @@ public class RexProgramTest extends RexProgramBuilderBase {
eq(aRef, literal4))),
"AND(=(?0.b, 2), =(?0.a, 3))");
- checkSimplify2(
+ checkSimplify3(
or(lt(vInt(), nullInt),
ne(literal(0), vInt())),
"OR(null, <>(0, ?0.int0))",
- "<>(0, ?0.int0)");
+ "<>(0, ?0.int0)",
+ "true");
}
@Test public void testSimplifyUnknown() {
@@ -1617,36 +1637,38 @@ public class RexProgramTest extends RexProgramBuilderBase {
"false");
checkSimplify2(
and(trueLiteral,
- nullInt),
+ nullBool),
"null",
"false");
checkSimplify2(
and(falseLiteral,
- nullInt),
+ nullBool),
"false",
"false");
checkSimplify2(
- and(nullInt,
+ and(nullBool,
eq(aRef, literal1)),
"AND(null, =(?0.a, 1))",
"false");
- checkSimplify2(
+ checkSimplify3(
or(eq(aRef, literal1),
- nullInt),
+ nullBool),
"OR(=(?0.a, 1), null)",
- "=(?0.a, 1)");
+ "=(?0.a, 1)",
+ "true");
checkSimplify2(
or(trueLiteral,
- nullInt),
+ nullBool),
"true",
"true");
- checkSimplify2(
+ checkSimplify3(
or(falseLiteral,
- nullInt),
+ nullBool),
"null",
- "false");
+ "false",
+ "true");
}
@Test public void testSimplifyAnd3() {
@@ -1659,11 +1681,12 @@ public class RexProgramTest extends RexProgramBuilderBase {
final RexNode aRef = rexBuilder.makeFieldAccess(range, 0);
// in the case of 3-valued logic, the result must be unknown if a is unknown
- checkSimplify2(
+ checkSimplify3(
and(aRef,
not(aRef)),
"AND(null, IS NULL(?0.a))",
- "false");
+ "false",
+ "AND(null, IS NULL(?0.a))");
}
@Test public void fieldAccessEqualsHashCode() {
@@ -1689,7 +1712,8 @@ public class RexProgramTest extends RexProgramBuilderBase {
rexBuilder.makeLiteral("S"));
RexCall caseNode = (RexCall) case_(condition, trueLiteral, falseLiteral);
- RexCall result = (RexCall) simplify.simplify(caseNode);
+ final RexCall result =
+ (RexCall) simplify.simplifyUnknownAs(caseNode, RexUnknownAs.UNKNOWN);
assertThat(result.getType().isNullable(), is(false));
assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN));
assertThat(result.getOperator(), is((SqlOperator) SqlStdOperatorTable.CASE));
@@ -1703,7 +1727,8 @@ public class RexProgramTest extends RexProgramBuilderBase {
RexNode condition = eq(input(tVarchar(), 0), literal("S"));
RexNode caseNode = case_(condition, trueLiteral, falseLiteral);
- RexCall result = (RexCall) simplify.simplify(caseNode);
+ RexCall result =
+ (RexCall) simplify.simplifyUnknownAs(caseNode, RexUnknownAs.UNKNOWN);
assertThat(result.getType().isNullable(), is(false));
assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN));
assertThat(result, is(condition));
@@ -1713,7 +1738,8 @@ public class RexProgramTest extends RexProgramBuilderBase {
RexNode condition = eq(input(tVarchar(), 0), literal("S"));
RexNode caseNode = case_(condition, literal("A"), literal("B"));
- RexCall result = (RexCall) simplify.simplify(caseNode);
+ RexCall result =
+ (RexCall) simplify.simplifyUnknownAs(caseNode, RexUnknownAs.UNKNOWN);
assertThat(result.getType().isNullable(), is(false));
assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.CHAR));
assertThat(result, is(caseNode));
@@ -1730,7 +1756,8 @@ public class RexProgramTest extends RexProgramBuilderBase {
and(rexBuilder.makeInputRef(booleanNotNullableType, 0),
rexBuilder.makeInputRef(booleanNullableType, 1),
rexBuilder.makeInputRef(booleanNotNullableType, 2));
- RexNode result = simplify.simplify(andCondition);
+ RexNode result =
+ simplify.simplifyUnknownAs(andCondition, RexUnknownAs.UNKNOWN);
assertThat(result.getType().isNullable(), is(true));
assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN));
}
@@ -1843,7 +1870,8 @@ public class RexProgramTest extends RexProgramBuilderBase {
assertThat(cast.getType(), is(toType));
continue; // makeCast already simplified
}
- final RexNode simplified = simplify.simplify(cast);
+ final RexNode simplified =
+ simplify.simplifyUnknownAs(cast, RexUnknownAs.UNKNOWN);
boolean expectedSimplify =
literal.getTypeName() != toType.getSqlTypeName()
|| (literal.getTypeName() == SqlTypeName.CHAR
@@ -2150,14 +2178,23 @@ public class RexProgramTest extends RexProgramBuilderBase {
"IS DISTINCT FROM(?0.bool0, ?0.bool1)");
}
+ /** Unit test for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-2505">[CALCITE-2505]
+ * RexSimplify wrongly simplifies "COALESCE(+(NULL), x)" to "NULL"</a>. */
@Test public void testSimplifyCoalesce() {
- checkSimplify(coalesce(vIntNotNull(), vInt()), "?0.notNullInt0"); // first arg not null
- checkSimplify(coalesce(vInt(), vIntNotNull()), "COALESCE(?0.int0, ?0.notNullInt0)");
- checkSimplify(coalesce(vInt(), vInt()), "?0.int0"); // repeated arg
- checkSimplify(coalesce(vIntNotNull(), vIntNotNull()), "?0.notNullInt0"); // repeated arg
+ checkSimplify(coalesce(vIntNotNull(), vInt()), // first arg not null
+ "?0.notNullInt0");
+ checkSimplify(coalesce(vInt(), vIntNotNull()),
+ "COALESCE(?0.int0, ?0.notNullInt0)");
+ checkSimplify(coalesce(vInt(), vInt()), // repeated arg
+ "?0.int0");
+ checkSimplify(coalesce(vIntNotNull(), vIntNotNull()), // repeated arg
+ "?0.notNullInt0");
checkSimplify(coalesce(vIntNotNull(), literal(1)), "?0.notNullInt0");
checkSimplify(coalesce(vInt(), literal(1)), "COALESCE(?0.int0, 1)");
- checkSimplify(coalesce(vInt(), plus(vInt(), vIntNotNull()), literal(1), vIntNotNull()),
+ checkSimplify(
+ coalesce(vInt(), plus(vInt(), vIntNotNull()), literal(1),
+ vIntNotNull()),
"COALESCE(?0.int0, +(?0.int0, ?0.notNullInt0), 1)");
checkSimplify2(coalesce(gt(nullInt, nullInt), trueLiteral),
"COALESCE(null, true)", "COALESCE(null, true)");
@@ -2167,11 +2204,10 @@ public class RexProgramTest extends RexProgramBuilderBase {
"COALESCE(+(?0.int1), +(?0.int0))");
}
- @Test
- public void simplifyNull() {
- checkSimplify2(nullBool, "null", "false");
+ @Test public void simplifyNull() {
+ checkSimplify3(nullBool, "null", "false", "true");
// null int must not be simplified to false
- checkSimplify2(nullInt, "null", "null");
+ checkSimplify(nullInt, "null");
}
/** Converts a map to a string, sorting on the string representation of its
@@ -2230,11 +2266,50 @@ public class RexProgramTest extends RexProgramBuilderBase {
"AND(NOT(?0.bool0), NOT(?0.bool1))");
}
+ @Test public void testSimplifyAndNot() {
+ // "x > 1 AND NOT (y > 2)" -> "x > 1 AND y <= 2"
+ checkSimplify(and(gt(vInt(1), literal(1)), not(gt(vInt(2), literal(2)))),
+ "AND(>(?0.int1, 1), <=(?0.int2, 2))");
+ // "x = x AND NOT (y >= y)"
+ // -> "x = x AND y < y" (treating unknown as unknown)
+ // -> false (treating unknown as false)
+ checkSimplify2(and(eq(vInt(1), vInt(1)), not(ge(vInt(2), vInt(2)))),
+ "AND(=(?0.int1, ?0.int1), <(?0.int2, ?0.int2))",
+ "false");
+
+ // "NOT(x = x AND NOT (y = y))"
+ // -> "OR(x <> x, y >= y)" (treating unknown as unknown)
+ // -> "y IS NOT NULL" (treating unknown as false)
+ checkSimplify2(not(and(eq(vInt(1), vInt(1)), not(ge(vInt(2), vInt(2))))),
+ "OR(<>(?0.int1, ?0.int1), >=(?0.int2, ?0.int2))",
+ "IS NOT NULL(?0.int2)");
+ }
+
+ @Test public void testSimplifyOrNot() {
+ // "x > 1 OR NOT (y > 2)" -> "x > 1 OR y <= 2"
+ checkSimplify(or(gt(vInt(1), literal(1)), not(gt(vInt(2), literal(2)))),
+ "OR(>(?0.int1, 1), <=(?0.int2, 2))");
+
+ // "x = x OR NOT (y >= y)"
+ // -> "x = x OR y < y" (treating unknown as unknown)
+ // -> "x IS NOT NULL" (treating unknown as false)
+ checkSimplify2(or(eq(vInt(1), vInt(1)), not(ge(vInt(2), vInt(2)))),
+ "OR(=(?0.int1, ?0.int1), <(?0.int2, ?0.int2))",
+ "IS NOT NULL(?0.int1)");
+
+ // "NOT(x = x OR NOT (y = y))"
+ // -> "AND(x <> x, y >= y)" (treating unknown as unknown)
+ // -> "FALSE" (treating unknown as false)
+ checkSimplify2(not(or(eq(vInt(1), vInt(1)), not(ge(vInt(2), vInt(2))))),
+ "AND(<>(?0.int1, ?0.int1), >=(?0.int2, ?0.int2))",
+ "false");
+ }
+
private RexNode simplify(RexNode e) {
final RexSimplify simplify =
- new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
- RexUtil.EXECUTOR).withParanoid(true);
- return simplify.simplify(e);
+ new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, RexUtil.EXECUTOR)
+ .withParanoid(true);
+ return simplify.simplifyUnknownAs(e, RexUnknownAs.UNKNOWN);
}
@Test public void testInterpreter() {
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderSimple.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderSimple.java b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderSimple.java
index c1a08be..da2b086 100644
--- a/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderSimple.java
+++ b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderSimple.java
@@ -279,7 +279,7 @@ public class MockCatalogReaderSimple extends MockCatalogReader {
salField.getIndex()),
rexBuilder.makeExactLiteral(BigDecimal.valueOf(1000L),
salField.getType())));
- return RexUtil.composeConjunction(rexBuilder, nodes, false);
+ return RexUtil.composeConjunction(rexBuilder, nodes);
}
};
salesSchema.addTable(Util.last(emp20View.getQualifiedName()));
@@ -314,7 +314,7 @@ public class MockCatalogReaderSimple extends MockCatalogReader {
salField.getIndex()),
rexBuilder.makeExactLiteral(BigDecimal.valueOf(1000L),
salField.getType())));
- return RexUtil.composeConjunction(rexBuilder, nodes, false);
+ return RexUtil.composeConjunction(rexBuilder, nodes);
}
};
salesSchema.addTable(Util.last(empNullables20View.getQualifiedName()));
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/test/java/org/apache/calcite/test/fuzzer/RexProgramFuzzyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/fuzzer/RexProgramFuzzyTest.java b/core/src/test/java/org/apache/calcite/test/fuzzer/RexProgramFuzzyTest.java
index 251b730..4b86f5b 100644
--- a/core/src/test/java/org/apache/calcite/test/fuzzer/RexProgramFuzzyTest.java
+++ b/core/src/test/java/org/apache/calcite/test/fuzzer/RexProgramFuzzyTest.java
@@ -19,6 +19,7 @@ package org.apache.calcite.test.fuzzer;
import org.apache.calcite.plan.Strong;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUnknownAs;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
@@ -44,6 +45,7 @@ import java.util.List;
import java.util.PriorityQueue;
import java.util.Random;
import java.util.Set;
+import javax.annotation.Nonnull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -141,34 +143,34 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase {
};
for (SqlOperator op1 : operators) {
RexNode n1 = rexBuilder.makeCall(op1, arg);
- checkTrueFalse(n1);
+ checkUnknownAs(n1);
for (SqlOperator op2 : operators) {
RexNode n2 = rexBuilder.makeCall(op2, n1);
- checkTrueFalse(n2);
+ checkUnknownAs(n2);
for (SqlOperator op3 : operators) {
RexNode n3 = rexBuilder.makeCall(op3, n2);
- checkTrueFalse(n3);
+ checkUnknownAs(n3);
for (SqlOperator op4 : operators) {
RexNode n4 = rexBuilder.makeCall(op4, n3);
- checkTrueFalse(n4);
+ checkUnknownAs(n4);
}
}
}
}
}
-
- private void checkTrueFalse(RexNode node) {
- checkTrueFalse(node, true);
- checkTrueFalse(node, false);
+ private void checkUnknownAs(RexNode node) {
+ checkUnknownAs(node, RexUnknownAs.FALSE);
+ checkUnknownAs(node, RexUnknownAs.UNKNOWN);
+ checkUnknownAs(node, RexUnknownAs.TRUE);
}
- private void checkTrueFalse(RexNode node, boolean unknownAsFalse) {
+ private void checkUnknownAs(RexNode node, RexUnknownAs unknownAs) {
RexNode opt;
- String uaf = unknownAsFalse ? "unknownAsFalse " : "";
+ final String uaf = unknownAsString(unknownAs);
try {
long start = System.nanoTime();
- opt = this.simplify.withUnknownAsFalse(unknownAsFalse).simplify(node);
+ opt = simplify.simplifyUnknownAs(node, unknownAs);
long end = System.nanoTime();
if (end - start > 1000 && slowestTasks != null) {
slowestTasks.add(new SimplifyTask(node, currentSeed, opt, end - start));
@@ -221,7 +223,8 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase {
}
}
if (STRONG.isNull(node)) {
- if (unknownAsFalse) {
+ switch (unknownAs) {
+ case FALSE:
if (node.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
if (!falseLiteral.equals(opt)) {
assertEquals(nodeToString(node)
@@ -235,7 +238,23 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase {
rexBuilder.makeNullLiteral(node.getType()), opt);
}
}
- } else {
+ break;
+ case TRUE:
+ if (node.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
+ if (!trueLiteral.equals(opt)) {
+ assertEquals(nodeToString(node)
+ + " is always null boolean, so it should simplify to TRUE " + uaf,
+ trueLiteral, opt);
+ }
+ } else {
+ if (!RexLiteral.isNullLiteral(opt)) {
+ assertEquals(nodeToString(node)
+ + " is always null (non boolean), so it should simplify to NULL " + uaf,
+ rexBuilder.makeNullLiteral(node.getType()), opt);
+ }
+ }
+ break;
+ case UNKNOWN:
if (!RexUtil.isNull(opt)) {
assertEquals(nodeToString(node)
+ " is always null, so it should simplify to NULL " + uaf,
@@ -255,6 +274,18 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase {
}
}
+ @Nonnull private String unknownAsString(RexUnknownAs unknownAs) {
+ switch (unknownAs) {
+ case UNKNOWN:
+ default:
+ return "";
+ case FALSE:
+ return "unknownAsFalse";
+ case TRUE:
+ return "unknownAsTrue";
+ }
+ }
+
private static String nodeToString(RexNode node) {
return node + "\n"
+ node.accept(new RexToTestCodeShuttle());
@@ -378,7 +409,7 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase {
private void generateRexAndCheckTrueFalse(RexFuzzer fuzzer, Random r) {
RexNode expression = fuzzer.getExpression(r, r.nextInt(10));
- checkTrueFalse(expression);
+ checkUnknownAs(expression);
}
@Ignore("This is just a scaffold for quick investigation of a single fuzz test")
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/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 c79f84c..c385c02 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
@@ -157,8 +157,9 @@ public class DruidRules {
final RelOptPredicateList predicates =
call.getMetadataQuery().getPulledUpPredicates(filter.getInput());
final RexSimplify simplify =
- new RexSimplify(rexBuilder, predicates, true, executor);
- final RexNode cond = simplify.simplify(filter.getCondition());
+ new RexSimplify(rexBuilder, predicates, executor);
+ final RexNode cond =
+ simplify.simplifyUnknownAsFalse(filter.getCondition());
for (RexNode e : RelOptUtil.conjunctions(cond)) {
DruidJsonFilter druidJsonFilter = DruidJsonFilter
.toDruidFilters(e, filter.getInput().getRowType(), query);
@@ -187,7 +188,7 @@ public class DruidRules {
.unwrap(CalciteConnectionConfig.class).timeZone();
assert timeZone != null;
intervals = DruidDateTimeUtils.createInterval(
- RexUtil.composeConjunction(rexBuilder, triple.getLeft(), false));
+ RexUtil.composeConjunction(rexBuilder, triple.getLeft()));
if (intervals == null || intervals.isEmpty()) {
// Case we have a filter with extract that can not be written as interval push down
triple.getMiddle().addAll(triple.getLeft());
@@ -196,7 +197,7 @@ public class DruidRules {
if (!triple.getMiddle().isEmpty()) {
final RelNode newFilter = filter.copy(filter.getTraitSet(), Util.last(query.rels),
- RexUtil.composeConjunction(rexBuilder, triple.getMiddle(), false));
+ RexUtil.composeConjunction(rexBuilder, triple.getMiddle()));
newDruidQuery = DruidQuery.extendQuery(query, newFilter);
}
if (intervals != null && !intervals.isEmpty()) {
@@ -563,7 +564,7 @@ public class DruidRules {
final RelOptPredicateList predicates =
call.getMetadataQuery().getPulledUpPredicates(scan);
final RexSimplify simplify =
- new RexSimplify(builder, predicates, true, executor);
+ new RexSimplify(builder, predicates, executor);
// if the druid query originally contained a filter
boolean containsFilter = false;
@@ -613,7 +614,7 @@ public class DruidRules {
// Simplify the filter as much as possible
RexNode tempFilterNode = filterNode;
- filterNode = simplify.simplify(filterNode);
+ filterNode = simplify.simplifyUnknownAsFalse(filterNode);
// It's possible that after simplification that the expression is now always false.
// Druid cannot handle such a filter.
[2/2] calcite git commit: [CALCITE-2604] When simplifying an
expression, say whether an UNKNOWN value will be interpreted as is,
or as TRUE or FALSE
Posted by jh...@apache.org.
[CALCITE-2604] When simplifying an expression, say whether an UNKNOWN value will be interpreted as is, or as TRUE or FALSE
Add class RexUnknownAs to describe policy, and make it an argument to
internal methods; public methods such as RexSimplify.simplify(RexNode)
and RexSimplify.simplifyAnds(Iterable) use UNKNOWN. (The RexSimplify
constructor that allows a different policy than UNKNOWN is deprecated,
and even if you use the deprecated constructor, that policy only
applies to the top-level expression, not arguments to it.)
Add RexSimplify.simplify(RexNode, RexUnknownAs) (mainly for internal
use), and RexSimplify.simplifyUnknownAsFalse(RexNode) (for public use).
Add variant of RexUtil.composeConjunction that never returns null,
with @Nonnull annotation.
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/6b3844c0
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/6b3844c0
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/6b3844c0
Branch: refs/heads/master
Commit: 6b3844c0634792263a5073b8ea93565fb3415f41
Parents: be1769b
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Sep 27 21:34:22 2018 -0400
Committer: Julian Hyde <jh...@apache.org>
Committed: Sun Oct 7 13:34:53 2018 -0700
----------------------------------------------------------------------
.../adapter/enumerable/EnumerableCalc.java | 2 +-
.../calcite/interpreter/TableScanNode.java | 3 +-
.../org/apache/calcite/plan/RelOptUtil.java | 20 +-
.../calcite/plan/SubstitutionVisitor.java | 27 +-
.../calcite/rel/metadata/RelMdPredicates.java | 35 +-
.../rel/rules/AbstractMaterializedViewRule.java | 103 +++---
.../calcite/rel/rules/DateRangeRules.java | 5 +-
.../calcite/rel/rules/FilterJoinRule.java | 3 +-
.../calcite/rel/rules/JoinAssociateRule.java | 6 +-
.../rel/rules/JoinPushThroughJoinRule.java | 8 +-
.../calcite/rel/rules/JoinToMultiJoinRule.java | 2 +-
.../rel/rules/MultiJoinOptimizeBushyRule.java | 5 +-
.../rel/rules/ReduceExpressionsRule.java | 28 +-
.../java/org/apache/calcite/rex/RexProgram.java | 2 +-
.../apache/calcite/rex/RexProgramBuilder.java | 5 +-
.../org/apache/calcite/rex/RexSimplify.java | 333 ++++++++++++-------
.../org/apache/calcite/rex/RexUnknownAs.java | 99 ++++++
.../java/org/apache/calcite/rex/RexUtil.java | 132 +++++---
.../apache/calcite/sql2rel/RelDecorrelator.java | 3 +-
.../calcite/sql2rel/SqlToRelConverter.java | 11 +-
.../sql2rel/StandardConvertletTable.java | 2 +-
.../org/apache/calcite/tools/RelBuilder.java | 7 +-
.../calcite/test/MaterializationTest.java | 9 +-
.../calcite/test/RexImplicationCheckerTest.java | 11 +-
.../calcite/test/RexProgramBuilderBase.java | 2 +-
.../org/apache/calcite/test/RexProgramTest.java | 189 +++++++----
.../test/catalog/MockCatalogReaderSimple.java | 4 +-
.../test/fuzzer/RexProgramFuzzyTest.java | 59 +++-
.../calcite/adapter/druid/DruidRules.java | 13 +-
29 files changed, 730 insertions(+), 398 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
index 5e38a8b..54eec73 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
@@ -146,7 +146,7 @@ public class EnumerableCalc extends Calc implements EnumerableRel {
final RelMetadataQuery mq = RelMetadataQuery.instance();
final RelOptPredicateList predicates = mq.getPulledUpPredicates(child);
final RexSimplify simplify =
- new RexSimplify(rexBuilder, predicates, false, RexUtil.EXECUTOR);
+ new RexSimplify(rexBuilder, predicates, RexUtil.EXECUTOR);
final RexProgram program = this.program.normalize(rexBuilder, simplify);
BlockStatement moveNextBody;
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
index 54217c9..a6a2a44 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
@@ -242,8 +242,7 @@ public class TableScanNode implements Node {
if (!rejectedFilters.isEmpty()) {
final RexNode filter =
RexUtil.composeConjunction(rel.getCluster().getRexBuilder(),
- rejectedFilters, false);
- assert filter != null;
+ rejectedFilters);
// Re-map filter for the projects that have been applied already
final RexNode filter2;
final RelDataType inputRowType;
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 38912ca..b5063d1 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -123,6 +123,7 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.function.Supplier;
+import javax.annotation.Nonnull;
/**
* <code>RelOptUtil</code> defines static utility methods for use in optimizing
@@ -858,7 +859,7 @@ public abstract class RelOptUtil {
* @return remaining join filters that are not equijoins; may return a
* {@link RexLiteral} true, but never null
*/
- public static RexNode splitJoinCondition(
+ public static @Nonnull RexNode splitJoinCondition(
RelNode left,
RelNode right,
RexNode condition,
@@ -877,7 +878,7 @@ public abstract class RelOptUtil {
nonEquiList);
return RexUtil.composeConjunction(
- left.getCluster().getRexBuilder(), nonEquiList, false);
+ left.getCluster().getRexBuilder(), nonEquiList);
}
@Deprecated // to be removed before 2.0
@@ -963,7 +964,7 @@ public abstract class RelOptUtil {
* returned
* @return What's left, never null
*/
- public static RexNode splitJoinCondition(
+ public static @Nonnull RexNode splitJoinCondition(
List<RelDataTypeField> sysFieldList,
List<RelNode> inputs,
RexNode condition,
@@ -983,7 +984,7 @@ public abstract class RelOptUtil {
// Convert the remainders into a list that are AND'ed together.
return RexUtil.composeConjunction(
- inputs.get(0).getCluster().getRexBuilder(), nonEquiList, false);
+ inputs.get(0).getCluster().getRexBuilder(), nonEquiList);
}
@Deprecated // to be removed before 2.0
@@ -1250,7 +1251,7 @@ public abstract class RelOptUtil {
}
/** Builds an equi-join condition from a set of left and right keys. */
- public static RexNode createEquiJoinCondition(
+ public static @Nonnull RexNode createEquiJoinCondition(
final RelNode left, final List<Integer> leftKeys,
final RelNode right, final List<Integer> rightKeys,
final RexBuilder rexBuilder) {
@@ -1272,8 +1273,7 @@ public abstract class RelOptUtil {
@Override public int size() {
return leftKeys.size();
}
- },
- false);
+ });
}
public static SqlOperator op(SqlKind kind, SqlOperator operator) {
@@ -3425,10 +3425,8 @@ public abstract class RelOptUtil {
new RexImplicationChecker(rexBuilder, (RexExecutorImpl) executor,
rowType);
final RexNode first =
- RexUtil.composeConjunction(rexBuilder, predicates.pulledUpPredicates,
- false);
- final RexNode second =
- RexUtil.composeConjunction(rexBuilder, list, false);
+ RexUtil.composeConjunction(rexBuilder, predicates.pulledUpPredicates);
+ final RexNode second = RexUtil.composeConjunction(rexBuilder, list);
// Suppose we have EMP(empno INT NOT NULL, mgr INT),
// and predicates [empno > 0, mgr > 0].
// We make first: "empno > 0 AND mgr > 0"
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
index 35b3399..f37d3cd 100644
--- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
+++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java
@@ -179,7 +179,7 @@ public class SubstitutionVisitor {
Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR);
final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
this.simplify =
- new RexSimplify(cluster.getRexBuilder(), predicates, false, executor);
+ new RexSimplify(cluster.getRexBuilder(), predicates, executor);
this.rules = rules;
this.query = Holder.of(MutableRels.toMutable(query_));
this.target = MutableRels.toMutable(target_);
@@ -270,35 +270,36 @@ public class SubstitutionVisitor {
@VisibleForTesting
public static RexNode splitFilter(final RexSimplify simplify,
RexNode condition, RexNode target) {
- RexNode condition2 = canonizeNode(simplify.rexBuilder, condition);
- RexNode target2 = canonizeNode(simplify.rexBuilder, target);
+ final RexBuilder rexBuilder = simplify.rexBuilder;
+ RexNode condition2 = canonizeNode(rexBuilder, condition);
+ RexNode target2 = canonizeNode(rexBuilder, target);
// First, try splitting into ORs.
// Given target c1 OR c2 OR c3 OR c4
// and condition c2 OR c4
// residue is c2 OR c4
// Also deals with case target [x] condition [x] yields residue [true].
- RexNode z = splitOr(simplify.rexBuilder, condition2, target2);
+ RexNode z = splitOr(rexBuilder, condition2, target2);
if (z != null) {
return z;
}
- if (isEquivalent(simplify.rexBuilder, condition2, target2)) {
- return simplify.rexBuilder.makeLiteral(true);
+ if (isEquivalent(rexBuilder, condition2, target2)) {
+ return rexBuilder.makeLiteral(true);
}
- RexNode x = andNot(simplify.rexBuilder, target2, condition2);
+ RexNode x = andNot(rexBuilder, target2, condition2);
if (mayBeSatisfiable(x)) {
- RexNode x2 = RexUtil.composeConjunction(simplify.rexBuilder,
- ImmutableList.of(condition2, target2), false);
- RexNode r = canonizeNode(simplify.rexBuilder,
- simplify.withUnknownAsFalse(true).simplify(x2));
- if (!r.isAlwaysFalse() && isEquivalent(simplify.rexBuilder, condition2, r)) {
+ RexNode x2 = RexUtil.composeConjunction(rexBuilder,
+ ImmutableList.of(condition2, target2));
+ RexNode r = canonizeNode(rexBuilder,
+ simplify.simplifyUnknownAsFalse(x2));
+ if (!r.isAlwaysFalse() && isEquivalent(rexBuilder, condition2, r)) {
List<RexNode> conjs = RelOptUtil.conjunctions(r);
for (RexNode e : RelOptUtil.conjunctions(target2)) {
removeAll(conjs, e);
}
- return RexUtil.composeConjunction(simplify.rexBuilder, conjs, false);
+ return RexUtil.composeConjunction(rexBuilder, conjs);
}
}
return null;
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
index 6e30189..985464c 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
@@ -74,6 +74,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
+import javax.annotation.Nonnull;
/**
* Utility to infer Predicates that are applicable above a RelNode.
@@ -300,14 +301,11 @@ public class RelMdPredicates
final RelOptPredicateList leftInfo = mq.getPulledUpPredicates(left);
final RelOptPredicateList rightInfo = mq.getPulledUpPredicates(right);
- final RexSimplify simplifier =
- new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, true, executor);
-
JoinConditionBasedPredicateInference joinInference =
new JoinConditionBasedPredicateInference(join,
- RexUtil.composeConjunction(rexBuilder, leftInfo.pulledUpPredicates, false),
- RexUtil.composeConjunction(rexBuilder, rightInfo.pulledUpPredicates, false),
- simplifier);
+ RexUtil.composeConjunction(rexBuilder, leftInfo.pulledUpPredicates),
+ RexUtil.composeConjunction(rexBuilder, rightInfo.pulledUpPredicates),
+ new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, executor));
return joinInference.inferPredicates(false);
}
@@ -385,7 +383,7 @@ public class RelMdPredicates
}
}
// Add new residual preds
- finalResidualPreds.add(RexUtil.composeConjunction(rexBuilder, residualPreds, false));
+ finalResidualPreds.add(RexUtil.composeConjunction(rexBuilder, residualPreds));
// Add those that are not part of the final set to residual
for (Entry<String, RexNode> e : finalPreds.entrySet()) {
if (!preds.containsKey(e.getKey())) {
@@ -393,7 +391,7 @@ public class RelMdPredicates
for (int j = 0; j < i; j++) {
finalResidualPreds.set(j,
RexUtil.composeConjunction(rexBuilder,
- Lists.newArrayList(finalResidualPreds.get(j), e.getValue()), false));
+ Lists.newArrayList(finalResidualPreds.get(j), e.getValue())));
}
}
}
@@ -406,9 +404,8 @@ public class RelMdPredicates
final RexExecutor executor =
Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR);
final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
- final RexSimplify simplify =
- new RexSimplify(rexBuilder, predicates, true, executor);
- RexNode disjPred = simplify.simplifyOrs(finalResidualPreds);
+ RexNode disjPred = new RexSimplify(rexBuilder, predicates, executor)
+ .simplifyOrs(finalResidualPreds);
if (!disjPred.isAlwaysTrue()) {
preds.add(disjPred);
}
@@ -487,19 +484,19 @@ public class RelMdPredicates
final Set<String> equalityPredicates;
final RexNode leftChildPredicates;
final RexNode rightChildPredicates;
- final RexSimplify simplifier;
+ final RexSimplify simplify;
JoinConditionBasedPredicateInference(Join joinRel,
- RexNode lPreds, RexNode rPreds, RexSimplify simplifier) {
- this(joinRel, joinRel instanceof SemiJoin, lPreds, rPreds, simplifier);
+ RexNode lPreds, RexNode rPreds, RexSimplify simplify) {
+ this(joinRel, joinRel instanceof SemiJoin, lPreds, rPreds, simplify);
}
private JoinConditionBasedPredicateInference(Join joinRel, boolean isSemiJoin,
- RexNode lPreds, RexNode rPreds, RexSimplify simplifier) {
+ RexNode lPreds, RexNode rPreds, RexSimplify simplify) {
super();
this.joinRel = joinRel;
this.isSemiJoin = isSemiJoin;
- this.simplifier = simplifier;
+ this.simplify = simplify;
nFieldsLeft = joinRel.getLeft().getRowType().getFieldList().size();
nFieldsRight = joinRel.getRight().getRowType().getFieldList().size();
nSysFields = joinRel.getSystemFieldList().size();
@@ -678,7 +675,7 @@ public class RelMdPredicates
// simplified RexNode versions as well. It also allows prevent of having
// some duplicates in in result pulledUpPredicates
RexNode simplifiedTarget =
- simplifier.simplifyFilterPredicates(RelOptUtil.conjunctions(tr));
+ simplify.simplifyFilterPredicates(RelOptUtil.conjunctions(tr));
if (checkTarget(inferringFields, allExprsDigests, tr)
&& checkTarget(inferringFields, allExprsDigests, simplifiedTarget)) {
inferredPredicates.add(simplifiedTarget);
@@ -713,9 +710,9 @@ public class RelMdPredicates
b.set(p1);
}
- RexNode compose(RexBuilder rexBuilder, Iterable<RexNode> exprs) {
+ @Nonnull RexNode compose(RexBuilder rexBuilder, Iterable<RexNode> exprs) {
exprs = Linq4j.asEnumerable(exprs).where(Objects::nonNull);
- return RexUtil.composeConjunction(rexBuilder, exprs, false);
+ return RexUtil.composeConjunction(rexBuilder, exprs);
}
/**
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/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 d52ea47..cb34dc8 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
@@ -82,6 +82,7 @@ import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
@@ -208,7 +209,7 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
Util.first(planner.getExecutor(), RexUtil.EXECUTOR);
final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
final RexSimplify simplify =
- new RexSimplify(rexBuilder, predicates, true, executor);
+ new RexSimplify(rexBuilder, predicates, executor);
final List<RelOptMaterialization> materializations =
planner.getMaterializations();
@@ -244,9 +245,10 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
// Bail out
return;
}
- final RexNode pred = simplify.simplify(
- RexUtil.composeConjunction(
- rexBuilder, queryPredicateList.pulledUpPredicates, false));
+ final RexNode pred =
+ simplify.simplifyUnknownAsFalse(
+ RexUtil.composeConjunction(rexBuilder,
+ queryPredicateList.pulledUpPredicates));
final Triple<RexNode, RexNode, RexNode> queryPreds =
splitPredicates(rexBuilder, pred);
@@ -290,9 +292,9 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
// Skip it
continue;
}
- final RexNode viewPred = simplify.simplify(
- RexUtil.composeConjunction(
- rexBuilder, viewPredicateList.pulledUpPredicates, false));
+ final RexNode viewPred = simplify.simplifyUnknownAsFalse(
+ RexUtil.composeConjunction(rexBuilder,
+ viewPredicateList.pulledUpPredicates));
final Triple<RexNode, RexNode, RexNode> viewPreds =
splitPredicates(rexBuilder, viewPred);
@@ -423,12 +425,10 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
continue;
}
RexNode compensationColumnsEquiPred = compensationPreds.getLeft();
- RexNode otherCompensationPred = RexUtil.composeConjunction(
- rexBuilder,
- ImmutableList.of(
- compensationPreds.getMiddle(),
- compensationPreds.getRight()),
- false);
+ RexNode otherCompensationPred =
+ RexUtil.composeConjunction(rexBuilder,
+ ImmutableList.of(compensationPreds.getMiddle(),
+ compensationPreds.getRight()));
assert !compensationColumnsEquiPred.isAlwaysTrue()
|| !otherCompensationPred.isAlwaysTrue();
@@ -463,12 +463,10 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
call.transformTo(result);
} else if (compensationPreds != null) {
RexNode compensationColumnsEquiPred = compensationPreds.getLeft();
- RexNode otherCompensationPred = RexUtil.composeConjunction(
- rexBuilder,
- ImmutableList.of(
- compensationPreds.getMiddle(),
- compensationPreds.getRight()),
- false);
+ RexNode otherCompensationPred =
+ RexUtil.composeConjunction(rexBuilder,
+ ImmutableList.of(compensationPreds.getMiddle(),
+ compensationPreds.getRight()));
// a. Compute final compensation predicate.
if (!compensationColumnsEquiPred.isAlwaysTrue()
@@ -500,12 +498,10 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
}
}
}
- final RexNode viewCompensationPred = RexUtil.composeConjunction(
- rexBuilder,
- ImmutableList.of(
- compensationColumnsEquiPred,
- otherCompensationPred),
- false);
+ final RexNode viewCompensationPred =
+ RexUtil.composeConjunction(rexBuilder,
+ ImmutableList.of(compensationColumnsEquiPred,
+ otherCompensationPred));
// b. Generate final rewriting if possible.
// First, we add the compensation predicate (if any) on top of the view.
@@ -515,7 +511,8 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
RelBuilder builder = call.builder();
RelNode viewWithFilter;
if (!viewCompensationPred.isAlwaysTrue()) {
- RexNode newPred = simplify.simplify(viewCompensationPred);
+ RexNode newPred =
+ simplify.simplifyUnknownAsFalse(viewCompensationPred);
viewWithFilter = builder.push(view).filter(newPred).build();
// We add (and push) the filter to the view plan before triggering the rewriting.
// This is useful in case some of the columns can be folded to same value after
@@ -580,7 +577,7 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
RelNode topProject, RelNode unionInputQuery, RelNode unionInputView);
/**
- * This method is responsible for rewriting the query using the given view query.
+ * Rewrites the query using the given view query.
*
* <p>The input node is a Scan on the view table and possibly a compensation Filter
* on top. If a rewriting can be produced, we return that rewriting. If it cannot
@@ -754,17 +751,14 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
}
}
final RexNode queryCompensationPred = RexUtil.not(
- RexUtil.composeConjunction(
- rexBuilder,
- ImmutableList.of(
- compensationColumnsEquiPred,
- otherCompensationPred),
- false));
+ RexUtil.composeConjunction(rexBuilder,
+ ImmutableList.of(compensationColumnsEquiPred,
+ otherCompensationPred)));
// Generate query rewriting.
RelNode rewrittenPlan = relBuilder
.push(target)
- .filter(simplify.simplify(queryCompensationPred))
+ .filter(simplify.simplifyUnknownAsFalse(queryCompensationPred))
.build();
if (unionRewritingPullProgram != null) {
rewrittenPlan = newNode.copy(
@@ -1147,17 +1141,14 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
}
}
final RexNode queryCompensationPred = RexUtil.not(
- RexUtil.composeConjunction(
- rexBuilder,
- ImmutableList.of(
- compensationColumnsEquiPred,
- otherCompensationPred),
- false));
+ RexUtil.composeConjunction(rexBuilder,
+ ImmutableList.of(compensationColumnsEquiPred,
+ otherCompensationPred)));
// Generate query rewriting.
RelNode rewrittenPlan = relBuilder
.push(target)
- .filter(simplify.simplify(queryCompensationPred))
+ .filter(simplify.simplifyUnknownAsFalse(queryCompensationPred))
.build();
if (unionRewritingPullProgram != null) {
return aggregate.copy(aggregate.getTraitSet(),
@@ -1601,11 +1592,11 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
}
// We only support project - filter - join, thus it should map to
// a single expression
- assert s.size() == 1;
+ final RexNode e = Iterables.getOnlyElement(s);
// Rewrite expr to be expressed on query tables
- RexNode expr = RexUtil.swapTableColumnReferences(
- rexBuilder,
- simplify.simplify(s.iterator().next()),
+ final RexNode simplified = simplify.simplifyUnknownAsFalse(e);
+ RexNode expr = RexUtil.swapTableColumnReferences(rexBuilder,
+ simplified,
tableMapping.inverse(),
equivalenceClassesMap);
exprsLineage.put(expr.toString(), i);
@@ -1635,7 +1626,9 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
additionalExprs.add(rewrittenCeilExpr);
// Then we simplify the expression and we add it to the expressions lineage so we
// can try to find a match
- exprsLineage.put(simplify.simplify(ceilExpr).toString(),
+ final RexNode simplified =
+ simplify.simplifyUnknownAsFalse(ceilExpr);
+ exprsLineage.put(simplified.toString(),
target.getRowType().getFieldCount() + additionalExprs.size() - 1);
}
// FLOOR
@@ -1651,7 +1644,9 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
additionalExprs.add(rewrittenFloorExpr);
// Then we simplify the expression and we add it to the expressions lineage so we
// can try to find a match
- exprsLineage.put(simplify.simplify(floorExpr).toString(),
+ final RexNode simplified =
+ simplify.simplifyUnknownAsFalse(floorExpr);
+ exprsLineage.put(simplified.toString(),
target.getRowType().getFieldCount() + additionalExprs.size() - 1);
}
}
@@ -1665,11 +1660,11 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
}
// We only support project - filter - join, thus it should map to
// a single expression
- assert s.size() == 1;
+ final RexNode e = Iterables.getOnlyElement(s);
// Rewrite expr to be expressed on query tables
- RexNode targetExpr = RexUtil.swapColumnReferences(
- rexBuilder, simplify.simplify(s.iterator().next()),
- equivalenceClassesMap);
+ final RexNode simplified = simplify.simplifyUnknownAsFalse(e);
+ RexNode targetExpr = RexUtil.swapColumnReferences(rexBuilder,
+ simplified, equivalenceClassesMap);
Collection<Integer> c = exprsLineage.get(targetExpr.toString());
if (!c.isEmpty()) {
for (Integer j : c) {
@@ -1936,9 +1931,9 @@ public abstract class AbstractMaterializedViewRule extends RelOptRule {
}
}
return ImmutableTriple.of(
- RexUtil.composeConjunction(rexBuilder, equiColumnsPreds, false),
- RexUtil.composeConjunction(rexBuilder, rangePreds, false),
- RexUtil.composeConjunction(rexBuilder, residualPreds, false));
+ RexUtil.composeConjunction(rexBuilder, equiColumnsPreds),
+ RexUtil.composeConjunction(rexBuilder, rangePreds),
+ RexUtil.composeConjunction(rexBuilder, residualPreds));
}
/**
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java b/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
index ae51560..e9a968e 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
@@ -65,6 +65,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
import java.util.function.Predicate;
+import javax.annotation.Nonnull;
/**
* Collection of planner rules that convert
@@ -488,7 +489,7 @@ public abstract class DateRangeRules {
}
}
- private RexNode toRex(RexNode operand, Range<Calendar> r) {
+ private @Nonnull RexNode toRex(RexNode operand, Range<Calendar> r) {
final List<RexNode> nodes = new ArrayList<>();
if (r.hasLowerBound()) {
final SqlBinaryOperator op = r.lowerBoundType() == BoundType.CLOSED
@@ -506,7 +507,7 @@ public abstract class DateRangeRules {
rexBuilder.makeCall(op, operand,
dateTimeLiteral(rexBuilder, r.upperEndpoint(), operand)));
}
- return RexUtil.composeConjunction(rexBuilder, nodes, false);
+ return RexUtil.composeConjunction(rexBuilder, nodes);
}
private RexLiteral dateTimeLiteral(RexBuilder rexBuilder, Calendar calendar,
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
index 9d06e50..9ee0745 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
@@ -227,8 +227,7 @@ public abstract class FilterJoinRule extends RelOptRule {
.addAll(RelOptUtil.getFieldTypeList(rightRel.getRowType())).build();
final RexNode joinFilter =
RexUtil.composeConjunction(rexBuilder,
- RexUtil.fixUp(rexBuilder, joinFilters, fieldTypes),
- false);
+ RexUtil.fixUp(rexBuilder, joinFilters, fieldTypes));
// If nothing actually got pushed and there is nothing leftover,
// then this rule is a no-op
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
index b3e9f99..56206d5 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
@@ -137,7 +137,7 @@ public class JoinAssociateRule extends RelOptRule {
new RexPermuteInputsShuttle(bottomMapping, relB, relC)
.visitList(bottom, newBottomList);
RexNode newBottomCondition =
- RexUtil.composeConjunction(rexBuilder, newBottomList, false);
+ RexUtil.composeConjunction(rexBuilder, newBottomList);
final Join newBottomJoin =
bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relB,
@@ -145,8 +145,8 @@ public class JoinAssociateRule extends RelOptRule {
// Condition for newTopJoin consists of pieces from bottomJoin and topJoin.
// Field ordinals do not need to be changed.
- RexNode newTopCondition =
- RexUtil.composeConjunction(rexBuilder, top, false);
+ RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, top);
+ @SuppressWarnings("SuspiciousNameCombination")
final Join newTopJoin =
topJoin.copy(topJoin.getTraitSet(), newTopCondition, relA,
newBottomJoin, JoinRelType.INNER, false);
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
index 96b6c84..76606a8 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
@@ -174,7 +174,7 @@ public class JoinPushThroughJoinRule extends RelOptRule {
.visitList(bottomNonIntersecting, newBottomList);
final RexBuilder rexBuilder = cluster.getRexBuilder();
RexNode newBottomCondition =
- RexUtil.composeConjunction(rexBuilder, newBottomList, false);
+ RexUtil.composeConjunction(rexBuilder, newBottomList);
final Join newBottomJoin =
bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relA,
relC, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
@@ -193,7 +193,7 @@ public class JoinPushThroughJoinRule extends RelOptRule {
new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB)
.visitList(bottomIntersecting, newTopList);
RexNode newTopCondition =
- RexUtil.composeConjunction(rexBuilder, newTopList, false);
+ RexUtil.composeConjunction(rexBuilder, newTopList);
@SuppressWarnings("SuspiciousNameCombination")
final Join newTopJoin =
topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin,
@@ -277,7 +277,7 @@ public class JoinPushThroughJoinRule extends RelOptRule {
.visitList(bottomNonIntersecting, newBottomList);
final RexBuilder rexBuilder = cluster.getRexBuilder();
RexNode newBottomCondition =
- RexUtil.composeConjunction(rexBuilder, newBottomList, false);
+ RexUtil.composeConjunction(rexBuilder, newBottomList);
final Join newBottomJoin =
bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relC,
relB, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
@@ -296,7 +296,7 @@ public class JoinPushThroughJoinRule extends RelOptRule {
new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA)
.visitList(bottomIntersecting, newTopList);
RexNode newTopCondition =
- RexUtil.composeConjunction(rexBuilder, newTopList, false);
+ RexUtil.composeConjunction(rexBuilder, newTopList);
@SuppressWarnings("SuspiciousNameCombination")
final Join newTopJoin =
topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin,
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java
index 52e5ed0..0576ff7 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java
@@ -176,7 +176,7 @@ public class JoinToMultiJoinRule extends RelOptRule {
new MultiJoin(
origJoin.getCluster(),
newInputs,
- RexUtil.composeConjunction(rexBuilder, newJoinFilters, false),
+ RexUtil.composeConjunction(rexBuilder, newJoinFilters),
origJoin.getRowType(),
origJoin.getJoinType() == JoinRelType.FULL,
Pair.right(joinSpecs),
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java b/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
index bdaeb05..3439376 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/MultiJoinOptimizeBushyRule.java
@@ -192,7 +192,7 @@ public class MultiJoinOptimizeBushyRule extends RelOptRule {
majorVertex.cost
* minorVertex.cost
* RelMdUtil.guessSelectivity(
- RexUtil.composeConjunction(rexBuilder, conditions, false));
+ RexUtil.composeConjunction(rexBuilder, conditions));
final Vertex newVertex =
new JoinVertex(v, majorFactor, minorFactor, newFactors,
cost, ImmutableList.copyOf(conditions));
@@ -260,8 +260,7 @@ public class MultiJoinOptimizeBushyRule extends RelOptRule {
final RexVisitor<RexNode> shuttle =
new RexPermuteInputsShuttle(mapping, left, right);
final RexNode condition =
- RexUtil.composeConjunction(rexBuilder, joinVertex.conditions,
- false);
+ RexUtil.composeConjunction(rexBuilder, joinVertex.conditions);
final RelNode join = relBuilder.push(left)
.push(right)
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/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 09fdeaa..3140ecf 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
@@ -52,6 +52,7 @@ import org.apache.calcite.rex.RexRangeRef;
import org.apache.calcite.rex.RexShuttle;
import org.apache.calcite.rex.RexSimplify;
import org.apache.calcite.rex.RexSubQuery;
+import org.apache.calcite.rex.RexUnknownAs;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.rex.RexUtil.ExprSimplifier;
import org.apache.calcite.rex.RexVisitorImpl;
@@ -534,14 +535,15 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
final RexExecutor executor =
Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR);
final RexSimplify simplify =
- new RexSimplify(rexBuilder, predicates, unknownAsFalse, executor);
+ new RexSimplify(rexBuilder, predicates, executor);
// Simplify predicates in place
- boolean reduced = reduceExpressionsInternal(rel, simplify, expList,
- predicates);
+ final RexUnknownAs unknownAs = RexUnknownAs.falseIf(unknownAsFalse);
+ boolean reduced = reduceExpressionsInternal(rel, simplify, unknownAs,
+ expList, predicates);
final ExprSimplifier simplifier =
- new ExprSimplifier(simplify, matchNullability);
+ new ExprSimplifier(simplify, unknownAs, matchNullability);
boolean simplified = false;
for (int i = 0; i < expList.size(); i++) {
RexNode expr2 = simplifier.apply(expList.get(i));
@@ -555,7 +557,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
}
protected static boolean reduceExpressionsInternal(RelNode rel,
- RexSimplify simplify, List<RexNode> expList,
+ RexSimplify simplify, RexUnknownAs unknownAs, List<RexNode> expList,
RelOptPredicateList predicates) {
boolean changed = false;
// Replace predicates on CASE to CASE on predicates.
@@ -582,7 +584,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
reducedExprs.add(call.getOperands().get(0));
}
RexReplacer replacer =
- new RexReplacer(simplify, removableCasts, reducedExprs,
+ new RexReplacer(simplify, unknownAs, removableCasts, reducedExprs,
Collections.nCopies(removableCasts.size(), false));
replacer.mutate(expList);
}
@@ -597,8 +599,8 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
final List<Map.Entry<RexNode, RexNode>> pairs =
Lists.newArrayList(predicates.constantMap.entrySet());
RexReplacer replacer =
- new RexReplacer(simplify, Pair.left(pairs), Pair.right(pairs),
- Collections.nCopies(pairs.size(), false));
+ new RexReplacer(simplify, unknownAs, Pair.left(pairs),
+ Pair.right(pairs), Collections.nCopies(pairs.size(), false));
replacer.mutate(constExps2);
}
@@ -635,9 +637,8 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
addCasts = Collections.nCopies(reducedValues.size(), true);
}
- RexReplacer replacer =
- new RexReplacer(simplify, constExps, reducedValues, addCasts);
- replacer.mutate(expList);
+ new RexReplacer(simplify, unknownAs, constExps, reducedValues, addCasts)
+ .mutate(expList);
return true;
}
@@ -757,16 +758,19 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
*/
protected static class RexReplacer extends RexShuttle {
private final RexSimplify simplify;
+ private final RexUnknownAs unknownAs;
private final List<RexNode> reducibleExps;
private final List<RexNode> reducedValues;
private final List<Boolean> addCasts;
RexReplacer(
RexSimplify simplify,
+ RexUnknownAs unknownAs,
List<RexNode> reducibleExps,
List<RexNode> reducedValues,
List<Boolean> addCasts) {
this.simplify = simplify;
+ this.unknownAs = unknownAs;
this.reducibleExps = reducibleExps;
this.reducedValues = reducedValues;
this.addCasts = addCasts;
@@ -787,7 +791,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
}
node = super.visitCall(call);
if (node != call) {
- node = simplify.withUnknownAsFalse(false).simplify(node);
+ node = simplify.simplifyUnknownAs(node, unknownAs);
}
return node;
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rex/RexProgram.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexProgram.java b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
index 32e438c..75a65b3 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexProgram.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
@@ -790,7 +790,7 @@ public class RexProgram {
public RexProgram normalize(RexBuilder rexBuilder, boolean simplify) {
final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
return normalize(rexBuilder, simplify
- ? new RexSimplify(rexBuilder, predicates, false, RexUtil.EXECUTOR)
+ ? new RexSimplify(rexBuilder, predicates, RexUtil.EXECUTOR)
: null);
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java
index a7aacd8..94329e2 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java
@@ -325,8 +325,7 @@ public class RexProgramBuilder {
*/
private RexLocalRef registerInternal(RexNode expr, boolean force) {
final RexSimplify simplify =
- new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
- RexUtil.EXECUTOR);
+ new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, RexUtil.EXECUTOR);
expr = simplify.simplify(expr);
RexLocalRef ref;
@@ -550,7 +549,7 @@ public class RexProgramBuilder {
boolean simplify_) {
RexSimplify simplify = null;
if (simplify_) {
- simplify = new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, false,
+ simplify = new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY,
RexUtil.EXECUTOR);
}
return new RexProgramBuilder(rexBuilder, inputRowType, exprList,
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
index 8a67ab7..6741c65 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -52,6 +52,9 @@ import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
+import static org.apache.calcite.rex.RexUnknownAs.FALSE;
+import static org.apache.calcite.rex.RexUnknownAs.UNKNOWN;
+
/**
* Context required to simplify a row-expression.
*/
@@ -59,7 +62,9 @@ public class RexSimplify {
private final boolean paranoid;
public final RexBuilder rexBuilder;
private final RelOptPredicateList predicates;
- final boolean unknownAsFalse;
+ /** How to treat UNKNOWN values, if one of the deprecated {@code
+ * simplify} methods without an {@code unknownAs} argument is called. */
+ final RexUnknownAs defaultUnknownAs;
final boolean predicateElimination;
private final RexExecutor executor;
private final Strong strong;
@@ -69,21 +74,20 @@ public class RexSimplify {
*
* @param rexBuilder Rex builder
* @param predicates Predicates known to hold on input fields
- * @param unknownAsFalse Whether to convert UNKNOWN values to FALSE
* @param executor Executor for constant reduction, not null
*/
public RexSimplify(RexBuilder rexBuilder, RelOptPredicateList predicates,
- boolean unknownAsFalse, RexExecutor executor) {
- this(rexBuilder, predicates, unknownAsFalse, true, false, executor);
+ RexExecutor executor) {
+ this(rexBuilder, predicates, UNKNOWN, true, false, executor);
}
/** Internal constructor. */
private RexSimplify(RexBuilder rexBuilder, RelOptPredicateList predicates,
- boolean unknownAsFalse, boolean predicateElimination, boolean paranoid,
- RexExecutor executor) {
+ RexUnknownAs defaultUnknownAs, boolean predicateElimination,
+ boolean paranoid, RexExecutor executor) {
this.rexBuilder = Objects.requireNonNull(rexBuilder);
this.predicates = Objects.requireNonNull(predicates);
- this.unknownAsFalse = unknownAsFalse;
+ this.defaultUnknownAs = Objects.requireNonNull(defaultUnknownAs);
this.predicateElimination = predicateElimination;
this.paranoid = paranoid;
this.executor = Objects.requireNonNull(executor);
@@ -93,27 +97,40 @@ public class RexSimplify {
@Deprecated // to be removed before 2.0
public RexSimplify(RexBuilder rexBuilder, boolean unknownAsFalse,
RexExecutor executor) {
- this(rexBuilder, RelOptPredicateList.EMPTY, unknownAsFalse, executor);
+ this(rexBuilder, RelOptPredicateList.EMPTY,
+ RexUnknownAs.falseIf(unknownAsFalse), true, false, executor);
+ }
+
+ @Deprecated // to be removed before 2.0
+ public RexSimplify(RexBuilder rexBuilder, RelOptPredicateList predicates,
+ boolean unknownAsFalse, RexExecutor executor) {
+ this(rexBuilder, predicates, RexUnknownAs.falseIf(unknownAsFalse), true,
+ false, executor);
}
//~ Methods ----------------------------------------------------------------
/** Returns a RexSimplify the same as this but with a specified
- * {@link #unknownAsFalse} value. */
+ * {@link #defaultUnknownAs} value.
+ *
+ * @deprecated Use methods with a {@link RexUnknownAs} argument, such as
+ * {@link #simplify(RexNode, RexUnknownAs)}. */
+ @Deprecated // to be removed before 2.0
public RexSimplify withUnknownAsFalse(boolean unknownAsFalse) {
- return unknownAsFalse == this.unknownAsFalse
- ? this
- : new RexSimplify(rexBuilder, predicates, unknownAsFalse, predicateElimination, paranoid,
- executor);
+ final RexUnknownAs defaultUnknownAs = RexUnknownAs.falseIf(unknownAsFalse);
+ return defaultUnknownAs == this.defaultUnknownAs
+ ? this
+ : new RexSimplify(rexBuilder, predicates, defaultUnknownAs,
+ predicateElimination, paranoid, executor);
}
/** Returns a RexSimplify the same as this but with a specified
* {@link #predicates} value. */
public RexSimplify withPredicates(RelOptPredicateList predicates) {
return predicates == this.predicates
- ? this
- : new RexSimplify(rexBuilder, predicates, unknownAsFalse, predicateElimination, paranoid,
- executor);
+ ? this
+ : new RexSimplify(rexBuilder, predicates, defaultUnknownAs,
+ predicateElimination, paranoid, executor);
}
/** Returns a RexSimplify the same as this but which verifies that
@@ -123,20 +140,22 @@ public class RexSimplify {
*/
public RexSimplify withParanoid(boolean paranoid) {
return paranoid == this.paranoid
- ? this
- : new RexSimplify(rexBuilder, predicates, unknownAsFalse, predicateElimination, paranoid,
- executor);
+ ? this
+ : new RexSimplify(rexBuilder, predicates, defaultUnknownAs,
+ predicateElimination, paranoid, executor);
}
- /** Returns a RexSimplify the same as this but with a specified {@link #predicateElimination}
- * value.
- * This is introduced temporarily; until CALCITE-2401 is fixed
+ /** Returns a RexSimplify the same as this but with a specified
+ * {@link #predicateElimination} value.
+ *
+ * <p>This is introduced temporarily, until
+ * {@link Bug#CALCITE_2401_FIXED [CALCITE-2401] is fixed}.
*/
private RexSimplify withPredicateElimination(boolean predicateElimination) {
return predicateElimination == this.predicateElimination
- ? this
- : new RexSimplify(rexBuilder, predicates, unknownAsFalse, predicateElimination, paranoid,
- executor);
+ ? this
+ : new RexSimplify(rexBuilder, predicates, defaultUnknownAs,
+ predicateElimination, paranoid, executor);
}
/** Simplifies a boolean expression, always preserving its type and its
@@ -145,7 +164,11 @@ public class RexSimplify {
* <p>This is useful if you are simplifying expressions in a
* {@link Project}. */
public RexNode simplifyPreservingType(RexNode e) {
- final RexNode e2 = simplify(e);
+ return simplifyPreservingType(e, defaultUnknownAs);
+ }
+
+ private RexNode simplifyPreservingType(RexNode e, RexUnknownAs unknownAs) {
+ final RexNode e2 = simplifyUnknownAs(e, unknownAs);
if (e2.getType() == e.getType()) {
return e2;
}
@@ -167,34 +190,74 @@ public class RexSimplify {
* returns {@code FALSE}</li>
* </ul>
*
- * <p>If the expression is a predicate in a WHERE clause, UNKNOWN values have
- * the same effect as FALSE. In situations like this, specify
- * {@code unknownAsFalse = true}, so and we can switch from 3-valued logic to
- * simpler 2-valued logic and make more optimizations.
+ * <p>Handles UNKNOWN values using the policy specified when you created this
+ * {@code RexSimplify}. Unless you used a deprecated constructor, that policy
+ * is {@link RexUnknownAs#UNKNOWN}.
+ *
+ * <p>If the expression is a predicate in a WHERE clause, consider instead
+ * using {@link #simplifyUnknownAsFalse(RexNode)}.
*
* @param e Expression to simplify
*/
public RexNode simplify(RexNode e) {
- return verify(e, simplifier -> simplifier.simplify_(e));
+ return simplifyUnknownAs(e, defaultUnknownAs);
+ }
+
+ /** As {@link #simplify(RexNode)}, but for a boolean expression
+ * for which a result of UNKNOWN will be treated as FALSE.
+ *
+ * <p>Use this form for expressions on a WHERE, ON, HAVING or FILTER(WHERE)
+ * clause.
+ *
+ * <p>This may allow certain additional simplifications. A result of UNKNOWN
+ * may yield FALSE, however it may still yield UNKNOWN. (If the simplified
+ * expression has type BOOLEAN NOT NULL, then of course it can only return
+ * FALSE.) */
+ public final RexNode simplifyUnknownAsFalse(RexNode e) {
+ return simplifyUnknownAs(e, FALSE);
}
- private RexNode simplify_(RexNode e) {
+ /** As {@link #simplify(RexNode)}, but specifying how UNKNOWN values are to be
+ * treated.
+ *
+ * <p>If UNKNOWN is treated as FALSE, this may allow certain additional
+ * simplifications. A result of UNKNOWN may yield FALSE, however it may still
+ * yield UNKNOWN. (If the simplified expression has type BOOLEAN NOT NULL,
+ * then of course it can only return FALSE.) */
+ public RexNode simplifyUnknownAs(RexNode e, RexUnknownAs unknownAs) {
+ return verify(e, unknownAs,
+ simplifier -> simplifier.simplify(e, unknownAs));
+ }
+
+ /** Internal method to simplify an expression.
+ *
+ * <p>Unlike the public {@link #simplify(RexNode)}
+ * and {@link #simplifyUnknownAsFalse(RexNode)} methods,
+ * never calls {@link #verify(RexNode, RexUnknownAs, Function)}.
+ * Verify adds an overhead that is only acceptable for a top-level call.
+ */
+ RexNode simplify(RexNode e, RexUnknownAs unknownAs) {
if (strong.isNull(e)) {
- // NULL integer must not be converted to FALSE even in unknownAsFalse mode
- if (unknownAsFalse && e.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
- return rexBuilder.makeLiteral(false);
+ // Only boolean NULL (aka UNKNOWN) can be converted to FALSE. Even in
+ // unknownAs=FALSE mode, we must not convert a NULL integer (say) to FALSE
+ if (e.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
+ switch (unknownAs) {
+ case FALSE:
+ case TRUE:
+ return rexBuilder.makeLiteral(unknownAs.toBoolean());
+ }
}
return rexBuilder.makeNullLiteral(e.getType());
}
switch (e.getKind()) {
case AND:
- return simplifyAnd((RexCall) e);
+ return simplifyAnd((RexCall) e, unknownAs);
case OR:
- return simplifyOr((RexCall) e);
+ return simplifyOr((RexCall) e, unknownAs);
case NOT:
- return simplifyNot((RexCall) e);
+ return simplifyNot((RexCall) e, unknownAs);
case CASE:
- return simplifyCase((RexCall) e);
+ return simplifyCase((RexCall) e, unknownAs);
case COALESCE:
return simplifyCoalesce((RexCall) e);
case CAST:
@@ -216,29 +279,29 @@ public class RexSimplify {
case LESS_THAN:
case LESS_THAN_OR_EQUAL:
case NOT_EQUALS:
- return simplifyComparison((RexCall) e);
+ return simplifyComparison((RexCall) e, unknownAs);
default:
return e;
}
}
// e must be a comparison (=, >, >=, <, <=, !=)
- private RexNode simplifyComparison(RexCall e) {
+ private RexNode simplifyComparison(RexCall e, RexUnknownAs unknownAs) {
//noinspection unchecked
- return simplifyComparison(e, Comparable.class);
+ return simplifyComparison(e, unknownAs, Comparable.class);
}
// e must be a comparison (=, >, >=, <, <=, !=)
private <C extends Comparable<C>> RexNode simplifyComparison(RexCall e,
- Class<C> clazz) {
+ RexUnknownAs unknownAs, Class<C> clazz) {
final List<RexNode> operands = new ArrayList<>(e.operands);
- simplifyList(operands);
+ simplifyList(operands, UNKNOWN);
// Simplify "x <op> x"
final RexNode o0 = operands.get(0);
final RexNode o1 = operands.get(1);
if (RexUtil.eq(o0, o1)
- && (unknownAsFalse
+ && (unknownAs == FALSE
|| (!o0.getType().isNullable()
&& !o1.getType().isNullable()))) {
switch (e.getKind()) {
@@ -246,8 +309,8 @@ public class RexSimplify {
case GREATER_THAN_OR_EQUAL:
case LESS_THAN_OR_EQUAL:
// "x = x" simplifies to "x is not null" (similarly <= and >=)
- return simplify_(
- rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, o0));
+ return simplify(
+ rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, o0), unknownAs);
default:
// "x != x" simplifies to "false" (similarly < and >)
return rexBuilder.makeLiteral(false);
@@ -266,7 +329,7 @@ public class RexSimplify {
final C v0 = ((RexLiteral) o0).getValueAs(clazz);
final C v1 = ((RexLiteral) o1).getValueAs(clazz);
if (v0 == null || v1 == null) {
- return unknownAsFalse
+ return unknownAs == FALSE
? rexBuilder.makeLiteral(false)
: rexBuilder.makeNullLiteral(e.getType());
}
@@ -303,33 +366,40 @@ public class RexSimplify {
* Simplifies a conjunction of boolean expressions.
*/
public RexNode simplifyAnds(Iterable<? extends RexNode> nodes) {
+ return simplifyAnds(nodes, defaultUnknownAs);
+ }
+
+ // package-protected only for a deprecated method; treat as private
+ RexNode simplifyAnds(Iterable<? extends RexNode> nodes,
+ RexUnknownAs unknownAs) {
final List<RexNode> terms = new ArrayList<>();
final List<RexNode> notTerms = new ArrayList<>();
for (RexNode e : nodes) {
RelOptUtil.decomposeConjunction(e, terms, notTerms);
}
- simplifyList(terms);
- simplifyList(notTerms);
- if (unknownAsFalse) {
+ simplifyList(terms, UNKNOWN);
+ simplifyList(notTerms, UNKNOWN);
+ if (unknownAs == FALSE) {
return simplifyAnd2ForUnknownAsFalse(terms, notTerms);
}
return simplifyAnd2(terms, notTerms);
}
- private void simplifyList(List<RexNode> terms) {
+ private void simplifyList(List<RexNode> terms, RexUnknownAs unknownAs) {
+ unknownAs = UNKNOWN; // TODO
for (int i = 0; i < terms.size(); i++) {
- terms.set(i, withUnknownAsFalse(false).simplify_(terms.get(i)));
+ terms.set(i, simplify(terms.get(i), unknownAs));
}
}
private void simplifyAndTerms(List<RexNode> terms) {
- RexSimplify simplify = withUnknownAsFalse(false);
+ RexSimplify simplify = this;
for (int i = 0; i < terms.size(); i++) {
RexNode t = terms.get(i);
if (Predicate.of(t) == null) {
continue;
}
- terms.set(i, simplify.simplify(t));
+ terms.set(i, simplify.simplify(t, UNKNOWN));
RelOptPredicateList newPredicates = simplify.predicates.union(rexBuilder,
RelOptPredicateList.of(rexBuilder, terms.subList(i, i + 1)));
simplify = simplify.withPredicates(newPredicates);
@@ -339,7 +409,7 @@ public class RexSimplify {
if (Predicate.of(t) != null) {
continue;
}
- terms.set(i, simplify.simplify(t));
+ terms.set(i, simplify.simplify(t, UNKNOWN));
}
}
@@ -354,10 +424,11 @@ public class RexSimplify {
if (Predicate.of(t) == null) {
continue;
}
- final RexNode t2 = simplify.simplify(t);
+ final RexNode t2 = simplify.simplify(t, RexUnknownAs.UNKNOWN);
terms.set(i, t2);
final RexNode inverse =
- simplify.simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, t2));
+ simplify.simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, t2),
+ RexUnknownAs.UNKNOWN);
final RelOptPredicateList newPredicates = simplify.predicates.union(rexBuilder,
RelOptPredicateList.of(rexBuilder, ImmutableList.of(inverse)));
simplify = simplify.withPredicates(newPredicates);
@@ -367,16 +438,16 @@ public class RexSimplify {
if (Predicate.of(t) != null) {
continue;
}
- terms.set(i, simplify.simplify(t));
+ terms.set(i, simplify.simplify(t, RexUnknownAs.UNKNOWN));
}
}
- private RexNode simplifyNot(RexCall call) {
+ private RexNode simplifyNot(RexCall call, RexUnknownAs unknownAs) {
final RexNode a = call.getOperands().get(0);
switch (a.getKind()) {
case NOT:
// NOT NOT x ==> x
- return simplify_(((RexCall) a).getOperands().get(0));
+ return simplify(((RexCall) a).getOperands().get(0), unknownAs);
case LITERAL:
if (a.getType().getSqlTypeName() == SqlTypeName.BOOLEAN
&& !RexLiteral.isNullLiteral(a)) {
@@ -385,35 +456,37 @@ public class RexSimplify {
}
final SqlKind negateKind = a.getKind().negate();
if (a.getKind() != negateKind) {
- return simplify_(
+ return simplify(
rexBuilder.makeCall(RexUtil.op(negateKind),
- ((RexCall) a).getOperands()));
+ ((RexCall) a).getOperands()), unknownAs);
}
final SqlKind negateKind2 = a.getKind().negateNullSafe();
if (a.getKind() != negateKind2) {
- return simplify_(
+ return simplify(
rexBuilder.makeCall(RexUtil.op(negateKind2),
- ((RexCall) a).getOperands()));
+ ((RexCall) a).getOperands()), unknownAs);
}
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.makeCall(SqlStdOperatorTable.NOT, operand)));
+ simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, operand),
+ unknownAs));
}
- return simplify_(
- rexBuilder.makeCall(SqlStdOperatorTable.OR, newOperands));
+ return simplify(
+ rexBuilder.makeCall(SqlStdOperatorTable.OR, newOperands), unknownAs);
}
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.makeCall(SqlStdOperatorTable.NOT, operand)));
+ simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, operand),
+ unknownAs));
}
- return simplify_(
- rexBuilder.makeCall(SqlStdOperatorTable.AND, newOperands));
+ return simplify(
+ rexBuilder.makeCall(SqlStdOperatorTable.AND, newOperands), unknownAs);
}
return call;
}
@@ -473,7 +546,7 @@ public class RexSimplify {
// 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_(a);
+ return simplify(a, UNKNOWN);
}
break;
case IS_FALSE:
@@ -481,7 +554,8 @@ public class RexSimplify {
// 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.makeCall(SqlStdOperatorTable.NOT, a));
+ return simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, a),
+ UNKNOWN);
}
break;
}
@@ -495,9 +569,9 @@ public class RexSimplify {
// because of null values.
final SqlOperator notKind = RexUtil.op(kind.negateNullSafe());
final RexNode arg = ((RexCall) a).operands.get(0);
- return simplify_(rexBuilder.makeCall(notKind, arg));
+ return simplify(rexBuilder.makeCall(notKind, arg), UNKNOWN);
}
- RexNode a2 = withUnknownAsFalse(false).simplify_(a);
+ RexNode a2 = simplify(a, UNKNOWN);
if (a != a2) {
return rexBuilder.makeCall(RexUtil.op(kind), ImmutableList.of(a2));
}
@@ -529,7 +603,7 @@ public class RexSimplify {
operands.add(simplified);
}
}
- return RexUtil.composeConjunction(rexBuilder, operands, false);
+ return RexUtil.composeConjunction(rexBuilder, operands);
case CUSTOM:
switch (a.getKind()) {
case LITERAL:
@@ -577,9 +651,8 @@ public class RexSimplify {
private RexNode simplifyCoalesce(RexCall call) {
final Set<String> digests = new HashSet<>();
final List<RexNode> operands = new ArrayList<>();
- final RexSimplify simplify = withUnknownAsFalse(false);
for (RexNode operand : call.getOperands()) {
- operand = simplify.simplify_(operand);
+ operand = simplify(operand, UNKNOWN);
if (digests.add(operand.toString())) {
operands.add(operand);
}
@@ -600,7 +673,7 @@ public class RexSimplify {
}
}
- private RexNode simplifyCase(RexCall call) {
+ private RexNode simplifyCase(RexCall call, RexUnknownAs unknownAs) {
final List<RexNode> operands = call.getOperands();
final List<RexNode> newOperands = new ArrayList<>();
final Set<String> values = new HashSet<>();
@@ -610,7 +683,7 @@ public class RexSimplify {
if (operand.isAlwaysTrue()) {
// Predicate is always TRUE. Make value the ELSE and quit.
newOperands.add(operands.get(++i));
- if (unknownAsFalse && RexUtil.isNull(operands.get(i))) {
+ if (unknownAs == FALSE && RexUtil.isNull(operands.get(i))) {
values.add(rexBuilder.makeLiteral(false).toString());
} else {
values.add(operands.get(i).toString());
@@ -622,7 +695,7 @@ public class RexSimplify {
continue;
}
} else {
- if (unknownAsFalse && RexUtil.isNull(operand)) {
+ if (unknownAs == FALSE && RexUtil.isNull(operand)) {
values.add(rexBuilder.makeLiteral(false).toString());
} else {
values.add(operand.toString());
@@ -651,7 +724,7 @@ public class RexSimplify {
// ELSE FALSE
// END
// can be rewritten to: (p1 or p2)
- if (unknownAsFalse) {
+ if (unknownAs == FALSE) {
final List<RexNode> terms = new ArrayList<>();
int pos = 0;
for (; pos < pairs.size(); pos++) {
@@ -693,7 +766,7 @@ public class RexSimplify {
}
if (!pair.e.getValue().isAlwaysTrue()
&& !pair.e.getValue().isAlwaysFalse()
- && (!unknownAsFalse || !RexUtil.isNull(pair.e.getValue()))) {
+ && (unknownAs == UNKNOWN || !RexUtil.isNull(pair.e.getValue()))) {
break trueFalse;
}
}
@@ -710,7 +783,7 @@ public class RexSimplify {
if (!call.getType().equals(disjunction.getType())) {
disjunction = rexBuilder.makeCast(call.getType(), disjunction);
}
- return simplify_(disjunction);
+ return simplify(disjunction, unknownAs);
}
if (newOperands.equals(operands)) {
return call;
@@ -732,22 +805,27 @@ public class RexSimplify {
return builder.build();
}
- // public only to support a deprecated method; treat as private
+ @Deprecated // to be removed before 2.0
public RexNode simplifyAnd(RexCall e) {
+ return simplifyAnd(e, defaultUnknownAs);
+ }
+
+ RexNode simplifyAnd(RexCall e, RexUnknownAs unknownAs) {
final List<RexNode> terms = new ArrayList<>();
final List<RexNode> notTerms = new ArrayList<>();
RelOptUtil.decomposeConjunction(e, terms, notTerms);
- if (unknownAsFalse && predicateElimination) {
+ if (unknownAs == FALSE && predicateElimination) {
simplifyAndTerms(terms);
} else {
- simplifyList(terms);
+ simplifyList(terms, unknownAs);
}
- simplifyList(notTerms);
+ simplifyList(notTerms, UNKNOWN); // TODO could be unknownAs.negate()?
- if (unknownAsFalse) {
- return simplifyAnd2ForUnknownAsFalse(terms, notTerms);
+ switch (unknownAs) {
+ case FALSE:
+ return simplifyAnd2ForUnknownAsFalse(terms, notTerms, Comparable.class);
}
return simplifyAnd2(terms, notTerms);
}
@@ -805,10 +883,11 @@ public class RexSimplify {
// Add the NOT disjunctions back in.
for (RexNode notDisjunction : notTerms) {
terms.add(
- simplify_(
- rexBuilder.makeCall(SqlStdOperatorTable.NOT, notDisjunction)));
+ simplify(
+ rexBuilder.makeCall(SqlStdOperatorTable.NOT, notDisjunction),
+ UNKNOWN));
}
- return RexUtil.composeConjunction(rexBuilder, terms, false);
+ return RexUtil.composeConjunction(rexBuilder, terms);
}
/** As {@link #simplifyAnd2(List, List)} but we assume that if the expression
@@ -831,7 +910,7 @@ public class RexSimplify {
}
if (terms.size() == 1 && notTerms.isEmpty()) {
// Make sure "x OR y OR x" (a single-term conjunction) gets simplified.
- return simplify_(terms.get(0));
+ return simplify(terms.get(0), FALSE);
}
// Try to simplify the expression
final Multimap<String, Pair<String, RexNode>> equalityTerms = ArrayListMultimap.create();
@@ -1031,7 +1110,7 @@ public class RexSimplify {
for (RexNode notDisjunction : notTerms) {
final RexNode call =
rexBuilder.makeCall(SqlStdOperatorTable.NOT, notDisjunction);
- terms.add(simplify_(call));
+ terms.add(simplify(call, FALSE));
}
// The negated terms: only deterministic expressions
for (String negatedTerm : negatedTerms) {
@@ -1039,7 +1118,7 @@ public class RexSimplify {
return rexBuilder.makeLiteral(false);
}
}
- return RexUtil.composeConjunction(rexBuilder, terms, false);
+ return RexUtil.composeConjunction(rexBuilder, terms);
}
private <C extends Comparable<C>> RexNode simplifyUsingPredicates(RexNode e,
@@ -1066,7 +1145,8 @@ public class RexSimplify {
// Range is always satisfied given these predicates; but nullability might
// be problematic
return simplify(
- rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, comparison.ref));
+ rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, comparison.ref),
+ RexUnknownAs.UNKNOWN);
} else if (range2.lowerEndpoint().equals(range2.upperEndpoint())) {
if (range2.lowerBoundType() == BoundType.OPEN
|| range2.upperBoundType() == BoundType.OPEN) {
@@ -1128,29 +1208,42 @@ public class RexSimplify {
return r0;
}
- /** Simplifies OR(x, x) into x, and similar. */
+ /** Simplifies OR(x, x) into x, and similar.
+ * The simplified expression returns UNKNOWN values as is (not as FALSE). */
public RexNode simplifyOr(RexCall call) {
+ return simplifyOr(call, UNKNOWN);
+ }
+
+ private RexNode simplifyOr(RexCall call, RexUnknownAs unknownAs) {
assert call.getKind() == SqlKind.OR;
final List<RexNode> terms = RelOptUtil.disjunctions(call);
if (predicateElimination) {
simplifyOrTerms(terms);
}
- return simplifyOrs(terms);
+ return simplifyOrs(terms, unknownAs);
}
/** Simplifies a list of terms and combines them into an OR.
- * Modifies the list in place. */
+ * Modifies the list in place.
+ * The simplified expression returns UNKNOWN values as is (not as FALSE). */
public RexNode simplifyOrs(List<RexNode> terms) {
+ return simplifyOrs(terms, UNKNOWN);
+ }
+
+ /** Simplifies a list of terms and combines them into an OR.
+ * Modifies the list in place. */
+ private RexNode simplifyOrs(List<RexNode> terms, RexUnknownAs unknownAs) {
if (paranoid) {
final RexNode before = RexUtil.composeDisjunction(rexBuilder, terms);
- return verify(before, simplifier -> simplifier.simplifyOrs(terms));
+ return verify(before, unknownAs,
+ simplifier -> simplifier.simplifyOrs(terms, unknownAs));
}
for (int i = 0; i < terms.size(); i++) {
- final RexNode term = simplify_(terms.get(i));
+ final RexNode term = simplify(terms.get(i), unknownAs);
switch (term.getKind()) {
case LITERAL:
if (RexLiteral.isNullLiteral(term)) {
- if (unknownAsFalse) {
+ if (unknownAs == FALSE) {
terms.remove(i);
--i;
continue;
@@ -1170,7 +1263,7 @@ public class RexSimplify {
return RexUtil.composeDisjunction(rexBuilder, terms);
}
- private RexNode verify(RexNode before,
+ private RexNode verify(RexNode before, RexUnknownAs unknownAs,
Function<RexSimplify, RexNode> simplifier) {
final RexNode simplified = simplifier.apply(withParanoid(false));
if (!paranoid) {
@@ -1203,13 +1296,16 @@ public class RexSimplify {
if (v1 == null) {
throw new AssertionError("interpreter returned null for " + foo1.e);
}
- if (unknownAsFalse
- && before.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
- if (v0 == NullSentinel.INSTANCE) {
- v0 = false;
- }
- if (v1 == NullSentinel.INSTANCE) {
- v1 = false;
+ if (before.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
+ switch (unknownAs) {
+ case FALSE:
+ case TRUE:
+ if (v0 == NullSentinel.INSTANCE) {
+ v0 = unknownAs.toBoolean();
+ }
+ if (v1 == NullSentinel.INSTANCE) {
+ v1 = unknownAs.toBoolean();
+ }
}
}
if (!v0.equals(v1)) {
@@ -1252,7 +1348,7 @@ public class RexSimplify {
Iterables.getOnlyElement(reducedValues));
default:
if (operand.getType().equals(e.getType())) {
- return simplify_(operand);
+ return simplify(operand, UNKNOWN);
}
return e;
}
@@ -1276,7 +1372,7 @@ public class RexSimplify {
// Bail out since we only simplify floor <date>
return e;
}
- final RexNode operand = simplify_(e.getOperands().get(0));
+ final RexNode operand = simplify(e.getOperands().get(0), UNKNOWN);
if (e.getKind() == operand.getKind()) {
assert e.getKind() == SqlKind.CEIL || e.getKind() == SqlKind.FLOOR;
// CEIL/FLOOR on top of CEIL/FLOOR
@@ -1702,12 +1798,18 @@ public class RexSimplify {
* Combines predicates AND, optimizes, and returns null if the result is
* always false.
*
+ * <p>The expression is simplified on the assumption that an UNKNOWN value
+ * is always treated as FALSE. Therefore the simplified expression may
+ * sometimes evaluate to FALSE where the original expression would evaluate to
+ * UNKNOWN.
+ *
* @param predicates Filter condition predicates
* @return simplified conjunction of predicates for the filter, null if always false
*/
public RexNode simplifyFilterPredicates(Iterable<? extends RexNode> predicates) {
- final RexNode simplifiedAnds = withPredicateElimination(Bug.CALCITE_2401_FIXED)
- .simplifyAnds(predicates);
+ final RexNode simplifiedAnds =
+ withPredicateElimination(Bug.CALCITE_2401_FIXED)
+ .simplifyAnds(predicates, FALSE);
if (simplifiedAnds.isAlwaysFalse()) {
return null;
}
@@ -1717,6 +1819,7 @@ public class RexSimplify {
// other rewrites.
return removeNullabilityCast(simplifiedAnds);
}
+
}
// End RexSimplify.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/6b3844c0/core/src/main/java/org/apache/calcite/rex/RexUnknownAs.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUnknownAs.java b/core/src/main/java/org/apache/calcite/rex/RexUnknownAs.java
new file mode 100644
index 0000000..e122e0d
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/rex/RexUnknownAs.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.rex;
+
+import javax.annotation.Nonnull;
+
+/** Policy for whether a simplified expression may instead return another
+ * value.
+ *
+ * <p>In particular, it deals with converting three-valued logic (TRUE, FALSE,
+ * UNKNOWN) to two-valued logic (TRUE, FALSE) for callers that treat the UNKNOWN
+ * value the same as TRUE or FALSE.
+ *
+ * <p>Sometimes the three-valued version of the expression is simpler (has a
+ * smaller expression tree) than the two-valued version. In these cases,
+ * favor simplicity over reduction to two-valued logic.
+ *
+ * @see RexSimplify */
+public enum RexUnknownAs {
+ /** Policy that indicates that the expression is being used in a context
+ * Where an UNKNOWN value is treated in the same way as FALSE. Therefore, when
+ * simplifying the expression, it is acceptable for the simplified expression
+ * to evaluate to FALSE in some situations where the original expression would
+ * evaluate to UNKNOWN.
+ *
+ * <p>SQL predicates ({@code WHERE}, {@code ON}, {@code HAVING} and
+ * {@code FILTER (WHERE)} clauses, a {@code WHEN} clause of a {@code CASE}
+ * expression, and in {@code CHECK} constraints) all treat UNKNOWN as FALSE.
+ *
+ * <p>If the simplified expression never returns UNKNOWN, the simplifier
+ * should make this clear to the caller, if possible, by marking its type as
+ * {@code BOOLEAN NOT NULL}. */
+ FALSE,
+
+ /** Policy that indicates that the expression is being used in a context
+ * Where an UNKNOWN value is treated in the same way as TRUE. Therefore, when
+ * simplifying the expression, it is acceptable for the simplified expression
+ * to evaluate to TRUE in some situations where the original expression would
+ * evaluate to UNKNOWN.
+ *
+ * <p>This does not occur commonly in SQL. However, it occurs internally
+ * during simplification. For example, "{@code WHERE NOT expression}"
+ * evaluates "{@code NOT expression}" in a context that treats UNKNOWN as
+ * FALSE; it is useful to consider that "{@code expression}" is evaluated in a
+ * context that treats UNKNOWN as TRUE.
+ *
+ * <p>If the simplified expression never returns UNKNOWN, the simplifier
+ * should make this clear to the caller, if possible, by marking its type as
+ * {@code BOOLEAN NOT NULL}. */
+ TRUE,
+
+ /** Policy that indicates that the expression is being used in a context
+ * Where an UNKNOWN value is treated as is. This occurs:
+ *
+ * <ul>
+ * <li>In any expression whose type is not {@code BOOLEAN}
+ * <li>In {@code BOOLEAN} expressions that are {@code NOT NULL}
+ * <li>In {@code BOOLEAN} expressions where {@code UNKNOWN} should be
+ * returned as is, for example in a {@code SELECT} clause, or within an
+ * expression such as an operand to {@code AND}, {@code OR} or
+ * {@code NOT}
+ * </ul>
+ *
+ * <p>If you are unsure, use UNKNOWN. It is the safest option. */
+ UNKNOWN;
+
+ /** Returns {@link #FALSE} if {@code unknownAsFalse} is true,
+ * {@link #UNKNOWN} otherwise. */
+ public static @Nonnull RexUnknownAs falseIf(boolean unknownAsFalse) {
+ return unknownAsFalse ? FALSE : UNKNOWN;
+ }
+
+ public boolean toBoolean() {
+ switch (this) {
+ case FALSE:
+ return false;
+ case TRUE:
+ return true;
+ default:
+ throw new IllegalArgumentException("unknown");
+ }
+ }
+}
+
+// End RexUnknownAs.java