Repository: calcite
Updated Branches:
  refs/heads/master 314b5b78b -> b60b67eb8


[CALCITE-2080] Query with NOT IN operator and literal throws AssertionError: 
'Cast for just nullability not allowed' (Volodymyr Vysotskyi)

Alternative fix (in SqlToRelConverter rather than RelOptUtil);
fix query formatting in SqlToRelConverterTest. (Julian Hyde)

Close apache/calcite#579


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/04cbdb2c
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/04cbdb2c
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/04cbdb2c

Branch: refs/heads/master
Commit: 04cbdb2cead5985322db737e1b0b8ce2259a7306
Parents: 314b5b7
Author: Volodymyr Vysotskyi <[email protected]>
Authored: Thu Dec 7 18:26:38 2017 +0200
Committer: Julian Hyde <[email protected]>
Committed: Mon Dec 11 02:11:11 2017 -0800

----------------------------------------------------------------------
 .../rel/rules/FilterProjectTransposeRule.java   |  10 +-
 .../org/apache/calcite/rex/RexSimplify.java     |   5 +-
 .../java/org/apache/calcite/rex/RexUtil.java    |  11 ++
 .../calcite/sql2rel/SqlToRelConverter.java      |   6 +-
 .../calcite/test/SqlToRelConverterTest.java     |  96 +++++++++---------
 .../calcite/test/SqlToRelConverterTest.xml      | 101 ++++++++++++-------
 6 files changed, 134 insertions(+), 95 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
index aaec8a8..3bdb5f5 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/FilterProjectTransposeRule.java
@@ -16,7 +16,6 @@
  */
 package org.apache.calcite.rel.rules;
 
