This is an automated email from the ASF dual-hosted git repository.

jhyde 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 8581f0a  [CALCITE-4562] Improve simplification of "x IS TRUE" and "x 
LIKE '%'"
8581f0a is described below

commit 8581f0a3fe9a4f079cb4d36f02121ae22118714c
Author: Julian Hyde <[email protected]>
AuthorDate: Wed Mar 31 13:37:04 2021 -0700

    [CALCITE-4562] Improve simplification of "x IS TRUE" and "x LIKE '%'"
    
    Simplify "x LIKE '%'" to "x IS NOT NULL" in an unknown-as-false
    context, such as a WHERE clause.
    
    Simplify "x IS TRUE" to "x" if "x" is already NOT NULL;
    similarly "IS FALSE", "IS NOT TRUE", "IS NOT FALSE".
---
 .../org/apache/calcite/rex/RexInterpreter.java     |  20 +++
 .../java/org/apache/calcite/rex/RexSimplify.java   | 148 ++++++++++++++-------
 .../main/java/org/apache/calcite/rex/RexUtil.java  |   5 +-
 .../org/apache/calcite/rex/RexProgramTest.java     |  48 ++++++-
 core/src/test/resources/sql/sub-query.iq           |   8 +-
 5 files changed, 169 insertions(+), 60 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java 
b/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java
index 8a4012e..80adc5c 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java
@@ -219,6 +219,8 @@ public class RexInterpreter implements 
RexVisitor<Comparable> {
       return extract(values);
     case LIKE:
       return like(values);
+    case SIMILAR:
+      return similar(values);
     case SEARCH:
       return search(call.operands.get(1).getType().getSqlTypeName(), values);
     default:
@@ -261,6 +263,24 @@ public class RexInterpreter implements 
RexVisitor<Comparable> {
     }
   }
 
+  private static Comparable similar(List<Comparable> values) {
+    if (containsNull(values)) {
+      return N;
+    }
+    final NlsString value = (NlsString) values.get(0);
+    final NlsString pattern = (NlsString) values.get(1);
+    switch (values.size()) {
+    case 2:
+      return SqlFunctions.similar(value.getValue(), pattern.getValue());
+    case 3:
+      final NlsString escape = (NlsString) values.get(2);
+      return SqlFunctions.similar(value.getValue(), pattern.getValue(),
+          escape.getValue());
+    default:
+      throw new AssertionError();
+    }
+  }
+
   @SuppressWarnings({"BetaApi", "rawtypes", "unchecked", "UnstableApiUsage"})
   private static Comparable search(SqlTypeName typeName, List<Comparable> 
values) {
     final Comparable value = values.get(0);
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 0579025..14337e7 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -306,7 +306,7 @@ public class RexSimplify {
     case SEARCH:
       return simplifySearch((RexCall) e, unknownAs);
     case LIKE:
-      return simplifyLike((RexCall) e);
+      return simplifyLike((RexCall) e, unknownAs);
     case MINUS_PREFIX:
       return simplifyUnaryMinus((RexCall) e, unknownAs);
     case PLUS_PREFIX:
@@ -320,6 +320,63 @@ public class RexSimplify {
     }
   }
 
+  /** Applies NOT to an expression. */
+  RexNode not(RexNode e) {
+    return RexUtil.not(rexBuilder, e);
+  }
+
+  /** Applies IS NOT FALSE to an expression. */
+  RexNode isNotFalse(RexNode e) {
+    return e.isAlwaysTrue()
+        ? rexBuilder.makeLiteral(true)
+        : e.isAlwaysFalse()
+        ? rexBuilder.makeLiteral(false)
+        : e.getKind() == SqlKind.NOT
+        ? isNotTrue(((RexCall) e).operands.get(0))
+        : predicates.isEffectivelyNotNull(e)
+        ? e // would "CAST(e AS BOOLEAN NOT NULL)" better?
+        : rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_FALSE, e);
+  }
+
+  /** Applies IS NOT TRUE to an expression. */
+  RexNode isNotTrue(RexNode e) {
+    return e.isAlwaysTrue()
+        ? rexBuilder.makeLiteral(false)
+        : e.isAlwaysFalse()
+        ? rexBuilder.makeLiteral(true)
+        : e.getKind() == SqlKind.NOT
+        ? isNotFalse(((RexCall) e).operands.get(0))
+        : predicates.isEffectivelyNotNull(e)
+        ? not(e)
+        : rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_TRUE, e);
+  }
+
+  /** Applies IS TRUE to an expression. */
+  RexNode isTrue(RexNode e) {
+    return e.isAlwaysTrue()
+        ? rexBuilder.makeLiteral(true)
+        : e.isAlwaysFalse()
+        ? rexBuilder.makeLiteral(false)
+        : e.getKind() == SqlKind.NOT
+        ? isFalse(((RexCall) e).operands.get(0))
+        : predicates.isEffectivelyNotNull(e)
+        ? e // would "CAST(e AS BOOLEAN NOT NULL)" better?
+        : rexBuilder.makeCall(SqlStdOperatorTable.IS_TRUE, e);
+  }
+
+  /** Applies IS FALSE to an expression. */
+  RexNode isFalse(RexNode e) {
+    return e.isAlwaysTrue()
+        ? rexBuilder.makeLiteral(false)
+        : e.isAlwaysFalse()
+        ? rexBuilder.makeLiteral(true)
+        : e.getKind() == SqlKind.NOT
+        ? isTrue(((RexCall) e).operands.get(0))
+        : predicates.isEffectivelyNotNull(e)
+        ? not(e)
+        : rexBuilder.makeCall(SqlStdOperatorTable.IS_FALSE, e);
+  }
+
   /**
    * Runs simplification inside a non-specialized node.
    */
