Repository: calcite Updated Branches: refs/heads/master 0d10336a3 -> 0ea976eed
[CALCITE-2041] When simplifying a nullable expression, allow the result to change type to NOT NULL Enable tests for [CALCITE-1439]. Close apache/calcite#570 Close apache/calcite#563 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/0ea976ee Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/0ea976ee Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/0ea976ee Branch: refs/heads/master Commit: 0ea976eed7ec6a4368c6002025a1eba0377df509 Parents: 0d10336 Author: Slim <[email protected]> Authored: Tue Nov 7 16:13:30 2017 -0800 Committer: Julian Hyde <[email protected]> Committed: Fri Nov 24 20:43:42 2017 -0800 ---------------------------------------------------------------------- .../rel/rules/ReduceExpressionsRule.java | 114 +++++++++++++++---- .../calcite/rel/rules/ValuesReduceRule.java | 3 +- .../java/org/apache/calcite/rex/RexUtil.java | 9 +- .../calcite/sql/test/SqlOperatorBaseTest.java | 10 +- .../apache/calcite/test/RelOptRulesTest.java | 34 +++++- .../calcite/test/RexImplicationCheckerTest.java | 42 ++++++- .../org/apache/calcite/test/RelOptRulesTest.xml | 46 +++++++- 7 files changed, 224 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/0ea976ee/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 b5fd694..47a859c 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 @@ -102,28 +102,34 @@ public abstract class ReduceExpressionsRule extends RelOptRule { * {@link org.apache.calcite.rel.logical.LogicalFilter}. */ public static final ReduceExpressionsRule FILTER_INSTANCE = - new FilterReduceExpressionsRule(LogicalFilter.class, RelFactories.LOGICAL_BUILDER); + new FilterReduceExpressionsRule(LogicalFilter.class, true, + RelFactories.LOGICAL_BUILDER); /** * Singleton rule that reduces constants inside a * {@link org.apache.calcite.rel.logical.LogicalProject}. */ public static final ReduceExpressionsRule PROJECT_INSTANCE = - new ProjectReduceExpressionsRule(LogicalProject.class, RelFactories.LOGICAL_BUILDER); + new ProjectReduceExpressionsRule(LogicalProject.class, true, + RelFactories.LOGICAL_BUILDER); /** * Singleton rule that reduces constants inside a * {@link org.apache.calcite.rel.core.Join}. */ public static final ReduceExpressionsRule JOIN_INSTANCE = - new JoinReduceExpressionsRule(Join.class, RelFactories.LOGICAL_BUILDER); + new JoinReduceExpressionsRule(Join.class, true, + RelFactories.LOGICAL_BUILDER); /** * Singleton rule that reduces constants inside a * {@link org.apache.calcite.rel.logical.LogicalCalc}. */ public static final ReduceExpressionsRule CALC_INSTANCE = - new CalcReduceExpressionsRule(LogicalCalc.class, RelFactories.LOGICAL_BUILDER); + new CalcReduceExpressionsRule(LogicalCalc.class, true, + RelFactories.LOGICAL_BUILDER); + + protected final boolean matchNullability; /** * Rule that reduces constants inside a {@link org.apache.calcite.rel.core.Filter}. @@ -131,10 +137,16 @@ public abstract class ReduceExpressionsRule extends RelOptRule { * an empty {@link org.apache.calcite.rel.core.Values} (if FALSE or NULL). */ public static class FilterReduceExpressionsRule extends ReduceExpressionsRule { - + @Deprecated // to be removed before 2.0 public FilterReduceExpressionsRule(Class<? extends Filter> filterClass, RelBuilderFactory relBuilderFactory) { - super(filterClass, relBuilderFactory, "ReduceExpressionsRule(Filter)"); + this(filterClass, true, relBuilderFactory); + } + + public FilterReduceExpressionsRule(Class<? extends Filter> filterClass, + boolean matchNullability, RelBuilderFactory relBuilderFactory) { + super(filterClass, matchNullability, relBuilderFactory, + "ReduceExpressionsRule(Filter)"); } @Override public void onMatch(RelOptRuleCall call) { @@ -146,7 +158,8 @@ public abstract class ReduceExpressionsRule extends RelOptRule { final RelMetadataQuery mq = call.getMetadataQuery(); final RelOptPredicateList predicates = mq.getPulledUpPredicates(filter.getInput()); - if (reduceExpressions(filter, expList, predicates, true)) { + if (reduceExpressions(filter, expList, predicates, true, + matchNullability)) { assert expList.size() == 1; newConditionExp = expList.get(0); reduced = true; @@ -251,10 +264,16 @@ public abstract class ReduceExpressionsRule extends RelOptRule { * Rule that reduces constants inside a {@link org.apache.calcite.rel.core.Project}. */ public static class ProjectReduceExpressionsRule extends ReduceExpressionsRule { - + @Deprecated // to be removed before 2.0 public ProjectReduceExpressionsRule(Class<? extends Project> projectClass, RelBuilderFactory relBuilderFactory) { - super(projectClass, relBuilderFactory, "ReduceExpressionsRule(Project)"); + this(projectClass, true, relBuilderFactory); + } + + public ProjectReduceExpressionsRule(Class<? extends Project> projectClass, + boolean matchNullability, RelBuilderFactory relBuilderFactory) { + super(projectClass, matchNullability, relBuilderFactory, + "ReduceExpressionsRule(Project)"); } @Override public void onMatch(RelOptRuleCall call) { @@ -264,7 +283,8 @@ public abstract class ReduceExpressionsRule extends RelOptRule { mq.getPulledUpPredicates(project.getInput()); final List<RexNode> expList = Lists.newArrayList(project.getProjects()); - if (reduceExpressions(project, expList, predicates)) { + if (reduceExpressions(project, expList, predicates, false, + matchNullability)) { call.transformTo( call.builder() .push(project.getInput()) @@ -281,10 +301,16 @@ public abstract class ReduceExpressionsRule extends RelOptRule { * Rule that reduces constants inside a {@link org.apache.calcite.rel.core.Join}. */ public static class JoinReduceExpressionsRule extends ReduceExpressionsRule { - + @Deprecated // to be removed before 2.0 public JoinReduceExpressionsRule(Class<? extends Join> joinClass, RelBuilderFactory relBuilderFactory) { - super(joinClass, relBuilderFactory, "ReduceExpressionsRule(Join)"); + this(joinClass, true, relBuilderFactory); + } + + public JoinReduceExpressionsRule(Class<? extends Join> joinClass, + boolean matchNullability, RelBuilderFactory relBuilderFactory) { + super(joinClass, matchNullability, relBuilderFactory, + "ReduceExpressionsRule(Join)"); } @Override public void onMatch(RelOptRuleCall call) { @@ -300,7 +326,8 @@ public abstract class ReduceExpressionsRule extends RelOptRule { final RelOptPredicateList predicates = leftPredicates.union(rexBuilder, rightPredicates.shift(rexBuilder, fieldCount)); - if (!reduceExpressions(join, expList, predicates, true)) { + if (!reduceExpressions(join, expList, predicates, true, + matchNullability)) { return; } if (join instanceof EquiJoin) { @@ -330,10 +357,16 @@ public abstract class ReduceExpressionsRule extends RelOptRule { * Rule that reduces constants inside a {@link org.apache.calcite.rel.core.Calc}. */ public static class CalcReduceExpressionsRule extends ReduceExpressionsRule { - + @Deprecated // to be removed before 2.0 public CalcReduceExpressionsRule(Class<? extends Calc> calcClass, RelBuilderFactory relBuilderFactory) { - super(calcClass, relBuilderFactory, "ReduceExpressionsRule(Calc)"); + this(calcClass, true, relBuilderFactory); + } + + public CalcReduceExpressionsRule(Class<? extends Calc> calcClass, + boolean matchNullability, RelBuilderFactory relBuilderFactory) { + super(calcClass, matchNullability, relBuilderFactory, + "ReduceExpressionsRule(Calc)"); } @Override public void onMatch(RelOptRuleCall call) { @@ -353,7 +386,8 @@ public abstract class ReduceExpressionsRule extends RelOptRule { expandedExprList.add(expr.accept(shuttle)); } final RelOptPredicateList predicates = RelOptPredicateList.EMPTY; - if (reduceExpressions(calc, expandedExprList, predicates)) { + if (reduceExpressions(calc, expandedExprList, predicates, false, + matchNullability)) { final RexProgramBuilder builder = new RexProgramBuilder( calc.getInput().getRowType(), @@ -423,10 +457,20 @@ public abstract class ReduceExpressionsRule extends RelOptRule { * Creates a ReduceExpressionsRule. * * @param clazz class of rels to which this rule should apply + * @param matchNullability Whether to add a CAST when a nullable expression + * reduces to a NOT NULL literal */ protected ReduceExpressionsRule(Class<? extends RelNode> clazz, - RelBuilderFactory relBuilderFactory, String desc) { - super(operand(clazz, any()), relBuilderFactory, desc); + boolean matchNullability, RelBuilderFactory relBuilderFactory, + String description) { + super(operand(clazz, any()), relBuilderFactory, description); + this.matchNullability = matchNullability; + } + + @Deprecated // to be removed before 2.0 + protected ReduceExpressionsRule(Class<? extends RelNode> clazz, + RelBuilderFactory relBuilderFactory, String description) { + this(clazz, true, relBuilderFactory, description); } //~ Methods ---------------------------------------------------------------- @@ -441,21 +485,48 @@ public abstract class ReduceExpressionsRule extends RelOptRule { */ protected static boolean reduceExpressions(RelNode rel, List<RexNode> expList, RelOptPredicateList predicates) { - return reduceExpressions(rel, expList, predicates, false); + return reduceExpressions(rel, expList, predicates, false, true); + } + + @Deprecated // to be removed before 2.0 + protected static boolean reduceExpressions(RelNode rel, List<RexNode> expList, + RelOptPredicateList predicates, boolean unknownAsFalse) { + return reduceExpressions(rel, expList, predicates, unknownAsFalse, true); } /** * Reduces a list of expressions. * + * <p>The {@code matchNullability} flag comes into play when reducing a + * expression whose type is nullable. Suppose we are reducing an expression + * {@code CASE WHEN 'a' = 'a' THEN 1 ELSE NULL END}. Before reduction the + * type is {@code INTEGER} (nullable), but after reduction the literal 1 has + * type {@code INTEGER NOT NULL}. + * + * <p>In some situations it is more important to preserve types; in this + * case you should use {@code matchNullability = true} (which used to be + * the default behavior of this method), and it will cast the literal to + * {@code INTEGER} (nullable). + * + * <p>In other situations, you would rather propagate the new stronger type, + * because it may allow further optimizations later; pass + * {@code matchNullability = false} and no cast will be added, but you may + * need to adjust types elsewhere in the expression tree. + * * @param rel Relational expression * @param expList List of expressions, modified in place * @param predicates Constraints known to hold on input expressions * @param unknownAsFalse Whether UNKNOWN will be treated as FALSE + * @param matchNullability Whether Calcite should add a CAST to a literal + * resulting from simplification and expression if the + * expression had nullable type and the literal is + * NOT NULL * * @return whether reduction found something to change, and succeeded */ protected static boolean reduceExpressions(RelNode rel, List<RexNode> expList, - RelOptPredicateList predicates, boolean unknownAsFalse) { + RelOptPredicateList predicates, boolean unknownAsFalse, + boolean matchNullability) { final RelOptCluster cluster = rel.getCluster(); final RexBuilder rexBuilder = cluster.getRexBuilder(); final RexExecutor executor = @@ -467,7 +538,8 @@ public abstract class ReduceExpressionsRule extends RelOptRule { boolean reduced = reduceExpressionsInternal(rel, simplify, expList, predicates); - final ExprSimplifier simplifier = new ExprSimplifier(simplify); + final ExprSimplifier simplifier = + new ExprSimplifier(simplify, matchNullability); boolean simplified = false; for (int i = 0; i < expList.size(); i++) { RexNode expr2 = simplifier.apply(expList.get(i)); http://git-wip-us.apache.org/repos/asf/calcite/blob/0ea976ee/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java index f7d5b15..b8b02c6 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java @@ -188,7 +188,8 @@ public abstract class ValuesReduceRule extends RelOptRule { // Compute the values they reduce to. final RelOptPredicateList predicates = RelOptPredicateList.EMPTY; - ReduceExpressionsRule.reduceExpressions(values, reducibleExps, predicates); + ReduceExpressionsRule.reduceExpressions(values, reducibleExps, predicates, + false, true); int changeCount = 0; final ImmutableList.Builder<ImmutableList<RexLiteral>> tuplesBuilder = http://git-wip-us.apache.org/repos/asf/calcite/blob/0ea976ee/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 216b27c..1dd0396 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java +++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java @@ -2574,10 +2574,17 @@ public class RexUtil { public static class ExprSimplifier extends RexShuttle { private final RexSimplify simplify; private final Map<RexNode, Boolean> unknownAsFalseMap; + private final boolean matchNullability; + @Deprecated // to be removed before 2.0 public ExprSimplifier(RexSimplify simplify) { + this(simplify, true); + } + + public ExprSimplifier(RexSimplify simplify, boolean matchNullability) { this.simplify = simplify; this.unknownAsFalseMap = new HashMap<>(); + this.matchNullability = matchNullability; } @Override public RexNode visitCall(RexCall call) { @@ -2611,7 +2618,7 @@ public class RexUtil { if (simplifiedNode.getType().equals(call.getType())) { return simplifiedNode; } - return simplify.rexBuilder.makeCast(call.getType(), simplifiedNode, true); + return simplify.rexBuilder.makeCast(call.getType(), simplifiedNode, matchNullability); } } } http://git-wip-us.apache.org/repos/asf/calcite/blob/0ea976ee/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java index 8bd922a..e1c9e9c 100644 --- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java +++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java @@ -1139,11 +1139,13 @@ public abstract class SqlOperatorBaseTest { tester.checkNull("cast(null as boolean)"); } - @Ignore("[CALCITE-1439] Handling errors during constant reduction") + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-1439">[CALCITE-1439] + * Handling errors during constant reduction</a>. */ @Test public void testCastInvalid() { - // Constant reduction kicks in and generates Java constants that throw - // when the class is loaded, thus ExceptionInInitializerError. We don't have - // a fix yet. + // Before CALCITE-1439 was fixed, constant reduction would kick in and + // generate Java constants that throw when the class is loaded, thus + // ExceptionInInitializerError. tester.checkScalarExact("cast('15' as integer)", "INTEGER NOT NULL", "15"); tester.checkFails("cast('15.4' as integer)", "xxx", true); tester.checkFails("cast('15.6' as integer)", "xxx", true); http://git-wip-us.apache.org/repos/asf/calcite/blob/0ea976ee/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java index 53c2c6a..67da90b 100644 --- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java @@ -35,6 +35,7 @@ import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.core.Minus; import org.apache.calcite.rel.core.RelFactories; import org.apache.calcite.rel.core.Union; +import org.apache.calcite.rel.logical.LogicalProject; import org.apache.calcite.rel.logical.LogicalTableModify; import org.apache.calcite.rel.metadata.CachingRelMetadataProvider; import org.apache.calcite.rel.metadata.ChainedRelMetadataProvider; @@ -1876,7 +1877,10 @@ public class RelOptRulesTest extends RelOptTestBase { + " where a - b < 21"); } - @Ignore @Test public void testReduceCase() throws Exception { + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-1439">[CALCITE-1439] + * Handling errors during constant reduction</a>. */ + @Test public void testReduceCase() throws Exception { HepProgram program = new HepProgramBuilder() .addRuleInstance(ReduceExpressionsRule.PROJECT_INSTANCE) .build(); @@ -1890,6 +1894,34 @@ public class RelOptRulesTest extends RelOptTestBase { .check(); } + private void checkReduceNullableToNotNull(ReduceExpressionsRule rule) { + HepProgram program = new HepProgramBuilder() + .addRuleInstance(rule) + .build(); + + final String sql = "select\n" + + " empno + case when 'a' = 'a' then 1 else null end as newcol\n" + + "from emp"; + sql(sql).with(program) + .withProperty(Hook.REL_BUILDER_SIMPLIFY, false) + .check(); + } + + /** Test case that reduces a nullable expression to a NOT NULL literal that + * is cast to nullable. */ + @Test public void testReduceNullableToNotNull() throws Exception { + checkReduceNullableToNotNull(ReduceExpressionsRule.PROJECT_INSTANCE); + } + + /** Test case that reduces a nullable expression to a NOT NULL literal. */ + @Test public void testReduceNullableToNotNull2() throws Exception { + final ReduceExpressionsRule.ProjectReduceExpressionsRule rule = + new ReduceExpressionsRule.ProjectReduceExpressionsRule( + LogicalProject.class, false, + RelFactories.LOGICAL_BUILDER); + checkReduceNullableToNotNull(rule); + } + @Test public void testReduceConstantsIsNull() throws Exception { HepProgram program = new HepProgramBuilder() .addRuleInstance(ReduceExpressionsRule.FILTER_INSTANCE) http://git-wip-us.apache.org/repos/asf/calcite/blob/0ea976ee/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 074a0f8..b42241c 100644 --- a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java +++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java @@ -31,6 +31,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.RexUtil; import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.schema.Schemas; import org.apache.calcite.server.CalciteServerStatement; @@ -51,7 +52,9 @@ import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; +import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** @@ -187,9 +190,9 @@ public class RexImplicationCheckerTest { f.checkNotImplies(node1, node2); final DateString dBeforeEpoch1 = DateString.fromDaysSinceEpoch(-12345); - final DateString dBeforeEpcoh2 = DateString.fromDaysSinceEpoch(-123); + final DateString dBeforeEpoch2 = DateString.fromDaysSinceEpoch(-123); final RexNode nodeBe1 = f.lt(f.dt, f.rexBuilder.makeDateLiteral(dBeforeEpoch1)); - final RexNode nodeBe2 = f.lt(f.dt, f.rexBuilder.makeDateLiteral(dBeforeEpcoh2)); + final RexNode nodeBe2 = f.lt(f.dt, f.rexBuilder.makeDateLiteral(dBeforeEpoch2)); f.checkImplies(nodeBe1, nodeBe2); f.checkNotImplies(nodeBe2, nodeBe1); } @@ -333,6 +336,41 @@ public class RexImplicationCheckerTest { f.checkNotImplies(f.gt(f.i, f.literal(10)), iIsNull); } + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-2041">[CALCITE-2041] + * When simplifying a nullable expression, allow the result to change type to + * NOT NULL</a> and + * {@link org.apache.calcite.rex.RexUtil.ExprSimplifier#matchNullability}. */ + @Test public void testSimplifyCastMatchNullability() { + final Fixture f = new Fixture(); + final RexUtil.ExprSimplifier defaultSimplifier = + new RexUtil.ExprSimplifier(f.simplify, true); + final RexUtil.ExprSimplifier nonMatchingNullabilitySimplifier = + new RexUtil.ExprSimplifier(f.simplify, 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 + // introduced on top of the expression, as nullability of the new expression + // does not match the nullability of the original one. If + // nonMatchingNullabilitySimplifier is used, the CAST is not added and the + // simplified expression only consists of the literal. + final RexNode e = f.cast(f.intRelDataType, f.literal(2014)); + assertThat(defaultSimplifier.apply(e).toString(), + is("CAST(2014):JavaType(class java.lang.Integer)")); + assertThat(nonMatchingNullabilitySimplifier.apply(e).toString(), + is("2014")); + + // In this case, the cast is not nullable. Thus, in both cases, the + // simplified expression only consists of the literal. + RelDataType notNullIntRelDataType = f.typeFactory.createJavaType(int.class); + final RexNode e2 = f.cast(notNullIntRelDataType, + f.cast(notNullIntRelDataType, f.literal(2014))); + assertThat(defaultSimplifier.apply(e2).toString(), + is("2014")); + assertThat(nonMatchingNullabilitySimplifier.apply(e2).toString(), + is("2014")); + } + /** Contains all the nourishment a test case could possibly need. * * <p>We put the data in here, rather than as fields in the test case, so that http://git-wip-us.apache.org/repos/asf/calcite/blob/0ea976ee/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml ---------------------------------------------------------------------- diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml index b8e1131..b1c4852 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -489,11 +489,11 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$ </TestCase> <TestCase name="testDecorrelateUncorrelatedInAndCorrelatedExists"> <Resource name="sql"> - <![CDATA["select * from sales.emp + <![CDATA[select * from sales.emp WHERE job in ( - select job from emp ee where ee.sal=34) -AND EXISTS ( - select * from emp e where emp.deptno = e.deptno)]]> + select job from emp ee where ee.sal=34)AND EXISTS ( + select * from emp e where emp.deptno = e.deptno) +]]> </Resource> <Resource name="planBefore"> <![CDATA[ @@ -6229,6 +6229,44 @@ LogicalAggregate(group=[{0, 1, 2}]) ]]> </Resource> </TestCase> + <TestCase name="testReduceNullableToNotNull"> + <Resource name="sql"> + <![CDATA[select + empno + case when 'a' = 'a' then 1 else null end as newcol +from emp]]> + </Resource> + <Resource name="planBefore"> + <![CDATA[ +LogicalProject(NEWCOL=[+($0, CASE(=('a', 'a'), 1, null))]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + <Resource name="planAfter"> + <![CDATA[ +LogicalProject(NEWCOL=[+($0, CAST(1):INTEGER)]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + </TestCase> + <TestCase name="testReduceNullableToNotNull2"> + <Resource name="sql"> + <![CDATA[select + empno + case when 'a' = 'a' then 1 else null end as newcol +from emp]]> + </Resource> + <Resource name="planBefore"> + <![CDATA[ +LogicalProject(NEWCOL=[+($0, CASE(=('a', 'a'), 1, null))]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + <Resource name="planAfter"> + <![CDATA[ +LogicalProject(NEWCOL=[+($0, 1)]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + </TestCase> <TestCase name="testSemiJoinRule"> <Resource name="sql"> <