Test case for [CALCITE-1493], and clean up test infrastructure

Also, fix a minor performance issue when tracing is disabled.


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

Branch: refs/heads/master
Commit: bac9ee7cb7e76d6307e34091b5a132e3d068dfd7
Parents: 751e2b0
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Nov 30 11:57:20 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Dec 1 20:10:18 2016 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/prepare/Prepare.java     |   6 +-
 .../org/apache/calcite/runtime/FlatLists.java   |  14 +++
 .../org/apache/calcite/test/CalciteAssert.java  |   8 +-
 .../java/org/apache/calcite/test/JdbcTest.java  |   6 +-
 .../apache/calcite/test/RelOptRulesTest.java    | 108 +++++++++++++------
 .../org/apache/calcite/test/RelOptTestBase.java |  84 ++++++++++++---
 .../apache/calcite/test/SqlToRelTestBase.java   |  65 +++++++----
 .../org/apache/calcite/test/RelOptRulesTest.xml |  36 +++++++
 8 files changed, 250 insertions(+), 77 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/main/java/org/apache/calcite/prepare/Prepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/Prepare.java 
b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
index 2064567..aa4ba8b 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -156,8 +156,10 @@ public abstract class Prepare {
     }
 
     final RelNode rootRel4 = program.run(planner, root.rel, desiredTraits);
-    LOGGER.debug("Plan after physical tweaks: {}",
-        RelOptUtil.toString(rootRel4, SqlExplainLevel.ALL_ATTRIBUTES));
+    if (LOGGER.isDebugEnabled()) {
+      LOGGER.debug("Plan after physical tweaks: {}",
+          RelOptUtil.toString(rootRel4, SqlExplainLevel.ALL_ATTRIBUTES));
+    }
 
     return root.withRel(rootRel4);
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/FlatLists.java 
b/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
index 4ab4ef2..73344c4 100644
--- a/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
+++ b/core/src/main/java/org/apache/calcite/runtime/FlatLists.java
@@ -19,6 +19,7 @@ package org.apache.calcite.runtime;
 import org.apache.calcite.util.ImmutableNullableList;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
 import java.util.AbstractList;
 import java.util.ArrayList;
@@ -26,6 +27,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.RandomAccess;
 
@@ -252,6 +254,18 @@ public class FlatLists {
     return FlatLists.of(newList);
   }
 
