Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions core/src/main/java/org/apache/calcite/plan/Strong.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/** Utilities for strong predicates.
*
* <p>A predicate is strong (or null-rejecting) if it is UNKNOWN if any of its
Expand Down Expand Up @@ -87,7 +85,7 @@ public static boolean isNotTrue(RexNode node, ImmutableBitSet nullColumns) {
/** Returns how to deduce whether a particular kind of expression is null,
* given whether its arguments are null. */
public static Policy policy(SqlKind kind) {
return Objects.requireNonNull(MAP.get(kind), kind.toString());
return MAP.getOrDefault(kind, Policy.AS_IS);
}

/** Returns whether an expression is definitely not true. */
Expand All @@ -106,7 +104,7 @@ public boolean isNotTrue(RexNode node) {
* expressions, and you may override methods to test hypotheses such as
* "if {@code x} is null, is {@code x + y} null? */
public boolean isNull(RexNode node) {
final Policy policy = MAP.get(node.getKind());
final Policy policy = policy(node.getKind());
switch (policy) {
case NOT_NULL:
return false;
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/java/org/apache/calcite/rex/RexInterpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,15 @@ public Comparable visitCall(RexCall call) {
case PLUS:
return containsNull(values) ? N
: number(values.get(0)).add(number(values.get(1)));
case MINUS:
return containsNull(values) ? N
: number(values.get(0)).subtract(number(values.get(1)));
case TIMES:
return containsNull(values) ? N
: number(values.get(0)).multiply(number(values.get(1)));
case DIVIDE:
return containsNull(values) ? N
: number(values.get(0)).divide(number(values.get(1)));
case CAST:
return cast(call, values);
case COALESCE:
Expand Down
15 changes: 12 additions & 3 deletions core/src/main/java/org/apache/calcite/rex/RexSimplify.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.type.SqlTypeUtil;
import org.apache.calcite.util.Bug;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
Expand Down Expand Up @@ -61,7 +62,7 @@ public class RexSimplify {
final boolean unknownAsFalse;
final boolean predicateElimination;
private final RexExecutor executor;

private final Strong strong;
/**
* Creates a RexSimplify.
*
Expand All @@ -85,6 +86,7 @@ private RexSimplify(RexBuilder rexBuilder, RelOptPredicateList predicates,
this.predicateElimination = predicateElimination;
this.paranoid = paranoid;
this.executor = Objects.requireNonNull(executor);
this.strong = new Strong();
}

@Deprecated // to be removed before 2.0
Expand Down Expand Up @@ -176,6 +178,12 @@ public RexNode simplify(RexNode e) {
}

private RexNode simplify_(RexNode e) {
if (strong.isNull(e)) {
if (unknownAsFalse) {
return rexBuilder.makeLiteral(false);
}
return rexBuilder.makeNullLiteral(e.getType());
}
switch (e.getKind()) {
case AND:
return simplifyAnd((RexCall) e);
Expand Down Expand Up @@ -251,7 +259,8 @@ private <C extends Comparable<C>> RexNode simplifyComparison(RexCall e,
// "1 != '1'" is unchanged because the types are not the same.
if (o0.isA(SqlKind.LITERAL)
&& o1.isA(SqlKind.LITERAL)
&& o0.getType().equals(o1.getType())) {
&& SqlTypeUtil.equalSansNullability(rexBuilder.getTypeFactory(),
o0.getType(), o1.getType())) {
final C v0 = ((RexLiteral) o0).getValueAs(clazz);
final C v1 = ((RexLiteral) o1).getValueAs(clazz);
if (v0 == null || v1 == null) {
Expand Down Expand Up @@ -483,7 +492,7 @@ private RexNode simplifyIs2(SqlKind kind, RexNode a) {
final RexNode arg = ((RexCall) a).operands.get(0);
return simplify_(rexBuilder.makeCall(notKind, arg));
}
RexNode a2 = simplify_(a);
RexNode a2 = withUnknownAsFalse(false).simplify_(a);
if (a != a2) {
return rexBuilder.makeCall(RexUtil.op(kind), ImmutableList.of(a2));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1875,7 +1875,7 @@ public void testSkipReduceConstantsCaseEquals() throws Exception {
// Rule should not fire, but there should be no NPE
final String sql =
"select * from (values (1,2)) where 1 + 2 > 3 + CAST(NULL AS INTEGER)";
checkPlanUnchanged(new HepPlanner(program), sql);
checkPlanning(new HepPlanner(program), sql);
}

@Test public void testAlreadyFalseEliminatesFilter() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@ protected RexNode plus(RexNode n1, RexNode n2) {
return rexBuilder.makeCall(SqlStdOperatorTable.PLUS, n1, n2);
}

protected RexNode mul(RexNode n1, RexNode n2) {
return rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, n1, n2);
}

protected RexNode coalesce(RexNode... nodes) {
return rexBuilder.makeCall(SqlStdOperatorTable.COALESCE, nodes);
}
Expand All @@ -296,6 +300,10 @@ protected RexNode divInt(RexNode n1, RexNode n2) {
return rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE_INTEGER, n1, n2);
}

protected RexNode div(RexNode n1, RexNode n2) {
return rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, n1, n2);
}

protected RexNode sub(RexNode n1, RexNode n2) {
return rexBuilder.makeCall(SqlStdOperatorTable.MINUS, n1, n2);
}
Expand Down
18 changes: 18 additions & 0 deletions core/src/test/java/org/apache/calcite/test/RexProgramTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,24 @@ private void checkExponentialCnf(int n) {
"IS NOT NULL(?0.int1)");
}

@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");

checkSimplify2(not(nullBool), "null", "false");
checkSimplify2(ne(vInt(), nullBool), "null", "false");
checkSimplify2(eq(vInt(), nullBool), "null", "false");

checkSimplify2(plus(vInt(), nullInt), "null", "false");
checkSimplify2(sub(vInt(), nullInt), "null", "false");
checkSimplify2(mul(vInt(), nullInt), "null", "false");
checkSimplify2(div(vInt(), nullInt), "null", "false");
}

@Test public void testSimplifyFilter() {
final RelDataType booleanType =
typeFactory.createSqlType(SqlTypeName.BOOLEAN);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5798,8 +5798,7 @@ LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
<Resource name="planAfter">
<![CDATA[
LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
LogicalFilter(condition=[>(+(1, 2), +(3, null))])
LogicalValues(tuples=[[{ 1, 2 }]])
LogicalValues(tuples=[[]])
]]>
</Resource>
</TestCase>
Expand Down
Loading