-import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptRuleOperand;
@@ -27,7 +26,6 @@ import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexOver;
-import org.apache.calcite.rex.RexSimplify;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.tools.RelBuilderFactory;
@@ -120,13 +118,9 @@ public class FilterProjectTransposeRule extends RelOptRule 
{
     final RelBuilder relBuilder = call.builder();
     RelNode newFilterRel;
     if (copyFilter) {
-      final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
-      final RexSimplify simplify =
-          new RexSimplify(relBuilder.getRexBuilder(), predicates, false,
-              RexUtil.EXECUTOR);
-      newCondition = simplify.removeNullabilityCast(newCondition);
       newFilterRel = filter.copy(filter.getTraitSet(), project.getInput(),
-          newCondition);
+          RexUtil.removeNullabilityCast(relBuilder.getTypeFactory(),
+              newCondition));
     } else {
       newFilterRel =
           relBuilder.push(project.getInput()).filter(newCondition).build();

http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
----------------------------------------------------------------------
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 cd42c81..34e3814 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -953,10 +953,7 @@ public class RexSimplify {
    *
    * <p>For example, {@code CAST(1 = 0 AS BOOLEAN)} becomes {@code 1 = 0}. */
   public RexNode removeNullabilityCast(RexNode e) {
-    while (RexUtil.isNullabilityCast(rexBuilder.getTypeFactory(), e)) {
-      e = ((RexCall) e).operands.get(0);
-    }
-    return e;
+    return RexUtil.removeNullabilityCast(rexBuilder.getTypeFactory(), e);
   }
 
   private static <C extends Comparable<C>> RexNode processRange(

http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/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 1dd0396..6f467be 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -310,6 +310,17 @@ public class RexUtil {
     return false;
   }
 
+  /** Removes any casts that change nullability but not type.
+   *
+   * <p>For example, {@code CAST(1 = 0 AS BOOLEAN)} becomes {@code 1 = 0}. */
+  public static RexNode removeNullabilityCast(RelDataTypeFactory typeFactory,
+      RexNode node) {
+    while (isNullabilityCast(typeFactory, node)) {
+      node = ((RexCall) node).operands.get(0);
+    }
+    return node;
+  }
+
   /** Creates a map containing each (e, constant) pair that occurs within
    * a predicate list.
    *

http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java 
b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index ede2daf..e1b0d17 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -963,15 +963,17 @@ public class SqlToRelConverter {
     SqlNode newWhere = pushDownNotForIn(bb.scope, where);
     replaceSubQueries(bb, newWhere, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
     final RexNode convertedWhere = bb.convertExpression(newWhere);
+    final RexNode convertedWhere2 =
+        RexUtil.removeNullabilityCast(typeFactory, convertedWhere);
 
     // only allocate filter if the condition is not TRUE
-    if (convertedWhere.isAlwaysTrue()) {
+    if (convertedWhere2.isAlwaysTrue()) {
       return;
     }
 
     final RelFactories.FilterFactory factory =
         RelFactories.DEFAULT_FILTER_FACTORY;
-    final RelNode filter = factory.createFilter(bb.root, convertedWhere);
+    final RelNode filter = factory.createFilter(bb.root, convertedWhere2);
     final RelNode r;
     final CorrelationUse p = getCorrelationUse(bb, filter);
     if (p != null) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index de0b268..6c3651a 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -2371,6 +2371,19 @@ public class SqlToRelConverterTest extends 
SqlToRelTestBase {
     sql(sql).with(getTesterWithDynamicTable()).ok();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2080";>[CALCITE-2080]
+   * Query with NOT IN operator and literal fails throws AssertionError: 'Cast
+   * for just nullability not allowed'</a>. */
+  @Test public void testNotInWithLiteral() {
+    final String sql = "SELECT *\n"
+        + "FROM SALES.NATION\n"
+        + "WHERE n_name NOT IN\n"
+        + "    (SELECT ''\n"
+        + "     FROM SALES.NATION)";
+    sql(sql).with(getTesterWithDynamicTable()).ok();
+  }
+
   /**
    * Test case for Dynamic Table / Dynamic Star support
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-1150";>[CALCITE-1150]</a>
@@ -2570,27 +2583,24 @@ public class SqlToRelConverterTest extends 
SqlToRelTestBase {
         + "    pattern (strt down+ up+)\n"
         + "    define\n"
         + "      down as down.mgr < PREV(down.mgr),\n"
-        + "      up as up.mgr > prev(up.mgr)\n"
-        + "  ) mr";
+        + "      up as up.mgr > prev(up.mgr)) as mr";
     sql(sql).ok();
   }
 
   @Test public void testMatchRecognizeMeasures1() {
     final String sql = "select *\n"
-        + "  from emp match_recognize\n"
-        + "  (\n"
-        + "   partition by job, sal\n"
-        + "   order by job asc, sal desc\n"
-        + "   measures  MATCH_NUMBER() as match_num, "
-        + "   CLASSIFIER() as var_match, "
-        + "   STRT.mgr as start_nw,"
-        + "   LAST(DOWN.mgr) as bottom_nw,"
-        + "   LAST(up.mgr) as end_nw"
-        + "    pattern (strt down+ up+)\n"
-        + "    define\n"
-        + "      down as down.mgr < PREV(down.mgr),\n"
-        + "      up as up.mgr > prev(up.mgr)\n"
-        + "  ) mr";
+        + "from emp match_recognize (\n"
+        + "  partition by job, sal\n"
+        + "  order by job asc, sal desc\n"
+        + "  measures MATCH_NUMBER() as match_num,\n"
+        + "    CLASSIFIER() as var_match,\n"
+        + "    STRT.mgr as start_nw,\n"
+        + "    LAST(DOWN.mgr) as bottom_nw,\n"
+        + "    LAST(up.mgr) as end_nw\n"
+        + "  pattern (strt down+ up+)\n"
+        + "  define\n"
+        + "    down as down.mgr < PREV(down.mgr),\n"
+        + "    up as up.mgr > prev(up.mgr)) as mr";
     sql(sql).ok();
   }
 
@@ -2600,40 +2610,36 @@ public class SqlToRelConverterTest extends 
SqlToRelTestBase {
    * columns</a>. */
   @Test public void testMatchRecognizeMeasures2() {
     final String sql = "select *\n"
-        + "  from emp match_recognize\n"
-        + "  (\n"
-        + "   partition by job\n"
-        + "   order by sal\n"
-        + "   measures  MATCH_NUMBER() as match_num, "
-        + "   CLASSIFIER() as var_match, "
-        + "   STRT.mgr as start_nw,"
-        + "   LAST(DOWN.mgr) as bottom_nw,"
-        + "   LAST(up.mgr) as end_nw"
-        + "    pattern (strt down+ up+)\n"
-        + "    define\n"
-        + "      down as down.mgr < PREV(down.mgr),\n"
-        + "      up as up.mgr > prev(up.mgr)\n"
-        + "  ) mr";
+        + "from emp match_recognize (\n"
+        + "  partition by job\n"
+        + "  order by sal\n"
+        + "  measures MATCH_NUMBER() as match_num,\n"
+        + "    CLASSIFIER() as var_match,\n"
+        + "    STRT.mgr as start_nw,\n"
+        + "    LAST(DOWN.mgr) as bottom_nw,\n"
+        + "    LAST(up.mgr) as end_nw\n"
+        + "  pattern (strt down+ up+)\n"
+        + "  define\n"
+        + "    down as down.mgr < PREV(down.mgr),\n"
+        + "    up as up.mgr > prev(up.mgr)) as mr";
     sql(sql).ok();
   }
 
   @Test public void testMatchRecognizeMeasures3() {
     final String sql = "select *\n"
-        + "  from emp match_recognize\n"
-        + "  (\n"
-        + "   partition by job\n"
-        + "   order by sal\n"
-        + "   measures  MATCH_NUMBER() as match_num, "
-        + "   CLASSIFIER() as var_match, "
-        + "   STRT.mgr as start_nw,"
-        + "   LAST(DOWN.mgr) as bottom_nw,"
-        + "   LAST(up.mgr) as end_nw"
-        + "   ALL ROWS PER MATCH"
-        + "    pattern (strt down+ up+)\n"
-        + "    define\n"
-        + "      down as down.mgr < PREV(down.mgr),\n"
-        + "      up as up.mgr > prev(up.mgr)\n"
-        + "  ) mr";
+        + "from emp match_recognize (\n"
+        + "  partition by job\n"
+        + "  order by sal\n"
+        + "  measures MATCH_NUMBER() as match_num,\n"
+        + "    CLASSIFIER() as var_match,\n"
+        + "    STRT.mgr as start_nw,\n"
+        + "    LAST(DOWN.mgr) as bottom_nw,\n"
+        + "    LAST(up.mgr) as end_nw\n"
+        + "  ALL ROWS PER MATCH\n"
+        + "  pattern (strt down+ up+)\n"
+        + "  define\n"
+        + "    down as down.mgr < PREV(down.mgr),\n"
+        + "    up as up.mgr > prev(up.mgr)) as mr";
     sql(sql).ok();
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/04cbdb2c/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git 
a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml 
b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index c7d2b24..de4a0c1 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -361,7 +361,7 @@ window w as (partition by productId)]]>
     </TestCase>
     <TestCase name="testArrayOfRecord">
         <Resource name="sql">
-            <![CDATA[select*from unnest(array(select*from dept))]]>
+            <![CDATA[select employees[1].skills[2+3].desc from dept_nested]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -648,7 +648,7 @@ LogicalProject(EXPR$0=[CASE(IS NULL($0), IS NOT NULL($1), 
IS NULL($1), IS NOT NU
         <Resource name="sql">
             <![CDATA[select empno is distinct from deptno
 from (values (cast(null as int), 1),
-              (2, cast(null as int))) as emp(empno, deptno)]]>
+             (2, cast(null as int))) as emp(empno, deptno)]]>
         </Resource>
     </TestCase>
     <TestCase name="testIsNotDistinctFrom">
@@ -1511,7 +1511,7 @@ LogicalSort(offset=[10], fetch=[5])
 ]]>
         </Resource>
     </TestCase>
-<TestCase name="testOffsetFetchWithDynamicParameter">
+    <TestCase name="testOffsetFetchWithDynamicParameter">
         <Resource name="sql">
             <![CDATA[select empno from emp
 offset ? rows fetch next ? rows only]]>
@@ -2444,8 +2444,7 @@ LogicalProject(DEPTNO=[$1], EXPR$1=[$2], EXPR$2=[$3], 
EXPR$3=[$4])
     pattern (strt down+ up+)
     define
       down as down.mgr < PREV(down.mgr),
-      up as up.mgr > prev(up.mgr)
-  ) mr]]>
+      up as up.mgr > prev(up.mgr)) as mr]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2458,15 +2457,18 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], 
MGR=[$3], HIREDATE=[$4], SAL=[$
     <TestCase name="testMatchRecognizeMeasures1">
         <Resource name="sql">
             <![CDATA[select *
-  from emp match_recognize
-  (
-   partition by job, sal
-   order by job asc, sal desc
-   measures STRT.mgr as start_nw,   LAST(DOWN.mgr) as bottom_nw,   
LAST(up.mgr) as end_nw    pattern (strt down+ up+)
-    define
-      down as down.mgr < PREV(down.mgr),
-      up as up.mgr > prev(up.mgr)
-  ) mr]]>
+from emp match_recognize (
+  partition by job, sal
+  order by job asc, sal desc
+  measures MATCH_NUMBER() as match_num,
+    CLASSIFIER() as var_match,
+    STRT.mgr as start_nw,
+    LAST(DOWN.mgr) as bottom_nw,
+    LAST(up.mgr) as end_nw
+  pattern (strt down+ up+)
+  define
+    down as down.mgr < PREV(down.mgr),
+    up as up.mgr > prev(up.mgr)) as mr]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2479,15 +2481,18 @@ LogicalProject(JOB=[$0], SAL=[$1], MATCH_NUM=[$2], 
VAR_MATCH=[$3], START_NW=[$4]
     <TestCase name="testMatchRecognizeMeasures2">
         <Resource name="sql">
             <![CDATA[select *
-  from emp match_recognize
-  (
-   partition by job
-   order by sal
-   measures STRT.mgr as start_nw,   LAST(DOWN.mgr) as bottom_nw,   
LAST(up.mgr) as end_nw    pattern (strt down+ up+)
-    define
-      down as down.mgr < PREV(down.mgr),
-      up as up.mgr > prev(up.mgr)
-  ) mr]]>
+from emp match_recognize (
+  partition by job
+  order by sal
+  measures MATCH_NUMBER() as match_num,
+    CLASSIFIER() as var_match,
+    STRT.mgr as start_nw,
+    LAST(DOWN.mgr) as bottom_nw,
+    LAST(up.mgr) as end_nw
+  pattern (strt down+ up+)
+  define
+    down as down.mgr < PREV(down.mgr),
+    up as up.mgr > prev(up.mgr)) as mr]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2500,17 +2505,19 @@ LogicalProject(JOB=[$0], MATCH_NUM=[$1], 
VAR_MATCH=[$2], START_NW=[$3], BOTTOM_N
     <TestCase name="testMatchRecognizeMeasures3">
         <Resource name="sql">
             <![CDATA[select *
-  from emp match_recognize
-  (
-   partition by job
-   order by sal
-   measures STRT.mgr as start_nw,   LAST(DOWN.mgr) as bottom_nw,   
LAST(up.mgr) as end_nw
-   ALL ROWS PER MATCH
-   pattern (strt down+ up+)
-    define
-      down as down.mgr < PREV(down.mgr),
-      up as up.mgr > prev(up.mgr)
-  ) mr]]>
+from emp match_recognize (
+  partition by job
+  order by sal
+  measures MATCH_NUMBER() as match_num,
+    CLASSIFIER() as var_match,
+    STRT.mgr as start_nw,
+    LAST(DOWN.mgr) as bottom_nw,
+    LAST(up.mgr) as end_nw
+  ALL ROWS PER MATCH
+  pattern (strt down+ up+)
+  define
+    down as down.mgr < PREV(down.mgr),
+    up as up.mgr > prev(up.mgr)) as mr]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2543,7 +2550,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], 
MGR=[$3], HIREDATE=[$4], SAL=[$
     <TestCase name="testMatchRecognizePrevDown">
         <Resource name="sql">
             <![CDATA[SELECT *
-FROM tmp
+FROM emp
 MATCH_RECOGNIZE (
   MEASURES
     STRT.mgr AS start_mgr,
@@ -2611,7 +2618,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], 
MGR=[$3], HIREDATE=[$4], SAL=[$
     <TestCase name="testPrevClassifier">
         <Resource name="sql">
             <![CDATA[SELECT *
-FROM tmp
+FROM emp
 MATCH_RECOGNIZE (
   MEASURES
     STRT.mgr AS start_mgr,
@@ -2916,6 +2923,28 @@ LogicalDelta
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testNotInWithLiteral">
+        <Resource name="sql">
+            <![CDATA[SELECT *
+FROM SALES.NATION
+WHERE n_name NOT IN
+    (SELECT ''
+     FROM SALES.NATION)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalProject(**=[$1])
+  LogicalFilter(condition=[NOT(AND(IS TRUE($4), IS NOT NULL($2)))])
+    LogicalJoin(condition=[=($2, $3)], joinType=[left])
+      LogicalProject($f0=[$0], $f1=[$1], $f2=[$0])
+        LogicalTableScan(table=[[CATALOG, SALES, NATION]])
+      LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
+        LogicalProject($f0=[$0], $f1=[true])
+          LogicalProject(EXPR$0=[''])
+            LogicalTableScan(table=[[CATALOG, SALES, NATION]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testSessionTable">
         <Resource name="sql">
             <![CDATA[select stream session_start(rowtime, interval '1' hour) 
as rowtime,

Reply via email to