+  /** Returns a list that consists of a given list plus an element, guaranteed
+   * to be an {@link ImmutableList}. */
+  public static <E> ImmutableList<E> append(ImmutableList<E> list, E e) {
+    return ImmutableList.<E>builder().addAll(list).add(e).build();
+  }
+
+  /** Returns a map that consists of a given map plus an (key, value),
+   * guaranteed to be an {@link ImmutableMap}. */
+  public static <K, V> ImmutableMap<K, V> append(Map<K, V> map, K k, V v) {
+    return ImmutableMap.<K, V>builder().putAll(map).put(k, v).build();
+  }
+
   /** Base class for flat lists. */
   public abstract static class AbstractFlatList<T>
       extends AbstractImmutableList<T> implements RandomAccess {

http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java 
b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
index c5efd87..e0f8a6b 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -28,6 +28,7 @@ import org.apache.calcite.jdbc.CalciteSchema;
 import org.apache.calcite.materialize.Lattice;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.runtime.FlatLists;
 import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.schema.Schema;
 import org.apache.calcite.schema.SchemaPlus;
@@ -1124,10 +1125,9 @@ public class CalciteAssert {
     }
 
     public ConnectionFactory with(String property, Object value) {
-      ImmutableMap.Builder<String, String> b = ImmutableMap.builder();
-      b.putAll(this.map);
-      b.put(property, value.toString());
-      return new MapConnectionFactory(b.build(), postProcessors);
+      return new MapConnectionFactory(
+          FlatLists.append(this.map, property, value.toString()),
+          postProcessors);
     }
 
     public ConnectionFactory with(

http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java 
b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index bc214c2..2740c41 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -99,7 +99,6 @@ import org.apache.calcite.util.Util;
 import com.google.common.base.Function;
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 
 import org.hsqldb.jdbcDriver;
 
@@ -6892,10 +6891,7 @@ public class JdbcTest {
           final Map<String, Table> tableMap = super.getTableMap();
           final Table table = tableMap.get("emps");
           final String tableName = (String) operand.get("tableName");
-          return ImmutableMap.<String, Table>builder()
-              .putAll(tableMap)
-              .put(tableName, table)
-              .build();
+          return FlatLists.append(tableMap, tableName, table);
         }
 
         @Override public boolean isMutable() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/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 74e2b03..3097d47 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -274,8 +274,12 @@ public class RelOptRulesTest extends RelOptTestBase {
     final String sql = "select *\n"
         + "from dept left join emp using (deptno)\n"
         + "where emp.deptno is not null and emp.sal > 100";
-    checkPlanning(tester.withDecorrelation(true).withTrim(true), preProgram,
-        new HepPlanner(program), sql);
+    sql(sql)
+        .withDecorrelation(true)
+        .withTrim(true)
+        .withPre(preProgram)
+        .with(program)
+        .check();
   }
 
   @Test public void testFullOuterJoinSimplificationToLeftOuter() {
@@ -500,12 +504,16 @@ public class RelOptRulesTest extends RelOptTestBase {
         HepProgram.builder()
             .addRuleInstance(SemiJoinRule.INSTANCE)
             .build();
-    checkPlanning(tester.withDecorrelation(true).withTrim(true), preProgram,
-        new HepPlanner(program),
-        "select * from dept where exists (\n"
-            + "  select * from emp\n"
-            + "  where emp.deptno = dept.deptno\n"
-            + "  and emp.sal > 100)");
+    final String sql = "select * from dept where exists (\n"
+        + "  select * from emp\n"
+        + "  where emp.deptno = dept.deptno\n"
+        + "  and emp.sal > 100)";
+    sql(sql)
+        .withDecorrelation(true)
+        .withTrim(true)
+        .withPre(preProgram)
+        .with(program)
+        .check();
   }
 
   /** Test case for
@@ -523,11 +531,16 @@ public class RelOptRulesTest extends RelOptTestBase {
             .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN)
             .addRuleInstance(FilterJoinRule.JOIN)
             .build();
-    checkPlanning(tester.withDecorrelation(true).withTrim(false), preProgram,
-        new HepPlanner(program),
-        "select * from (select * from dept where dept.deptno in (\n"
-            + "  select emp.deptno from emp\n"
-            + "  ))R where R.deptno <=10 ");
+    final String sql = "select * from (\n"
+        + "  select * from dept where dept.deptno in (\n"
+        + "    select emp.deptno from emp))R\n"
+        + "where R.deptno <=10";
+    sql(sql)
+        .withDecorrelation(true)
+        .withTrim(false)
+        .withPre(preProgram)
+        .with(program)
+        .check();
   }
 
   /** Test case for
@@ -545,8 +558,12 @@ public class RelOptRulesTest extends RelOptTestBase {
         + "from (select * from emp where deptno = 200) as e1\n"
         + "where e1.deptno in (\n"
         + "  select e2.deptno from emp e2 where e2.sal = 100)";
-    checkPlanning(tester.withDecorrelation(false).withTrim(true), preProgram,
-        new HepPlanner(program), sql, true);
+    sql(sql)
+        .withDecorrelation(false)
+        .withTrim(true)
+        .withPre(preProgram)
+        .with(program)
+        .checkUnchanged();
   }
 
   @Test public void testSemiJoinTrim() {
@@ -1973,7 +1990,6 @@ public class RelOptRulesTest extends RelOptTestBase {
 
   @Test public void testPullConstantThroughUnion()
       throws Exception {
-    HepProgram preProgram = HepProgram.builder().build();
     HepProgram program = HepProgram.builder()
         .addRuleInstance(UnionPullUpConstantsRule.INSTANCE)
         .addRuleInstance(ProjectMergeRule.INSTANCE)
@@ -1981,7 +1997,10 @@ public class RelOptRulesTest extends RelOptTestBase {
     final String sql = "select 2, deptno, job from emp as e1\n"
         + "union all\n"
         + "select 2, deptno, job from emp as e2";
-    checkPlanning(tester.withTrim(true), preProgram, new HepPlanner(program), 
sql);
+    sql(sql)
+        .withTrim(true)
+        .with(program)
+        .check();
   }
 
   @Test public void testPullConstantThroughUnion2()
@@ -2000,7 +2019,6 @@ public class RelOptRulesTest extends RelOptTestBase {
   @Test public void testPullConstantThroughUnion3()
       throws Exception {
     // We should leave at least a single column in each Union input
-    HepProgram preProgram = HepProgram.builder().build();
     HepProgram program = HepProgram.builder()
         .addRuleInstance(UnionPullUpConstantsRule.INSTANCE)
         .addRuleInstance(ProjectMergeRule.INSTANCE)
@@ -2008,7 +2026,10 @@ public class RelOptRulesTest extends RelOptTestBase {
     final String sql = "select 2, 3 from emp as e1\n"
         + "union all\n"
         + "select 2, 3 from emp as e2";
-    checkPlanning(tester.withTrim(true), preProgram, new HepPlanner(program), 
sql);
+    sql(sql)
+        .withTrim(true)
+        .with(program)
+        .check();
   }
 
   @Test public void testAggregateProjectMerge() throws Exception {
@@ -2257,8 +2278,6 @@ public class RelOptRulesTest extends RelOptTestBase {
    * <a href="https://issues.apache.org/jira/browse/CALCITE-841";>[CALCITE-841]
    * Redundant windows when window function arguments are expressions</a>. */
   @Test public void testExpressionInWindowFunction() {
-    HepProgram preProgram =  new HepProgramBuilder().build();
-
     HepProgramBuilder builder = new HepProgramBuilder();
     builder.addRuleClass(ProjectToWindowRule.class);
 
@@ -2269,16 +2288,15 @@ public class RelOptRulesTest extends RelOptTestBase {
         + " sum(deptno) over(partition by deptno order by sal) as sum1,\n"
         + "sum(deptno + sal) over(partition by deptno order by sal) as sum2\n"
         + "from emp";
-    checkPlanning(tester, preProgram, hepPlanner, sql);
+    sql(sql)
+        .with(hepPlanner)
+        .check();
   }
 
   /** Test case for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-888";>[CALCITE-888]
    * Overlay window loses PARTITION BY list</a>. */
   @Test public void testWindowInParenthesis() {
-    HepProgram preProgram =  new HepProgramBuilder()
-        .build();
-
     HepProgramBuilder builder = new HepProgramBuilder();
     builder.addRuleClass(ProjectToWindowRule.class);
     HepPlanner hepPlanner = new HepPlanner(builder.build());
@@ -2287,7 +2305,9 @@ public class RelOptRulesTest extends RelOptTestBase {
     final String sql = "select count(*) over (w), count(*) over w\n"
         + "from emp\n"
         + "window w as (partition by empno order by empno)";
-    checkPlanning(tester, preProgram, hepPlanner, sql);
+    sql(sql)
+        .with(hepPlanner)
+        .check();
   }
 
   /** Test case for
@@ -2479,7 +2499,8 @@ public class RelOptRulesTest extends RelOptTestBase {
    * Wrong collation trait in SortJoinTransposeRule for right joins</a>. */
   @Test public void testSortJoinTranspose4() {
     // Create a customized test with RelCollation trait in the test cluster.
-    Tester tester = new TesterImpl(getDiffRepos(), true, true, false, null, 
null) {
+    Tester tester = new TesterImpl(getDiffRepos(), true, true, false, false,
+        null, null) {
       @Override public RelOptPlanner createPlanner() {
         return new MockRelOptPlanner() {
           @Override public List<RelTraitDef> getRelTraitDefs() {
@@ -2591,6 +2612,18 @@ public class RelOptRulesTest extends RelOptTestBase {
     checkSubQuery(sql).check();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-1493";>[CALCITE-1493]
+   * Wrong plan for NOT IN correlated queries</a>. */
+  @Ignore("[CALCITE-1493] is not fixed yet")
+  @Test public void testWhereNotInCorrelated() {
+    final String sql = "select sal from emp\n"
+        + "where empno NOT IN (\n"
+        + "  select deptno from dept\n"
+        + "  where emp.job = dept.name)";
+    checkSubQuery(sql).withLateDecorrelation(false).check();
+  }
+
   @Test public void testExpandProjectIn() throws Exception {
     final String sql = "select empno,\n"
         + "  deptno in (select deptno from sales.emp where empno < 20) as d\n"
@@ -2754,8 +2787,11 @@ public class RelOptRulesTest extends RelOptTestBase {
         .addRuleInstance(SubQueryRemoveRule.FILTER)
         .addRuleInstance(SubQueryRemoveRule.JOIN)
         .build();
-    final Tester tester = this.tester.withTrim(true).withExpand(false);
-    checkPlanning(tester, null, new HepPlanner(program), sql);
+    sql(sql)
+        .withTrim(true)
+        .expand(false)
+        .with(program)
+        .check();
   }
 
   @Test public void testCustomColumnResolvingInCorrelatedSubQuery() {
@@ -2768,8 +2804,11 @@ public class RelOptRulesTest extends RelOptTestBase {
         .addRuleInstance(SubQueryRemoveRule.FILTER)
         .addRuleInstance(SubQueryRemoveRule.JOIN)
         .build();
-    final Tester tester = this.tester.withTrim(true).withExpand(false);
-    checkPlanning(tester, null, new HepPlanner(program), sql);
+    sql(sql)
+        .withTrim(true)
+        .expand(false)
+        .with(program)
+        .check();
   }
 
   @Test public void testCustomColumnResolvingInCorrelatedSubQuery2() {
@@ -2782,8 +2821,11 @@ public class RelOptRulesTest extends RelOptTestBase {
         .addRuleInstance(SubQueryRemoveRule.FILTER)
         .addRuleInstance(SubQueryRemoveRule.JOIN)
         .build();
-    final Tester tester = this.tester.withTrim(true).withExpand(false);
-    checkPlanning(tester, null, new HepPlanner(program), sql);
+    sql(sql)
+        .withTrim(true)
+        .expand(false)
+        .with(program)
+        .check();
   }
 
   /** Test case for

http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java 
b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
index 4c57833..277d368 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
@@ -27,10 +27,13 @@ import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.metadata.ChainedRelMetadataProvider;
 import org.apache.calcite.rel.metadata.DefaultRelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelMetadataProvider;
+import org.apache.calcite.runtime.FlatLists;
 import org.apache.calcite.runtime.Hook;
+import org.apache.calcite.sql2rel.RelDecorrelator;
 import org.apache.calcite.util.Closer;
 
 import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 
@@ -160,8 +163,11 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
 
     planner.setRoot(relBefore);
     RelNode relAfter = planner.findBestExp();
-
     String planAfter = NL + RelOptUtil.toString(relAfter);
+    if (tester.isLateDecorrelate()) {
+      relAfter = RelDecorrelator.decorrelateQuery(relAfter);
+      planAfter = NL + RelOptUtil.toString(relAfter);
+    }
     if (unchanged) {
       assertThat(planAfter, is(planBefore));
     } else {
@@ -176,7 +182,9 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
 
   /** Sets the SQL statement for a test. */
   Sql sql(String sql) {
-    return new Sql(sql, null, null, true, ImmutableMap.<Hook, Function>of());
+    return new Sql(sql, null, null,
+        ImmutableMap.<Hook, Function>of(),
+        ImmutableList.<Function<Tester, Tester>>of());
   }
 
   /** Allows fluent testing. */
@@ -184,47 +192,88 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
     private final String sql;
     private HepProgram preProgram;
     private final HepPlanner hepPlanner;
-    private final boolean expand;
     private final ImmutableMap<Hook, Function> hooks;
+    private ImmutableList<Function<Tester, Tester>> transforms;
 
     Sql(String sql, HepProgram preProgram, HepPlanner hepPlanner,
-        boolean expand, ImmutableMap<Hook, Function> hooks) {
+        ImmutableMap<Hook, Function> hooks,
+        ImmutableList<Function<Tester, Tester>> transforms) {
       this.sql = sql;
       this.preProgram = preProgram;
       this.hepPlanner = hepPlanner;
-      this.expand = expand;
       this.hooks = hooks;
+      this.transforms = transforms;
     }
 
     public Sql withPre(HepProgram preProgram) {
-      return new Sql(sql, preProgram, hepPlanner, expand, hooks);
+      return new Sql(sql, preProgram, hepPlanner, hooks, transforms);
     }
 
     public Sql with(HepPlanner hepPlanner) {
-      return new Sql(sql, preProgram, hepPlanner, expand, hooks);
+      return new Sql(sql, preProgram, hepPlanner, hooks, transforms);
     }
 
     public Sql with(HepProgram program) {
-      return new Sql(sql, preProgram, new HepPlanner(program), expand, hooks);
+      return new Sql(sql, preProgram, new HepPlanner(program), hooks,
+          transforms);
+    }
+
+    /** Adds a transform that will be applied to {@link #tester}
+     * just before running the query. */
+    private Sql withTransform(Function<Tester, Tester> transform) {
+      return new Sql(sql, preProgram, hepPlanner, hooks,
+          FlatLists.append(transforms, transform));
     }
 
     /** Adds a hook and a handler for that hook. Calcite will create a thread
      * hook (by calling {@link 
Hook#addThread(com.google.common.base.Function)})
      * just before running the query, and remove the hook afterwards. */
     public <T> Sql withHook(Hook hook, Function<T, Void> handler) {
-      return new Sql(sql, preProgram, hepPlanner, expand,
-          ImmutableMap.<Hook, Function>builder().putAll(hooks)
-              .put(hook, handler).build());
+      return new Sql(sql, preProgram, hepPlanner,
+          FlatLists.append(hooks, hook, handler), transforms);
     }
 
     public <V> Sql withProperty(Hook hook, V value) {
       return withHook(hook, Hook.property(value));
     }
 
-    public Sql expand(boolean expand) {
-      return new Sql(sql, preProgram, hepPlanner, expand, hooks);
+    public Sql expand(final boolean b) {
+      return withTransform(
+          new Function<Tester, Tester>() {
+            public Tester apply(Tester tester) {
+              return tester.withExpand(b);
+            }
+          });
+    }
+
+    public Sql withLateDecorrelation(final boolean b) {
+      return withTransform(
+          new Function<Tester, Tester>() {
+            public Tester apply(Tester tester) {
+              return tester.withLateDecorrelation(b);
+            }
+          });
+    }
+
+    public Sql withDecorrelation(final boolean b) {
+      return withTransform(
+          new Function<Tester, Tester>() {
+            public Tester apply(Tester tester) {
+              return tester.withDecorrelation(b);
+            }
+          });
+    }
+
+    public Sql withTrim(final boolean b) {
+      return withTransform(
+          new Function<Tester, Tester>() {
+            public Tester apply(Tester tester) {
+              return tester.withTrim(b);
+            }
+          });
     }
 
+
     public void check() {
       check(false);
     }
@@ -238,11 +287,16 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
         for (Map.Entry<Hook, Function> entry : hooks.entrySet()) {
           closer.add(entry.getKey().addThread(entry.getValue()));
         }
-        checkPlanning(tester.withExpand(expand), preProgram, hepPlanner, sql,
-            unchanged);
+        Tester t = tester;
+        for (Function<Tester, Tester> transform : transforms) {
+          t = transform.apply(t);
+        }
+        checkPlanning(t, preProgram, hepPlanner, sql, unchanged);
       }
     }
+
   }
+
 }
 
 // End RelOptTestBase.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java 
b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
index 166db72..3cfbf35 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -93,7 +93,8 @@ public abstract class SqlToRelTestBase {
   }
 
   protected Tester createTester() {
-    return new TesterImpl(getDiffRepos(), false, false, true, null, null);
+    return new TesterImpl(getDiffRepos(), false, false, true, false, null,
+        null);
   }
 
   /**
@@ -210,6 +211,10 @@ public abstract class SqlToRelTestBase {
     /** Returns a tester that optionally decorrelates queries. */
     Tester withDecorrelation(boolean enable);
 
+    /** Returns a tester that optionally decorrelates queries after planner
+     * rules have fired. */
+    Tester withLateDecorrelation(boolean enable);
+
     /** Returns a tester that optionally expands sub-queries.
      * If {@code expand} is false, the plan contains a
      * {@link org.apache.calcite.rex.RexSubQuery} for each sub-query.
@@ -228,6 +233,8 @@ public abstract class SqlToRelTestBase {
     Tester withTrim(boolean enable);
 
     Tester withClusterFactory(Function<RelOptCluster, RelOptCluster> function);
+
+    boolean isLateDecorrelate();
   }
 
   //~ Inner Classes ----------------------------------------------------------
@@ -466,6 +473,7 @@ public abstract class SqlToRelTestBase {
     private SqlOperatorTable opTab;
     private final DiffRepository diffRepos;
     private final boolean enableDecorrelate;
+    private final boolean enableLateDecorrelate;
     private final boolean enableTrim;
     private final boolean enableExpand;
     private final Function<RelDataTypeFactory, Prepare.CatalogReader>
@@ -486,15 +494,18 @@ public abstract class SqlToRelTestBase {
      */
     protected TesterImpl(DiffRepository diffRepos, boolean enableDecorrelate,
         boolean enableTrim, boolean enableExpand,
+        boolean enableLateDecorrelate,
         Function<RelDataTypeFactory, Prepare.CatalogReader>
             catalogReaderFactory,
         Function<RelOptCluster, RelOptCluster> clusterFactory) {
       this(diffRepos, enableDecorrelate, enableTrim, enableExpand,
-          catalogReaderFactory, clusterFactory, 
SqlToRelConverter.Config.DEFAULT);
+          enableLateDecorrelate, catalogReaderFactory, clusterFactory,
+          SqlToRelConverter.Config.DEFAULT);
     }
 
     protected TesterImpl(DiffRepository diffRepos, boolean enableDecorrelate,
         boolean enableTrim, boolean enableExpand,
+        boolean enableLateDecorrelate,
         Function<RelDataTypeFactory, Prepare.CatalogReader>
             catalogReaderFactory,
         Function<RelOptCluster, RelOptCluster> clusterFactory,
@@ -503,6 +514,7 @@ public abstract class SqlToRelTestBase {
       this.enableDecorrelate = enableDecorrelate;
       this.enableTrim = enableTrim;
       this.enableExpand = enableExpand;
+      this.enableLateDecorrelate = enableLateDecorrelate;
       this.catalogReaderFactory = catalogReaderFactory;
       this.clusterFactory = clusterFactory;
       this.config = config;
@@ -689,44 +701,61 @@ public abstract class SqlToRelTestBase {
       return createValidator(catalogReader, typeFactory);
     }
 
-    public TesterImpl withDecorrelation(boolean enable) {
-      return this.enableDecorrelate == enable
+    public TesterImpl withDecorrelation(boolean enableDecorrelate) {
+      return this.enableDecorrelate == enableDecorrelate
+          ? this
+          : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
+              enableExpand, enableLateDecorrelate, catalogReaderFactory,
+              clusterFactory);
+    }
+
+    public Tester withLateDecorrelation(boolean enableLateDecorrelate) {
+      return this.enableLateDecorrelate == enableLateDecorrelate
           ? this
-          : new TesterImpl(diffRepos, enable, enableTrim, enableExpand,
-              catalogReaderFactory, clusterFactory);
+          : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
+              enableExpand, enableLateDecorrelate, catalogReaderFactory,
+              clusterFactory);
     }
 
     public TesterImpl withConfig(SqlToRelConverter.Config config) {
       return this.config == config
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
-              enableExpand, catalogReaderFactory, clusterFactory, config);
+              enableExpand, enableLateDecorrelate, catalogReaderFactory,
+              clusterFactory, config);
     }
 
-    public Tester withTrim(boolean enable) {
-      return this.enableTrim == enable
+    public Tester withTrim(boolean enableTrim) {
+      return this.enableTrim == enableTrim
           ? this
-          : new TesterImpl(diffRepos, enableDecorrelate, enable, enableExpand,
-              catalogReaderFactory, clusterFactory);
+          : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
+              enableExpand, enableLateDecorrelate, catalogReaderFactory,
+              clusterFactory);
     }
 
-    public Tester withExpand(boolean expand) {
-      return this.enableExpand == expand
+    public Tester withExpand(boolean enableExpand) {
+      return this.enableExpand == enableExpand
           ? this
-          : new TesterImpl(diffRepos, enableDecorrelate, enableTrim, expand,
-              catalogReaderFactory, clusterFactory);
+          : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
+              enableExpand, enableLateDecorrelate, catalogReaderFactory,
+              clusterFactory);
     }
 
     public Tester withCatalogReaderFactory(
         Function<RelDataTypeFactory, Prepare.CatalogReader> factory) {
-      return new TesterImpl(diffRepos, enableDecorrelate, false, enableExpand,
-          factory, clusterFactory);
+      return new TesterImpl(diffRepos, enableDecorrelate, false,
+          enableExpand, enableLateDecorrelate, factory,
+          clusterFactory);
     }
 
     public Tester withClusterFactory(
         Function<RelOptCluster, RelOptCluster> clusterFactory) {
       return new TesterImpl(diffRepos, enableDecorrelate, false, enableExpand,
-          catalogReaderFactory, clusterFactory);
+          enableLateDecorrelate, catalogReaderFactory, clusterFactory);
+    }
+
+    public boolean isLateDecorrelate() {
+      return enableLateDecorrelate;
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/bac9ee7c/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 e0836dd..ba017bd 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -6190,4 +6190,40 @@ LogicalProject(JOB=[$0], EMPNO=[10], SAL=[$1], S=[$2])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testWhereNotInCorrelated">
+        <Resource name="sql">
+            <![CDATA[select sal from emp where empno NOT IN (select deptno 
from dept where emp.job = dept.name)]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(SAL=[$5])
+  LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(DEPTNO=[$0])
+  LogicalFilter(condition=[=($cor0.JOB, $1)])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+}))], variablesSet=[[$cor0]])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![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=[IS NULL($11)])
+      LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], 
HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], 
DEPTNO0=[CAST($9):INTEGER], JOB0=[CAST($10):VARCHAR(10) CHARACTER SET 
"ISO-8859-1" COLLATE "ISO-8859-1$en_US$primary"], $f2=[CAST($11):BOOLEAN])
+        LogicalJoin(condition=[AND(=($2, $10), =($0, $9))], joinType=[inner])
+          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+          LogicalProject(DEPTNO=[$0], JOB=[$1], $f2=[true])
+            LogicalAggregate(group=[{0, 1}])
+              LogicalProject(DEPTNO=[$0], JOB=[$2], i=[$1])
+                LogicalProject(DEPTNO=[$0], i=[true], JOB=[$1])
+                  LogicalProject(DEPTNO=[$0], JOB=[$2])
+                    LogicalJoin(condition=[=($2, $1)], joinType=[inner])
+                      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+                      LogicalAggregate(group=[{0}])
+                        LogicalProject(JOB=[$2])
+                          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
 </Root>

Reply via email to