@@ -332,16 +389,14 @@ public class RexSimplify {
     return rexBuilder.makeCall(e.getType(), e.getOperator(), operands);
   }
 
-  private RexNode simplifyLike(RexCall e) {
+  private RexNode simplifyLike(RexCall e, RexUnknownAs unknownAs) {
     if (e.operands.get(1) instanceof RexLiteral) {
       final RexLiteral literal = (RexLiteral) e.operands.get(1);
       if ("%".equals(literal.getValueAs(String.class))) {
-        RexNode x = e.operands.get(0);
-        // "x LIKE '%'" simplifies to "UNKNOWN OR x IS NOT NULL"
-        return simplify(
-            rexBuilder.makeCall(SqlStdOperatorTable.OR,
-                rexBuilder.makeNullLiteral(e.getType()),
-                rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, x)));
+        // "x LIKE '%'" simplifies to "x = x"
+        final RexNode x = e.operands.get(0);
+        return simplify(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, x, x),
+            unknownAs);
       }
     }
     return simplifyGenericNode(e);
@@ -397,7 +452,7 @@ public class RexSimplify {
             return cmp.ref;
           case LESS_THAN:
           case NOT_EQUALS: // x!=true
-            return simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, 
cmp.ref), unknownAs);
+            return simplify(not(cmp.ref), unknownAs);
           case GREATER_THAN:
             /* this is false, but could be null if x is null */
             if (!cmp.ref.getType().isNullable()) {
@@ -418,7 +473,7 @@ public class RexSimplify {
           switch (cmp.kind) {
           case EQUALS:
           case LESS_THAN_OR_EQUAL:
-            return simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, 
cmp.ref), unknownAs);
+            return simplify(not(cmp.ref), unknownAs);
           case NOT_EQUALS:
           case GREATER_THAN:
             return cmp.ref;
@@ -561,8 +616,7 @@ public class RexSimplify {
       final RexNode t2 = simplify.simplify(t, unknownAs);
       terms.set(i, t2);
       final RexNode inverse =
-          
simplify.simplify(rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_TRUE, t2),
-              RexUnknownAs.UNKNOWN);
+          simplify.simplify(isNotTrue(t2), RexUnknownAs.UNKNOWN);
       final RelOptPredicateList newPredicates = 
simplify.predicates.union(rexBuilder,
           RelOptPredicateList.of(rexBuilder, ImmutableList.of(inverse)));
       simplify = simplify.withPredicates(newPredicates);
@@ -617,9 +671,7 @@ public class RexSimplify {
       // NOT distributivity for AND
       newOperands = new ArrayList<>();
       for (RexNode operand : ((RexCall) a).getOperands()) {
-        newOperands.add(
-            simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, operand),
-                unknownAs));
+        newOperands.add(simplify(not(operand), unknownAs));
       }
       return simplify(
           rexBuilder.makeCall(SqlStdOperatorTable.OR, newOperands), unknownAs);
