This is an automated email from the ASF dual-hosted git repository. kgyrtkirk pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push: new c462838 [CALCITE-2838] Simplification: Remove redundant IS TRUE/IS NOT FALSE checks c462838 is described below commit c462838f37f02b490088a216773415926688e9f3 Author: Zoltan Haindrich <k...@rxd.hu> AuthorDate: Thu Feb 14 09:15:31 2019 +0100 [CALCITE-2838] Simplification: Remove redundant IS TRUE/IS NOT FALSE checks Earlier expressions like ((x IS TRUE) IS TRUE) were left as is, the new behaviour recognizes if the IS TRUE/IS NOT FALSE check is redundant. In case ((x IS TRUE) IS TRUE) is a filter expression, it is simplified to 'x'. --- .../java/org/apache/calcite/rex/RexSimplify.java | 46 ++++++++++++---- .../org/apache/calcite/test/RelOptRulesTest.java | 2 +- .../org/apache/calcite/test/RexProgramTest.java | 63 ++++++++++++++++++---- .../calcite/test/fuzzer/RexProgramFuzzyTest.java | 7 +-- .../org/apache/calcite/test/RelOptRulesTest.xml | 18 +++---- core/src/test/resources/sql/blank.iq | 4 +- core/src/test/resources/sql/sub-query.iq | 36 +++---------- 7 files changed, 112 insertions(+), 64 deletions(-) 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 7ae8195..15e3b94 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java +++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java @@ -275,7 +275,7 @@ public class RexSimplify { case IS_FALSE: case IS_NOT_FALSE: assert e instanceof RexCall; - return simplifyIs((RexCall) e); + return simplifyIs((RexCall) e, unknownAs); case EQUALS: case GREATER_THAN: case GREATER_THAN_OR_EQUAL: @@ -534,16 +534,35 @@ public class RexSimplify { return rexBuilder.makeCall(SqlStdOperatorTable.NOT, a2); } - private RexNode simplifyIs(RexCall call) { + private RexNode simplifyIs(RexCall call, RexUnknownAs unknownAs) { final SqlKind kind = call.getKind(); final RexNode a = call.getOperands().get(0); + // UnknownAs.FALSE corresponds to x IS TRUE evaluation + // UnknownAs.TRUE to x IS NOT FALSE + // Note that both UnknownAs.TRUE and UnknownAs.FALSE only changes the meaning of Unknown + // (1) if we are already in UnknownAs.FALSE mode; x IS TRUE can be simiplified to x + // (2) similarily in UnknownAs.TRUE mode ; x IS NOT FALSE can be simplified to x + // (3) x IS FALSE could be rewritten to (NOT x) IS TRUE and from there the 1. rule applies + // (4) x IS NOT TRUE can be rewritten to (NOT x) IS NOT FALSE and from there the 2. rule applies + if (kind == SqlKind.IS_TRUE && unknownAs == RexUnknownAs.FALSE) { + return simplify(a, unknownAs); + } + if (kind == SqlKind.IS_FALSE && unknownAs == RexUnknownAs.FALSE) { + return simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, a), unknownAs); + } + if (kind == SqlKind.IS_NOT_FALSE && unknownAs == RexUnknownAs.TRUE) { + return simplify(a, unknownAs); + } + if (kind == SqlKind.IS_NOT_TRUE && unknownAs == RexUnknownAs.TRUE) { + return simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, a), unknownAs); + } final RexNode pred = simplifyIsPredicate(kind, a); if (pred != null) { return pred; } - final RexNode simplified = simplifyIs2(kind, a); + final RexNode simplified = simplifyIs2(kind, a, unknownAs); if (simplified != null) { return simplified; } @@ -567,21 +586,21 @@ public class RexSimplify { return null; } - private RexNode simplifyIs2(SqlKind kind, RexNode a) { + private RexNode simplifyIs2(SqlKind kind, RexNode a, RexUnknownAs unknownAs) { final RexNode simplified; switch (kind) { case IS_NULL: // x IS NULL ==> FALSE (if x is not nullable) simplified = simplifyIsNull(a); if (simplified != null) { - return simplified; + return simplify(simplified, unknownAs); } break; case IS_NOT_NULL: // x IS NOT NULL ==> TRUE (if x is not nullable) simplified = simplifyIsNotNull(a); if (simplified != null) { - return simplified; + return simplify(simplified, unknownAs); } break; case IS_TRUE: @@ -589,16 +608,21 @@ 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, UNKNOWN); + return simplify(a, unknownAs); + } else { + RexNode newSub = + simplify(a, kind == SqlKind.IS_TRUE ? RexUnknownAs.FALSE : RexUnknownAs.TRUE); + if (newSub == a) { + return null; + } + return rexBuilder.makeCall(RexUtil.op(kind), ImmutableList.of(newSub)); } - break; case IS_FALSE: case IS_NOT_TRUE: // x IS NOT TRUE ==> NOT x (if x is not nullable) // x IS FALSE ==> NOT x (if x is not nullable) if (!a.getType().isNullable()) { - return simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, a), - UNKNOWN); + return simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, a), unknownAs); } break; } @@ -1129,7 +1153,7 @@ public class RexSimplify { for (RexNode notSatisfiableNullable : notSatisfiableNullables) { terms.add( simplifyIs((RexCall) - rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, notSatisfiableNullable))); + rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, notSatisfiableNullable), UNKNOWN)); } } // Add the NOT disjunctions back in. 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 9dca7b1..ef2b705 100644 --- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java @@ -1805,7 +1805,7 @@ public class RelOptRulesTest extends RelOptTestBase { .addRuleInstance(ReduceExpressionsRule.JOIN_INSTANCE) .build(); - checkPlanning(new HepPlanner(program), + checkPlanUnchanged(new HepPlanner(program), "select p1 is not distinct from p0 from (values (2, cast(null as integer))) as t(p0, p1)"); } 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 3234050..b9e9ba0 100644 --- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java +++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java @@ -299,9 +299,8 @@ public class RexProgramTest extends RexProgramBuilderBase { assertThat(program.normalize(rexBuilder, simplify).toString(), is("(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], " + "expr#4=[+($t0, $t3)], expr#5=[+($t2, $t4)], " - + "expr#6=[+($t0, $t4)], expr#7=[5], expr#8=[>($t4, $t7)], " - + "expr#9=[NOT($t8)], " - + "a=[$t5], b=[$t6], $condition=[$t9])")); + + "expr#6=[+($t0, $t4)], expr#7=[5], expr#8=[<=($t4, $t7)], " + + "a=[$t5], b=[$t6], $condition=[$t8])")); } /** @@ -321,9 +320,8 @@ public class RexProgramTest extends RexProgramBuilderBase { assertThat(program.normalize(rexBuilder, simplify).toString(), is("(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], " + "expr#4=[+($t0, $t3)], expr#5=[+($t2, $t4)], " - + "expr#6=[+($t0, $t4)], expr#7=[5], expr#8=[>($t4, $t7)], " - + "expr#9=[NOT($t8)], " - + "a=[$t5], b=[$t6], $condition=[$t9])")); + + "expr#6=[+($t0, $t4)], expr#7=[5], expr#8=[<=($t4, $t7)], " + + "a=[$t5], b=[$t6], $condition=[$t8])")); } /** @@ -1801,7 +1799,7 @@ public class RexProgramTest extends RexProgramBuilderBase { isTrue(vBool()), literal(1), isNotTrue(vBool()), literal(1), literal(2)), - "CASE(OR(IS TRUE(?0.bool0), IS NOT TRUE(?0.bool0)), 1, 2)"); + "CASE(OR(?0.bool0, IS NOT TRUE(?0.bool0)), 1, 2)"); } @Test public void testSimplifyCaseBranchesCollapse2() { @@ -1909,7 +1907,7 @@ public class RexProgramTest extends RexProgramBuilderBase { isTrue(vBool()), vBool(1), gt(div(vIntNotNull(), literal(2)), literal(1)), vBool(2), vBool(3))), - "CASE(IS TRUE(?0.bool0), NOT(?0.bool1), >(/(?0.notNullInt0, 2), 1), NOT(?0.bool2), NOT(?0.bool3))"); + "CASE(?0.bool0, NOT(?0.bool1), >(/(?0.notNullInt0, 2), 1), NOT(?0.bool2), NOT(?0.bool3))"); } @Test public void testNotRecursion() { @@ -2434,9 +2432,13 @@ public class RexProgramTest extends RexProgramBuilderBase { // "NOT(false)" => "true" checkSimplify(not(falseLiteral), "true"); // "NOT(IS FALSE(x))" => "IS NOT FALSE(x)" - checkSimplify(not(isFalse(vBool())), "IS NOT FALSE(?0.bool0)"); + checkSimplify3(not(isFalse(vBool())), + "IS NOT FALSE(?0.bool0)", "IS NOT FALSE(?0.bool0)", "?0.bool0"); // "NOT(IS TRUE(x))" => "IS NOT TRUE(x)" - checkSimplify(not(isTrue(vBool())), "IS NOT TRUE(?0.bool0)"); + checkSimplify3(not(isTrue(vBool())), + "IS NOT TRUE(?0.bool0)", + "IS NOT TRUE(?0.bool0)", + "NOT(?0.bool0)"); // "NOT(IS NULL(x))" => "IS NOT NULL(x)" checkSimplify(not(isNull(vBool())), "IS NOT NULL(?0.bool0)"); // "NOT(IS NOT NULL(x)) => "IS NULL(x)" @@ -2512,6 +2514,47 @@ public class RexProgramTest extends RexProgramBuilderBase { is(false)); } + @Test public void testIsNullRecursion() { + // make sure that simplifcation is visiting below isX expressions + checkSimplify( + isNull(or(coalesce(nullBool, trueLiteral), falseLiteral)), + "false"); + } + + @Test public void testRedundantIsTrue() { + checkSimplify2( + isTrue(isTrue(vBool())), + "IS TRUE(?0.bool0)", + "?0.bool0" + ); + } + + @Test public void testRedundantIsFalse() { + checkSimplify2( + isTrue(isFalse(vBool())), + "IS FALSE(?0.bool0)", + "NOT(?0.bool0)" + ); + } + + @Test public void testRedundantIsNotTrue() { + checkSimplify3( + isNotFalse(isNotTrue(vBool())), + "IS NOT TRUE(?0.bool0)", + "IS NOT TRUE(?0.bool0)", + "NOT(?0.bool0)" + ); + } + + @Test public void testRedundantIsNotFalse() { + checkSimplify3( + isNotFalse(isNotFalse(vBool())), + "IS NOT FALSE(?0.bool0)", + "IS NOT FALSE(?0.bool0)", + "?0.bool0" + ); + } + /** Unit tests for * <a href="https://issues.apache.org/jira/browse/CALCITE-2438">[CALCITE-2438] * RexCall#isAlwaysTrue returns incorrect result</a>. */ 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 4b86f5b..e745d49 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 @@ -262,11 +262,12 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase { } } } - if (opt.getType().isNullable() && !node.getType().isNullable()) { + if (unknownAs == RexUnknownAs.UNKNOWN + && opt.getType().isNullable() + && !node.getType().isNullable()) { fail(nodeToString(node) + " had non-nullable type " + opt.getType() + ", and it was optimized to " + nodeToString(opt) - + " that has nullable type " + opt.getType() - + ", " + uaf); + + " that has nullable type " + opt.getType()); } if (!SqlTypeUtil.equalSansNullability(typeFactory, node.getType(), opt.getType())) { assertEquals(nodeToString(node) + " has different type after simplification to " 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 8c7e46c..5da4200 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -481,7 +481,7 @@ LogicalProject(DEPTNO=[$0]) <![CDATA[ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8]) LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8]) - LogicalFilter(condition=[AND(OR(IS NOT TRUE(<=($0, $9)), =($10, 0)), OR(<=($10, $11), =($10, 0), IS TRUE(<=($0, $9))), OR(>($0, $9), =($10, 0), IS TRUE(<=($0, $9)), >($10, $11)))]) + LogicalFilter(condition=[AND(OR(IS NOT TRUE(<=($0, $9)), =($10, 0)), OR(<=($10, $11), =($10, 0), <=($0, $9)), OR(>($0, $9), =($10, 0), <=($0, $9), >($10, $11)))]) LogicalJoin(condition=[true], joinType=[inner]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) LogicalAggregate(group=[{}], m=[MAX($0)], c=[COUNT()], d=[COUNT($0)]) @@ -493,7 +493,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$ <![CDATA[ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8]) LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8]) - LogicalFilter(condition=[AND(OR(IS NOT TRUE(<=($0, $9)), =($10, 0)), OR(<=($10, $11), =($10, 0), IS TRUE(<=($0, $9))), OR(>($0, $9), =($10, 0), IS TRUE(<=($0, $9)), >($10, $11)))]) + LogicalFilter(condition=[AND(OR(IS NOT TRUE(<=($0, $9)), =($10, 0)), OR(<=($10, $11), =($10, 0), <=($0, $9)), OR(>($0, $9), =($10, 0), <=($0, $9), >($10, $11)))]) LogicalJoin(condition=[true], joinType=[inner]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) LogicalAggregate(group=[{}], m=[MAX($0)], c=[COUNT()], d=[COUNT($0)]) @@ -2241,7 +2241,7 @@ LogicalCalc(expr#0=[{inputs}], expr#1=['TABLE ':VARCHAR(26)], expr#2=['t' </Resource> <Resource name="planBefore"> <![CDATA[ -LogicalProject(EXPR$0=[IS TRUE(null:BOOLEAN)]) +LogicalProject(EXPR$0=[false]) LogicalValues(tuples=[[{ 0 }]]) ]]> </Resource> @@ -2637,7 +2637,7 @@ LogicalFilter(condition=[IS NOT DISTINCT FROM($7, 20)]) </Resource> <Resource name="planAfter"> <![CDATA[ -LogicalFilter(condition=[IS TRUE(=($7, 20))]) +LogicalFilter(condition=[=($7, 20)]) LogicalTableScan(table=[[scott, EMP]]) ]]> </Resource> @@ -4551,7 +4551,7 @@ LogicalAggregate(group=[{}], EXPR$0=[COUNT()]) <![CDATA[ LogicalAggregate(group=[{}], EXPR$0=[COUNT()]) LogicalProject($f0=[0]) - LogicalFilter(condition=[IS TRUE(<($0, 10))]) + LogicalFilter(condition=[<($0, 10)]) LogicalProject(MGR=[$3]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]> @@ -8512,7 +8512,7 @@ LogicalProject(DEPTNO=[$0]) <Resource name="planAfter"> <![CDATA[ LogicalProject(SAL=[$5]) - LogicalFilter(condition=[OR(IS NOT TRUE(OR(IS NOT NULL($13), <($11, $10))), IS TRUE(=($10, 0)))]) + LogicalFilter(condition=[OR(IS NOT TRUE(OR(IS NOT NULL($13), <($11, $10))), =($10, 0))]) LogicalJoin(condition=[AND(=($0, $12), =($2, $14))], joinType=[left]) LogicalJoin(condition=[=($2, $9)], joinType=[left]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) @@ -8527,7 +8527,7 @@ LogicalProject(SAL=[$5]) <![CDATA[ LogicalProject(SAL=[$5]) LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8]) - LogicalFilter(condition=[OR(IS NOT TRUE(OR(IS NOT NULL($12), <($10, $9))), IS TRUE(=($9, 0)))]) + LogicalFilter(condition=[OR(IS NOT TRUE(OR(IS NOT NULL($12), <($10, $9))), =($9, 0))]) LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{2}]) LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{2}]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) @@ -8604,7 +8604,7 @@ LogicalProject(EMPNO=[$1]) <![CDATA[ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8]) LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8]) - LogicalFilter(condition=[OR(IS NOT TRUE(OR(IS NOT NULL($12), <($10, $9))), IS TRUE(=($9, 0)))]) + LogicalFilter(condition=[OR(IS NOT TRUE(OR(IS NOT NULL($12), <($10, $9))), =($9, 0))]) LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{1}]) LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{1}]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) @@ -8623,7 +8623,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$ <Resource name="planAfter"> <![CDATA[ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8]) - LogicalFilter(condition=[OR(IS NOT TRUE(OR(IS NOT NULL($13), <($11, $10))), IS TRUE(=($10, 0)))]) + LogicalFilter(condition=[OR(IS NOT TRUE(OR(IS NOT NULL($13), <($11, $10))), =($10, 0))]) LogicalJoin(condition=[AND(=($0, $12), =($1, $14))], joinType=[left]) LogicalJoin(condition=[=($1, $9)], joinType=[left]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) diff --git a/core/src/test/resources/sql/blank.iq b/core/src/test/resources/sql/blank.iq index 80bfe3d..1cae199 100644 --- a/core/src/test/resources/sql/blank.iq +++ b/core/src/test/resources/sql/blank.iq @@ -73,9 +73,9 @@ insert into table2 values (NULL, 1), (2, 1); # Checked on Oracle !set lateDecorrelate true select i, j from table1 where table1.j NOT IN (select i from table2 where table1.i=table2.j); -EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT NULL($t7)], expr#9=[<($t4, $t3)], expr#10=[OR($t8, $t9)], expr#11=[IS NOT TRUE($t10)], expr#12=[0], expr#13=[=($t3, $t12)], expr#14=[IS TRUE($t13)], expr#15=[IS NULL($t1)], expr#16=[OR($t11, $t14, $t15)], proj#0..1=[{exprs}], $condition=[$t16]) +EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT NULL($t7)], expr#9=[<($t4, $t3)], expr#10=[OR($t8, $t9)], expr#11=[IS NOT TRUE($t10)], expr#12=[0], expr#13=[=($t3, $t12)], expr#14=[IS NULL($t1)], expr#15=[OR($t11, $t13, $t14)], proj#0..1=[{exprs}], $condition=[$t15]) EnumerableJoin(condition=[AND(=($0, $6), =($1, $5))], joinType=[left]) - EnumerableCalc(expr#0..4=[{inputs}], expr#5=[IS NOT NULL($t1)], expr#6=[0], expr#7=[=($t3, $t6)], expr#8=[IS TRUE($t7)], expr#9=[OR($t5, $t8)], proj#0..4=[{exprs}], $condition=[$t9]) + EnumerableCalc(expr#0..4=[{inputs}], expr#5=[IS NOT NULL($t1)], expr#6=[0], expr#7=[=($t3, $t6)], expr#8=[OR($t5, $t7)], proj#0..4=[{exprs}], $condition=[$t8]) EnumerableJoin(condition=[=($0, $2)], joinType=[left]) EnumerableTableScan(table=[[BLANK, TABLE1]]) EnumerableAggregate(group=[{1}], c=[COUNT()], ck=[COUNT($0)]) diff --git a/core/src/test/resources/sql/sub-query.iq b/core/src/test/resources/sql/sub-query.iq index b9f6b3f..c3aa3f2 100644 --- a/core/src/test/resources/sql/sub-query.iq +++ b/core/src/test/resources/sql/sub-query.iq @@ -1440,7 +1440,7 @@ select sal from "scott".emp (0 rows) !ok -EnumerableCalc(expr#0..3=[{inputs}], expr#4=[false], expr#5=[=($t2, $t4)], expr#6=[IS NOT TRUE($t5)], expr#7=[IS NULL($t3)], expr#8=[OR($t6, $t7)], expr#9=[IS TRUE($t5)], expr#10=[OR($t7, $t9)], expr#11=[AND($t8, $t10)], SAL=[$t1], $condition=[$t11]) +EnumerableCalc(expr#0..3=[{inputs}], expr#4=[false], expr#5=[=($t2, $t4)], expr#6=[IS NOT TRUE($t5)], expr#7=[IS NULL($t3)], expr#8=[OR($t6, $t7)], expr#9=[OR($t7, $t5)], expr#10=[AND($t8, $t9)], SAL=[$t1], $condition=[$t10]) EnumerableJoin(condition=[true], joinType=[left]) EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5]) EnumerableTableScan(table=[[scott, EMP]]) @@ -1482,7 +1482,7 @@ select sal from "scott".emp (0 rows) !ok -EnumerableCalc(expr#0..3=[{inputs}], expr#4=[false], expr#5=[=($t2, $t4)], expr#6=[IS NOT TRUE($t5)], expr#7=[IS NULL($t3)], expr#8=[OR($t6, $t7)], expr#9=[IS TRUE($t5)], expr#10=[OR($t7, $t9)], expr#11=[AND($t8, $t10)], SAL=[$t1], $condition=[$t11]) +EnumerableCalc(expr#0..3=[{inputs}], expr#4=[false], expr#5=[=($t2, $t4)], expr#6=[IS NOT TRUE($t5)], expr#7=[IS NULL($t3)], expr#8=[OR($t6, $t7)], expr#9=[OR($t7, $t5)], expr#10=[AND($t8, $t9)], SAL=[$t1], $condition=[$t10]) EnumerableJoin(condition=[true], joinType=[left]) EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5]) EnumerableTableScan(table=[[scott, EMP]]) @@ -1503,7 +1503,7 @@ select sal from "scott".emp (0 rows) !ok -EnumerableCalc(expr#0..3=[{inputs}], expr#4=[false], expr#5=[=($t2, $t4)], expr#6=[IS NOT TRUE($t5)], expr#7=[IS NULL($t3)], expr#8=[OR($t6, $t7)], expr#9=[IS TRUE($t5)], expr#10=[OR($t7, $t9)], expr#11=[AND($t8, $t10)], SAL=[$t1], $condition=[$t11]) +EnumerableCalc(expr#0..3=[{inputs}], expr#4=[false], expr#5=[=($t2, $t4)], expr#6=[IS NOT TRUE($t5)], expr#7=[IS NULL($t3)], expr#8=[OR($t6, $t7)], expr#9=[OR($t7, $t5)], expr#10=[AND($t8, $t9)], SAL=[$t1], $condition=[$t10]) EnumerableJoin(condition=[true], joinType=[left]) EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5]) EnumerableTableScan(table=[[scott, EMP]]) @@ -1524,7 +1524,7 @@ select sal from "scott".emp (0 rows) !ok -EnumerableCalc(expr#0..3=[{inputs}], expr#4=[false], expr#5=[=($t2, $t4)], expr#6=[IS NOT TRUE($t5)], expr#7=[IS NULL($t3)], expr#8=[OR($t6, $t7)], expr#9=[IS TRUE($t5)], expr#10=[OR($t7, $t9)], expr#11=[AND($t8, $t10)], SAL=[$t1], $condition=[$t11]) +EnumerableCalc(expr#0..3=[{inputs}], expr#4=[false], expr#5=[=($t2, $t4)], expr#6=[IS NOT TRUE($t5)], expr#7=[IS NULL($t3)], expr#8=[OR($t6, $t7)], expr#9=[OR($t7, $t5)], expr#10=[AND($t8, $t9)], SAL=[$t1], $condition=[$t10]) EnumerableJoin(condition=[true], joinType=[left]) EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5]) EnumerableTableScan(table=[[scott, EMP]]) @@ -1747,12 +1747,7 @@ select sal from "scott".emp e (0 rows) !ok -EnumerableCalc(expr#0..4=[{inputs}], expr#5=[false], expr#6=[=($t4, $t5)], expr#7=[IS NOT TRUE($t6)], expr#8=[IS TRUE($t6)], expr#9=[AND($t7, $t8)], SAL=[$t1], $condition=[$t9]) - EnumerableJoin(condition=[=($2, $3)], joinType=[left]) - EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7]) - EnumerableTableScan(table=[[scott, EMP]]) - EnumerableCalc(expr#0..2=[{inputs}], expr#3=[false], DEPTNO=[$t0], $f1=[$t3]) - EnumerableTableScan(table=[[scott, DEPT]]) +EnumerableValues(tuples=[[]]) !plan # Test filter literal NOT IN null correlated @@ -1783,12 +1778,7 @@ select sal from "scott".emp e (0 rows) !ok -EnumerableCalc(expr#0..4=[{inputs}], expr#5=[false], expr#6=[=($t4, $t5)], expr#7=[IS NOT TRUE($t6)], expr#8=[IS TRUE($t6)], expr#9=[AND($t7, $t8)], SAL=[$t1], $condition=[$t9]) - EnumerableJoin(condition=[=($2, $3)], joinType=[left]) - EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7]) - EnumerableTableScan(table=[[scott, EMP]]) - EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], DEPTNO=[$t0], $f1=[$t3]) - EnumerableTableScan(table=[[scott, DEPT]]) +EnumerableValues(tuples=[[]]) !plan # Test filter null NOT IN required correlated @@ -1801,12 +1791,7 @@ select sal from "scott".emp e (0 rows) !ok -EnumerableCalc(expr#0..4=[{inputs}], expr#5=[false], expr#6=[=($t4, $t5)], expr#7=[IS NOT TRUE($t6)], expr#8=[IS TRUE($t6)], expr#9=[AND($t7, $t8)], SAL=[$t1], $condition=[$t9]) - EnumerableJoin(condition=[=($2, $3)], joinType=[left]) - EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7]) - EnumerableTableScan(table=[[scott, EMP]]) - EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], DEPTNO=[$t0], $f1=[$t3]) - EnumerableTableScan(table=[[scott, DEPT]]) +EnumerableValues(tuples=[[]]) !plan # Test filter null NOT IN nullable correlated @@ -1819,12 +1804,7 @@ select sal from "scott".emp e (0 rows) !ok -EnumerableCalc(expr#0..4=[{inputs}], expr#5=[false], expr#6=[=($t4, $t5)], expr#7=[IS NOT TRUE($t6)], expr#8=[IS TRUE($t6)], expr#9=[AND($t7, $t8)], SAL=[$t1], $condition=[$t9]) - EnumerableJoin(condition=[=($2, $3)], joinType=[left]) - EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5], DEPTNO=[$t7]) - EnumerableTableScan(table=[[scott, EMP]]) - EnumerableCalc(expr#0..2=[{inputs}], expr#3=[true], DEPTNO=[$t0], $f1=[$t3]) - EnumerableTableScan(table=[[scott, DEPT]]) +EnumerableValues(tuples=[[]]) !plan # Test filter literal NOT IN required correlated