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 2016/06/15 16:39:32 UTC
[4/5] calcite git commit: [CALCITE-1289] RexUtil.simplifyCase()
should account for nullability (Minji Kim)
[CALCITE-1289] RexUtil.simplifyCase() should account for nullability (Minji Kim)
Close apache/calcite#248
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/94051eae
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/94051eae
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/94051eae
Branch: refs/heads/master
Commit: 94051eaed884bd07a03f69ab20c9e1496aac4862
Parents: 7661637
Author: Minji Kim <mi...@dremio.com>
Authored: Fri Jun 10 18:02:58 2016 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jun 14 18:02:59 2016 -0700
----------------------------------------------------------------------
.../java/org/apache/calcite/rex/RexUtil.java | 10 +-
.../org/apache/calcite/test/RexProgramTest.java | 166 +++++++++++++------
2 files changed, 120 insertions(+), 56 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/94051eae/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 e59b018..5f06102 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -1566,7 +1566,15 @@ public class RexUtil {
notTerms.add(pair.e.getKey());
}
}
- return composeDisjunction(rexBuilder, terms, false);
+ RexNode disjunction = composeDisjunction(rexBuilder, terms, false);
+
+ assert call.getType().getSqlTypeName() == disjunction.getType().getSqlTypeName();
+ if (call.getType().isNullable() == disjunction.getType().isNullable()) {
+ return disjunction;
+ } else if (call.getType().isNullable() && !disjunction.getType().isNullable()) {
+ return rexBuilder.ensureType(call.getType(), disjunction, false);
+ }
+ // if call is not nullable, but the disjunction is, we should not use the disjunction.
}
if (newOperands.equals(operands)) {
return call;
http://git-wip-us.apache.org/repos/asf/calcite/blob/94051eae/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 9907959..e142c72 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
@@ -32,6 +32,7 @@ import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexProgram;
import org.apache.calcite.rex.RexProgramBuilder;
import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.ImmutableBitSet;
@@ -60,6 +61,10 @@ public class RexProgramTest {
//~ Instance fields --------------------------------------------------------
private JavaTypeFactory typeFactory;
private RexBuilder rexBuilder;
+ private RexLiteral trueLiteral;
+ private RexLiteral falseLiteral;
+ private RexNode nullLiteral;
+ private RexNode unknownLiteral;
//~ Methods ----------------------------------------------------------------
@@ -74,6 +79,10 @@ public class RexProgramTest {
public void setUp() {
typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
rexBuilder = new RexBuilder(typeFactory);
+ trueLiteral = rexBuilder.makeLiteral(true);
+ falseLiteral = rexBuilder.makeLiteral(false);
+ nullLiteral = rexBuilder.makeNullLiteral(SqlTypeName.INTEGER);
+ unknownLiteral = rexBuilder.makeNullLiteral(SqlTypeName.BOOLEAN);
}
private void checkCnf(RexNode node, String expected) {
@@ -235,7 +244,8 @@ public class RexProgramTest {
is("(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], "
+ "expr#4=[+($t0, $t3)], expr#5=[+($t2, $t4)], "
+ "expr#6=[+($t0, $t4)], expr#7=[5], expr#8=[>($t4, $t7)], "
- + "expr#9=[NOT($t8)], a=[$t5], b=[$t6], $condition=[$t9])"));
+ + "expr#9=[CAST($t8):BOOLEAN], expr#10=[IS FALSE($t9)], "
+ + "a=[$t5], b=[$t6], $condition=[$t10])"));
}
/**
@@ -256,7 +266,8 @@ public class RexProgramTest {
is("(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], "
+ "expr#4=[+($t0, $t3)], expr#5=[+($t2, $t4)], "
+ "expr#6=[+($t0, $t4)], expr#7=[5], expr#8=[>($t4, $t7)], "
- + "expr#9=[NOT($t8)], a=[$t5], b=[$t6], $condition=[$t9])"));
+ + "expr#9=[CAST($t8):BOOLEAN], expr#10=[IS FALSE($t9)], "
+ + "a=[$t5], b=[$t6], $condition=[$t10])"));
}
/**
@@ -391,10 +402,7 @@ public class RexProgramTest {
// $t8 = $t7 AND $t7
t8 =
builder.addExpr(
- rexBuilder.makeCall(
- SqlStdOperatorTable.AND,
- t7,
- t7));
+ and(t7, t7));
builder.addCondition(t8);
builder.addCondition(t7);
break;
@@ -403,12 +411,10 @@ public class RexProgramTest {
// $t7 = 5
t7 = builder.addExpr(c5);
// $t8 = $t2 > $t7 (i.e. (x + 1) > 5)
- t8 =
- builder.addExpr(
- rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN, t2, t7));
+ t8 = builder.addExpr(gt(t2, t7));
// $t9 = true
final RexLocalRef t9 =
- builder.addExpr(rexBuilder.makeLiteral(true));
+ builder.addExpr(trueLiteral);
// $t10 = $t1 is not null (i.e. y is not null)
assert t1 != null;
final RexLocalRef t10 =
@@ -416,19 +422,16 @@ public class RexProgramTest {
rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, t1));
// $t11 = false
final RexLocalRef t11 =
- builder.addExpr(rexBuilder.makeLiteral(false));
+ builder.addExpr(falseLiteral);
// $t12 = unknown
final RexLocalRef t12 =
- builder.addExpr(rexBuilder.makeNullLiteral(SqlTypeName.BOOLEAN));
+ builder.addExpr(unknownLiteral);
// $t13 = case when $t8 then $t9 when $t10 then $t11 else $t12 end
final RexLocalRef t13 =
- builder.addExpr(
- rexBuilder.makeCall(SqlStdOperatorTable.CASE,
- t8, t9, t10, t11, t12));
+ builder.addExpr(case_(t8, t9, t10, t11, t12));
// $t14 = not $t13 (i.e. not case ... end)
final RexLocalRef t14 =
- builder.addExpr(
- rexBuilder.makeCall(SqlStdOperatorTable.NOT, t13));
+ builder.addExpr(not(t13));
// don't add 't14 is true' - that is implicit
if (variant == 3) {
builder.addCondition(t14);
@@ -466,12 +469,6 @@ public class RexProgramTest {
assertThat(strongIf(aRef, c13), is(false));
// literals are strong iff they are always null
- final RexLiteral trueLiteral = rexBuilder.makeLiteral(true);
- final RexLiteral falseLiteral = rexBuilder.makeLiteral(false);
- final RexNode nullLiteral = rexBuilder.makeNullLiteral(SqlTypeName.INTEGER);
- final RexNode unknownLiteral =
- rexBuilder.makeNullLiteral(SqlTypeName.BOOLEAN);
-
assertThat(strongIf(trueLiteral, c), is(false));
assertThat(strongIf(trueLiteral, c13), is(false));
assertThat(strongIf(falseLiteral, c13), is(false));
@@ -480,15 +477,9 @@ public class RexProgramTest {
assertThat(strongIf(unknownLiteral, c13), is(true));
// AND is strong if one of its arguments is strong
- final RexNode andUnknownTrue =
- rexBuilder.makeCall(SqlStdOperatorTable.AND,
- unknownLiteral, trueLiteral);
- final RexNode andTrueUnknown =
- rexBuilder.makeCall(SqlStdOperatorTable.AND,
- trueLiteral, unknownLiteral);
- final RexNode andFalseTrue =
- rexBuilder.makeCall(SqlStdOperatorTable.AND,
- falseLiteral, trueLiteral);
+ final RexNode andUnknownTrue = and(unknownLiteral, trueLiteral);
+ final RexNode andTrueUnknown = and(trueLiteral, unknownLiteral);
+ final RexNode andFalseTrue = and(falseLiteral, trueLiteral);
assertThat(strongIf(andUnknownTrue, c), is(true));
assertThat(strongIf(andTrueUnknown, c), is(true));
@@ -525,11 +516,6 @@ public class RexProgramTest {
rexBuilder.makeExactLiteral(BigDecimal.valueOf(7));
final RexNode hEqSeven = eq(hRef, sevenLiteral);
- final RexLiteral trueLiteral = rexBuilder.makeLiteral(true);
- final RexLiteral falseLiteral = rexBuilder.makeLiteral(false);
- final RexNode unknownLiteral =
- rexBuilder.makeNullLiteral(SqlTypeName.BOOLEAN);
-
checkCnf(aRef, "?0.a");
checkCnf(trueLiteral, "true");
checkCnf(falseLiteral, "false");
@@ -711,11 +697,6 @@ public class RexProgramTest {
rexBuilder.makeExactLiteral(BigDecimal.valueOf(7));
final RexNode hEqSeven = eq(hRef, sevenLiteral);
- final RexLiteral trueLiteral = rexBuilder.makeLiteral(true);
- final RexLiteral falseLiteral = rexBuilder.makeLiteral(false);
- final RexNode unknownLiteral =
- rexBuilder.makeNullLiteral(SqlTypeName.BOOLEAN);
-
// Most of the expressions in testCnf are unaffected by pullFactors.
checkPullFactors(
or(and(aRef, bRef),
@@ -778,19 +759,17 @@ public class RexProgramTest {
final RexNode cRef = rexBuilder.makeFieldAccess(range, 2);
final RexNode dRef = rexBuilder.makeFieldAccess(range, 3);
final RexNode eRef = rexBuilder.makeFieldAccess(range, 4);
- final RexLiteral true_ = rexBuilder.makeLiteral(true);
- final RexLiteral false_ = rexBuilder.makeLiteral(false);
final RexLiteral literal1 = rexBuilder.makeExactLiteral(BigDecimal.ONE);
// and: remove duplicates
checkSimplify(and(aRef, bRef, aRef), "AND(?0.a, ?0.b)");
// and: remove true
- checkSimplify(and(aRef, bRef, true_),
+ checkSimplify(and(aRef, bRef, trueLiteral),
"AND(?0.a, ?0.b)");
// and: false falsifies
- checkSimplify(and(aRef, bRef, false_),
+ checkSimplify(and(aRef, bRef, falseLiteral),
"false");
// and: remove duplicate "not"s
@@ -798,7 +777,7 @@ public class RexProgramTest {
"AND(?0.b, NOT(?0.a), NOT(?0.c))");
// and: "not true" falsifies
- checkSimplify(and(not(aRef), bRef, not(true_)),
+ checkSimplify(and(not(aRef), bRef, not(trueLiteral)),
"false");
// and: flatten and remove duplicates
@@ -817,32 +796,37 @@ public class RexProgramTest {
checkSimplify(or(aRef, bRef, aRef), "OR(?0.a, ?0.b)");
// or: remove false
- checkSimplify(or(aRef, bRef, false_),
+ checkSimplify(or(aRef, bRef, falseLiteral),
"OR(?0.a, ?0.b)");
// or: true makes everything true
- checkSimplify(or(aRef, bRef, true_), "true");
+ checkSimplify(or(aRef, bRef, trueLiteral), "true");
// case: remove false branches
- checkSimplify(case_(eq(bRef, cRef), dRef, false_, aRef, eRef),
+ checkSimplify(case_(eq(bRef, cRef), dRef, falseLiteral, aRef, eRef),
"CASE(=(?0.b, ?0.c), ?0.d, ?0.e)");
// case: true branches become the last branch
checkSimplify(
- case_(eq(bRef, cRef), dRef, true_, aRef, eq(cRef, dRef), eRef, cRef),
+ case_(eq(bRef, cRef), dRef, trueLiteral, aRef, eq(cRef, dRef), eRef, cRef),
"CASE(=(?0.b, ?0.c), ?0.d, ?0.a)");
// case: singleton
- checkSimplify(case_(true_, aRef, eq(cRef, dRef), eRef, cRef), "?0.a");
+ checkSimplify(case_(trueLiteral, aRef, eq(cRef, dRef), eRef, cRef), "?0.a");
// case: form an AND of branches that return true
checkSimplify(
- case_(aRef, true_, bRef, false_, cRef, false_, dRef, true_, false_),
+ case_(aRef, trueLiteral, bRef,
+ falseLiteral, cRef,
+ falseLiteral, dRef, trueLiteral,
+ falseLiteral),
"OR(?0.a, AND(?0.d, NOT(?0.b), NOT(?0.c)))");
checkSimplify(
- case_(aRef, true_, bRef, false_, cRef, false_, dRef, true_, eRef,
- false_, true_),
+ case_(aRef, trueLiteral, bRef,
+ falseLiteral, cRef,
+ falseLiteral, dRef, trueLiteral, eRef,
+ falseLiteral, trueLiteral),
"OR(?0.a, AND(?0.d, NOT(?0.b), NOT(?0.c)), AND(NOT(?0.b), NOT(?0.c), NOT(?0.e)))");
// is null, applied to not-null value
@@ -893,6 +877,78 @@ public class RexProgramTest {
checkSimplifyFilter(and(lt(aRef, literal1), eq(aRef, literal1), ge(aRef, literal1)),
"false");
}
+
+ /** Unit test for
+ * <a href="https://issues.apache.org/jira/browse/CALCITE-1289">[CALCITE-1289]
+ * RexUtil.simplifyCase() should account for nullability</a>. */
+ @Test public void testSimplifyCaseNotNullableBoolean() {
+ RexNode condition = eq(
+ rexBuilder.makeInputRef(
+ typeFactory.createTypeWithNullability(
+ typeFactory.createSqlType(SqlTypeName.VARCHAR), true),
+ 0),
+ rexBuilder.makeLiteral("S"));
+ RexCall caseNode = (RexCall) case_(condition, trueLiteral, falseLiteral);
+
+ RexCall result = (RexCall) RexUtil.simplify(rexBuilder, caseNode, false);
+ assertThat(result.getType().isNullable(), is(false));
+ assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN));
+ assertThat(result.getOperator(), is((SqlOperator) SqlStdOperatorTable.CASE));
+ assertThat(result.getOperands().size(), is((Object) 3));
+ assertThat(result.getOperands().get(0), is(condition));
+ assertThat(result.getOperands().get(1), is((RexNode) trueLiteral));
+ assertThat(result.getOperands().get(2), is((RexNode) falseLiteral));
+ }
+
+ @Test public void testSimplifyCaseNullableBoolean() {
+ RexNode condition = eq(
+ rexBuilder.makeInputRef(
+ typeFactory.createTypeWithNullability(
+ typeFactory.createSqlType(SqlTypeName.VARCHAR), false),
+ 0),
+ rexBuilder.makeLiteral("S"));
+ RexCall caseNode = (RexCall) case_(condition, trueLiteral, falseLiteral);
+
+ RexCall result = (RexCall) RexUtil.simplify(rexBuilder, caseNode, false);
+ assertThat(result.getType().isNullable(), is(false));
+ assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN));
+ assertThat(result, is(condition));
+ }
+
+ @Test public void testSimplifyCaseNullableVarChar() {
+ RexNode condition = eq(
+ rexBuilder.makeInputRef(
+ typeFactory.createTypeWithNullability(
+ typeFactory.createSqlType(SqlTypeName.VARCHAR), false),
+ 0),
+ rexBuilder.makeLiteral("S"));
+ RexLiteral aLiteral = rexBuilder.makeLiteral("A");
+ RexLiteral bLiteral = rexBuilder.makeLiteral("B");
+ RexCall caseNode = (RexCall) case_(condition, aLiteral, bLiteral);
+
+
+ RexCall result = (RexCall) RexUtil.simplify(rexBuilder, caseNode, false);
+ assertThat(result.getType().isNullable(), is(false));
+ assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.CHAR));
+ assertThat(result, is(caseNode));
+ }
+
+ @Test public void testSimplifyAnd() {
+ RelDataType booleanNotNullableType =
+ typeFactory.createTypeWithNullability(
+ typeFactory.createSqlType(SqlTypeName.BOOLEAN), false);
+ RelDataType booleanNullableType =
+ typeFactory.createTypeWithNullability(
+ typeFactory.createSqlType(SqlTypeName.BOOLEAN), true);
+ RexNode andCondition =
+ and(rexBuilder.makeInputRef(booleanNotNullableType, 0),
+ rexBuilder.makeInputRef(booleanNullableType, 1),
+ rexBuilder.makeInputRef(booleanNotNullableType, 2));
+ RexNode result = RexUtil.simplify(rexBuilder, andCondition, false);
+ assertThat(result.getType().isNullable(), is(true));
+ assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN));
+ }
+
}
// End RexProgramTest.java