@@ -628,9 +680,7 @@ public class RexSimplify {
       // NOT distributivity for OR
       newOperands = new ArrayList<>();
       for (RexNode operand : ((RexCall) a).getOperands()) {
-        newOperands.add(
-            simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, operand),
-                unknownAs));
+        newOperands.add(simplify(not(operand), unknownAs));
       }
       return simplify(
           rexBuilder.makeCall(SqlStdOperatorTable.AND, newOperands), 
unknownAs);
@@ -640,10 +690,10 @@ public class RexSimplify {
       List<RexNode> operands = ((RexCall) a).getOperands();
       for (int i = 0; i < operands.size(); i += 2) {
         if (i + 1 == operands.size()) {
-          newOperands.add(rexBuilder.makeCall(SqlStdOperatorTable.NOT, 
operands.get(i)));
+          newOperands.add(not(operands.get(i)));
         } else {
           newOperands.add(operands.get(i));
-          newOperands.add(rexBuilder.makeCall(SqlStdOperatorTable.NOT, 
operands.get(i + 1)));
+          newOperands.add(not(operands.get(i + 1)));
         }
       }
       return simplify(
@@ -673,13 +723,7 @@ public class RexSimplify {
     if (a == a2) {
       return call;
     }
-    if (a2.isAlwaysTrue()) {
-      return rexBuilder.makeLiteral(false);
-    }
-    if (a2.isAlwaysFalse()) {
-      return rexBuilder.makeLiteral(true);
-    }
-    return rexBuilder.makeCall(SqlStdOperatorTable.NOT, a2);
+    return not(a2);
   }
 
   private RexNode simplifyUnaryMinus(RexCall call, RexUnknownAs unknownAs) {
@@ -714,13 +758,13 @@ public class RexSimplify {
       return simplify(a, unknownAs);
     }
     if (kind == SqlKind.IS_FALSE && unknownAs == RexUnknownAs.FALSE) {
-      return simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, a), 
unknownAs);
+      return simplify(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);
+      return simplify(not(a), unknownAs);
     }
     final RexNode pred = simplifyIsPredicate(kind, a);
     if (pred != null) {
@@ -766,28 +810,38 @@ public class RexSimplify {
         return simplified;
       }
       break;
+
     case IS_TRUE:
-    case IS_NOT_FALSE:
       // x IS TRUE ==> x (if x is not nullable)
+      if (predicates.isEffectivelyNotNull(a)) {
+        return simplify(a, unknownAs);
+      }
+      simplified = simplify(a, RexUnknownAs.FALSE);
+      if (simplified == a) {
+        return null;
+      }
+      return isTrue(simplified);
+
+    case IS_NOT_FALSE:
       // x IS NOT FALSE ==> x (if x is not nullable)
       if (predicates.isEffectivelyNotNull(a)) {
         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));
       }
+      simplified = simplify(a, RexUnknownAs.TRUE);
+      if (simplified == a) {
+        return null;
+      }
+      return isNotFalse(simplified);
+
     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 (predicates.isEffectivelyNotNull(a)) {
-        return simplify(rexBuilder.makeCall(SqlStdOperatorTable.NOT, a), 
unknownAs);
+        return simplify(not(a), unknownAs);
       }
       break;
+
     default:
       break;
     }
@@ -1252,7 +1306,7 @@ public class RexSimplify {
     return r.accept(SafeRexVisitor.INSTANCE);
   }
 
-  private static @Nullable RexNode simplifyBooleanCase(RexBuilder rexBuilder,
+  private @Nullable RexNode simplifyBooleanCase(RexBuilder rexBuilder,
       List<CaseBranch> inputBranches, @SuppressWarnings("unused") RexUnknownAs 
unknownAs,
       RelDataType branchType) {
     RexNode result;
@@ -1266,13 +1320,8 @@ public class RexSimplify {
           || !isSafeExpression(branch.value)) {
         return null;
       }
-      RexNode cond;
-      RexNode value;
-      if (branch.cond.getType().isNullable()) {
-        cond = rexBuilder.makeCall(SqlStdOperatorTable.IS_TRUE, branch.cond);
-      } else {
-        cond = branch.cond;
-      }
+      final RexNode cond = isTrue(branch.cond);
+      final RexNode value;
       if (!branchType.equals(branch.value.getType())) {
         value = rexBuilder.makeAbstractCast(branchType, branch.value);
       } else {
@@ -1419,10 +1468,7 @@ public class RexSimplify {
     }
     // Add the NOT disjunctions back in.
     for (RexNode notDisjunction : notTerms) {
-      terms.add(
-          simplify(
-              rexBuilder.makeCall(SqlStdOperatorTable.NOT, notDisjunction),
-              UNKNOWN));
+      terms.add(simplify(not(notDisjunction), UNKNOWN));
     }
     return RexUtil.composeConjunction(rexBuilder, terms);
   }
@@ -1652,7 +1698,7 @@ public class RexSimplify {
     }
     // Add the NOT disjunctions back in.
     for (RexNode notDisjunction : notTerms) {
-      terms.add(rexBuilder.makeCall(SqlStdOperatorTable.NOT, notDisjunction));
+      terms.add(not(notDisjunction));
     }
     // The negated terms: only deterministic expressions
     for (RexNode negatedTerm : negatedTerms) {
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 9d1ff99..cfe0a8f 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -2208,7 +2208,10 @@ public class RexUtil {
     return e -> not(rexBuilder, e);
   }
 
-  /** Applies NOT to an expression. */
+  /** Applies NOT to an expression.
+   *
+   * <p>Unlike {@link #not}, may strengthen the type from {@code BOOLEAN}
+   * to {@code BOOLEAN NOT NULL}. */
   static RexNode not(final RexBuilder rexBuilder, RexNode input) {
     return input.isAlwaysTrue()
         ? rexBuilder.makeLiteral(false)
diff --git a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java 
b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
index 1a8a748..8df9bea 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexProgramTest.java
@@ -2928,6 +2928,11 @@ class RexProgramTest extends RexProgramTestBase {
         "?0.bool0");
   }
 
+  @Test void testSimplifyIsTrue() {
+    final RexNode ref = input(tVarchar(true, 10), 0);
+    checkSimplify(isTrue(like(ref, literal("%"))), "IS NOT NULL($0)");
+  }
+
   /** Unit tests for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2438";>[CALCITE-2438]
    * RexCall#isAlwaysTrue returns incorrect result</a>. */
@@ -3084,16 +3089,51 @@ class RexProgramTest extends RexProgramTestBase {
    * RexSimplify should simplify more always true OR expressions</a>. */
   @Test void testSimplifyLike() {
     final RexNode ref = input(tVarchar(true, 10), 0);
-    checkSimplify(like(ref, literal("%")),
-        "OR(null, IS NOT NULL($0))");
-    checkSimplify(like(ref, literal("%"), literal("#")),
-        "OR(null, IS NOT NULL($0))");
+    checkSimplify3(like(ref, literal("%")),
+        "OR(null, IS NOT NULL($0))", "IS NOT NULL($0)", "true");
+    checkSimplify3(like(ref, literal("%"), literal("#")),
+        "OR(null, IS NOT NULL($0))", "IS NOT NULL($0)", "true");
+    checkSimplify3(
+        or(like(ref, literal("%")),
+            like(ref, literal("% %"))),
+        "OR(null, IS NOT NULL($0), LIKE($0, '% %'))",
+        "OR(IS NOT NULL($0), LIKE($0, '% %'))", "true");
     checkSimplify(or(isNull(ref), like(ref, literal("%"))),
         "true");
     checkSimplify(or(isNull(ref), like(ref, literal("%"), literal("#"))),
         "true");
     checkSimplifyUnchanged(like(ref, literal("%A")));
     checkSimplifyUnchanged(like(ref, literal("%A"), literal("#")));
+
+    // As above, but ref is NOT NULL
+    final RexNode refMandatory = vVarcharNotNull(0);
+    checkSimplify(like(refMandatory, literal("%")), "true");
+    checkSimplify(
+        or(like(refMandatory, literal("%")),
+            like(refMandatory, literal("% %"))), "true");
+
+    // NOT LIKE and NOT SIMILAR TO are not allowed in Rex land
+    try {
+      rexBuilder.makeCall(SqlStdOperatorTable.NOT_LIKE, ref, literal("%"));
+    } catch (AssertionError e) {
+      assertThat(e.getMessage(), is("unsupported negated operator NOT LIKE"));
+    }
+    try {
+      rexBuilder.makeCall(SqlStdOperatorTable.NOT_SIMILAR_TO, ref, 
literal("%"));
+    } catch (AssertionError e) {
+      assertThat(e.getMessage(),
+          is("unsupported negated operator NOT SIMILAR TO"));
+    }
+
+    // NOT(LIKE)
+    checkSimplify3(not(like(ref, literal("%"))),
+        "NOT(OR(null, IS NOT NULL($0)))", "false", "NOT(IS NOT NULL($0))");
+    // SIMILAR TO is not optimized
+    checkSimplifyUnchanged(
+        rexBuilder.makeCall(SqlStdOperatorTable.SIMILAR_TO, ref, 
literal("%")));
+    // NOT(SIMILAR TO) is not optimized
+    checkSimplifyUnchanged(
+        not(rexBuilder.makeCall(SqlStdOperatorTable.SIMILAR_TO, ref, 
literal("%"))));
   }
 
   @Test void testSimplifyNonDeterministicFunction() {
diff --git a/core/src/test/resources/sql/sub-query.iq 
b/core/src/test/resources/sql/sub-query.iq
index a8844be..c158571 100644
--- a/core/src/test/resources/sql/sub-query.iq
+++ b/core/src/test/resources/sql/sub-query.iq
@@ -809,7 +809,7 @@ from "scott".emp;
 (14 rows)
 
 !ok
-EnumerableCalc(expr#0..3=[{inputs}], expr#4=[NOT($t2)], expr#5=[IS TRUE($t4)], 
expr#6=[null:BOOLEAN], expr#7=[IS NOT NULL($t3)], expr#8=[AND($t5, $t6, $t7)], 
expr#9=[IS NOT NULL($t2)], expr#10=[IS NOT FALSE($t2)], expr#11=[AND($t9, $t7, 
$t10)], expr#12=[OR($t8, $t11)], SAL=[$t1], EXPR$1=[$t12])
+EnumerableCalc(expr#0..3=[{inputs}], expr#4=[IS FALSE($t2)], 
expr#5=[null:BOOLEAN], expr#6=[IS NOT NULL($t3)], expr#7=[AND($t4, $t5, $t6)], 
expr#8=[IS NOT NULL($t2)], expr#9=[IS NOT FALSE($t2)], expr#10=[AND($t8, $t6, 
$t9)], expr#11=[OR($t7, $t10)], SAL=[$t1], EXPR$1=[$t11])
   EnumerableNestedLoopJoin(condition=[true], joinType=[left])
     EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5])
       EnumerableTableScan(table=[[scott, EMP]])
@@ -987,7 +987,7 @@ from "scott".emp;
 (14 rows)
 
 !ok
-EnumerableCalc(expr#0..3=[{inputs}], expr#4=[NOT($t2)], expr#5=[IS TRUE($t4)], 
expr#6=[null:BOOLEAN], expr#7=[IS NOT NULL($t3)], expr#8=[AND($t5, $t6, $t7)], 
expr#9=[IS NOT NULL($t2)], expr#10=[IS NOT FALSE($t2)], expr#11=[AND($t9, $t7, 
$t10)], expr#12=[OR($t8, $t11)], SAL=[$t1], EXPR$1=[$t12])
+EnumerableCalc(expr#0..3=[{inputs}], expr#4=[IS FALSE($t2)], 
expr#5=[null:BOOLEAN], expr#6=[IS NOT NULL($t3)], expr#7=[AND($t4, $t5, $t6)], 
expr#8=[IS NOT NULL($t2)], expr#9=[IS NOT FALSE($t2)], expr#10=[AND($t8, $t6, 
$t9)], expr#11=[OR($t7, $t10)], SAL=[$t1], EXPR$1=[$t11])
   EnumerableNestedLoopJoin(condition=[true], joinType=[left])
     EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5])
       EnumerableTableScan(table=[[scott, EMP]])
@@ -1059,7 +1059,7 @@ from "scott".emp;
 (14 rows)
 
 !ok
-EnumerableCalc(expr#0..3=[{inputs}], expr#4=[IS NULL($t3)], expr#5=[NOT($t2)], 
expr#6=[IS TRUE($t5)], expr#7=[null:BOOLEAN], expr#8=[AND($t6, $t7)], 
expr#9=[IS NOT FALSE($t2)], expr#10=[IS NULL($t2)], expr#11=[AND($t9, $t10)], 
expr#12=[OR($t4, $t8, $t11)], SAL=[$t1], EXPR$1=[$t12])
+EnumerableCalc(expr#0..3=[{inputs}], expr#4=[IS NULL($t3)], expr#5=[IS 
FALSE($t2)], expr#6=[null:BOOLEAN], expr#7=[AND($t5, $t6)], expr#8=[IS NOT 
FALSE($t2)], expr#9=[IS NULL($t2)], expr#10=[AND($t8, $t9)], expr#11=[OR($t4, 
$t7, $t10)], SAL=[$t1], EXPR$1=[$t11])
   EnumerableNestedLoopJoin(condition=[true], joinType=[left])
     EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5])
       EnumerableTableScan(table=[[scott, EMP]])
@@ -1237,7 +1237,7 @@ from "scott".emp;
 (14 rows)
 
 !ok
-EnumerableCalc(expr#0..3=[{inputs}], expr#4=[IS NULL($t3)], expr#5=[NOT($t2)], 
expr#6=[IS TRUE($t5)], expr#7=[null:BOOLEAN], expr#8=[AND($t6, $t7)], 
expr#9=[IS NOT FALSE($t2)], expr#10=[IS NULL($t2)], expr#11=[AND($t9, $t10)], 
expr#12=[OR($t4, $t8, $t11)], SAL=[$t1], EXPR$1=[$t12])
+EnumerableCalc(expr#0..3=[{inputs}], expr#4=[IS NULL($t3)], expr#5=[IS 
FALSE($t2)], expr#6=[null:BOOLEAN], expr#7=[AND($t5, $t6)], expr#8=[IS NOT 
FALSE($t2)], expr#9=[IS NULL($t2)], expr#10=[AND($t8, $t9)], expr#11=[OR($t4, 
$t7, $t10)], SAL=[$t1], EXPR$1=[$t11])
   EnumerableNestedLoopJoin(condition=[true], joinType=[left])
     EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], SAL=[$t5])
       EnumerableTableScan(table=[[scott, EMP]])

Reply via email to