You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2016/11/01 22:02:39 UTC

[1/3] calcite git commit: [CALCITE-1416] Make classes implement AutoCloseable where possible (Chinmay Kolhatkar)

Repository: calcite
Updated Branches:
  refs/heads/master 35c417527 -> 03d6b00cd


[CALCITE-1416] Make classes implement AutoCloseable where possible (Chinmay Kolhatkar)

Classes include Planner, Interpreter, Source, Hook.Closeable, SqlTesterImpl.

Add class Closer, which closes AutoCloseable resources (Julian Hyde).

Close apache/calcite#316


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

Branch: refs/heads/master
Commit: 6378fa6889a2527f13ef70a223ee4ee305bb51fb
Parents: 35c4175
Author: Chinmay Kolhatkar <ch...@datatorrent.com>
Authored: Sat Oct 22 11:47:28 2016 +0530
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Nov 1 01:54:04 2016 -0700

----------------------------------------------------------------------
 .../apache/calcite/interpreter/Interpreter.java |  9 ++--
 .../org/apache/calcite/interpreter/Source.java  |  2 +-
 .../java/org/apache/calcite/runtime/Hook.java   | 16 +++---
 .../java/org/apache/calcite/tools/Planner.java  |  2 +-
 .../java/org/apache/calcite/util/Closer.java    | 50 ++++++++++++++++++
 .../apache/calcite/sql/test/SqlTesterImpl.java  |  8 +--
 .../org/apache/calcite/test/CalciteAssert.java  | 53 ++++++++++++--------
 .../org/apache/calcite/test/RelOptTestBase.java | 11 ++--
 .../org/apache/calcite/tools/PlannerTest.java   | 40 ++++++++-------
 9 files changed, 121 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/6378fa68/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
index bd76efd..5b2752c 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
@@ -57,15 +57,17 @@ import java.util.NoSuchElementException;
  *
  * <p>Contains the context for interpreting relational expressions. In
  * particular it holds working state while the data flow graph is being
- * assembled.</p>
+ * assembled.
  */
-public class Interpreter extends AbstractEnumerable<Object[]> {
+public class Interpreter extends AbstractEnumerable<Object[]>
+    implements AutoCloseable {
   final Map<RelNode, NodeInfo> nodes = Maps.newLinkedHashMap();
   private final DataContext dataContext;
   private final RelNode rootRel;
   private final Map<RelNode, List<RelNode>> relInputs = Maps.newHashMap();
   protected final ScalarCompiler scalarCompiler;
 
+  /** Creates an Interpreter. */
   public Interpreter(DataContext dataContext, RelNode rootRel) {
     this.dataContext = Preconditions.checkNotNull(dataContext);
     this.scalarCompiler =
@@ -118,8 +120,7 @@ public class Interpreter extends AbstractEnumerable<Object[]> {
     }
   }
 
-  private void close() {
-    // TODO:
+  public void close() {
   }
 
   /** Compiles an expression to an executable form. */

http://git-wip-us.apache.org/repos/asf/calcite/blob/6378fa68/core/src/main/java/org/apache/calcite/interpreter/Source.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Source.java b/core/src/main/java/org/apache/calcite/interpreter/Source.java
index 75b6c1b..1371819 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Source.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Source.java
@@ -21,7 +21,7 @@ package org.apache.calcite.interpreter;
  *
  * <p>Corresponds to an input of a relational expression.
  */
-public interface Source {
+public interface Source extends AutoCloseable {
   /** Reads a row. Null means end of data. */
   Row receive();
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/6378fa68/core/src/main/java/org/apache/calcite/runtime/Hook.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/Hook.java b/core/src/main/java/org/apache/calcite/runtime/Hook.java
index a97a406..6257f4a 100644
--- a/core/src/main/java/org/apache/calcite/runtime/Hook.java
+++ b/core/src/main/java/org/apache/calcite/runtime/Hook.java
@@ -71,12 +71,12 @@ public enum Hook {
   QUERY_PLAN;
 
   private final List<Function<Object, Object>> handlers =
-      new CopyOnWriteArrayList<Function<Object, Object>>();
+      new CopyOnWriteArrayList<>();
 
   private final ThreadLocal<List<Function<Object, Object>>> threadHandlers =
       new ThreadLocal<List<Function<Object, Object>>>() {
         protected List<Function<Object, Object>> initialValue() {
-          return new ArrayList<Function<Object, Object>>();
+          return new ArrayList<>();
         }
       };
 
@@ -143,20 +143,16 @@ public enum Hook {
     return holder.get();
   }
 
-  /** Removes a Hook after use.
-   *
-   * <p>Note: Although it would be convenient, this interface cannot extend
-   * {@code AutoCloseable} while Calcite maintains compatibility with
-   * JDK 1.6.</p>
-   */
-  public interface Closeable /*extends AutoCloseable*/ {
+  /** Removes a Hook after use. */
+  public interface Closeable extends AutoCloseable {
     /** Closeable that does nothing. */
     Closeable EMPTY =
         new Closeable() {
           public void close() {}
         };
 
-    void close(); // override, removing "throws"
+    // override, removing "throws"
+    @Override void close();
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/6378fa68/core/src/main/java/org/apache/calcite/tools/Planner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/Planner.java b/core/src/main/java/org/apache/calcite/tools/Planner.java
index 8b2b25d..2d9cd82 100644
--- a/core/src/main/java/org/apache/calcite/tools/Planner.java
+++ b/core/src/main/java/org/apache/calcite/tools/Planner.java
@@ -35,7 +35,7 @@ import org.apache.calcite.util.Pair;
  * reset() after each use of Planner that corresponds to a different
  * query.
  */
-public interface Planner {
+public interface Planner extends AutoCloseable {
   /**
    * Parses and validates a SQL statement.
    *

http://git-wip-us.apache.org/repos/asf/calcite/blob/6378fa68/core/src/main/java/org/apache/calcite/util/Closer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Closer.java b/core/src/main/java/org/apache/calcite/util/Closer.java
new file mode 100644
index 0000000..e82fdbc
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/util/Closer.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.util;
+
+import com.google.common.base.Throwables;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Helper that holds onto {@link AutoCloseable} resources and releases them
+ * when its {@code #close} method is called.
+ *
+ * <p>Similar to {@link com.google.common.io.Closer} but can deal with
+ * {@link AutoCloseable} and doesn't throw {@link IOException}. */
+public final class Closer implements AutoCloseable {
+  private final List<AutoCloseable> list = new ArrayList<>();
+
+  /** Registers a resource. */
+  public <E extends AutoCloseable> E add(E e) {
+    list.add(e);
+    return e;
+  }
+
+  public void close() {
+    for (AutoCloseable closeable : list) {
+      try {
+        closeable.close();
+      } catch (Exception e) {
+        throw Throwables.propagate(e);
+      }
+    }
+  }
+}
+
+// End Closer.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/6378fa68/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java b/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
index fdf08f8..663714d 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
@@ -74,7 +74,7 @@ import static org.junit.Assert.fail;
  * Implementation of {@link org.apache.calcite.test.SqlValidatorTestCase.Tester}
  * that talks to a mock catalog.
  */
-public class SqlTesterImpl implements SqlTester {
+public class SqlTesterImpl implements SqlTester, AutoCloseable {
   protected final SqlTestFactory factory;
 
   public SqlTesterImpl(SqlTestFactory factory) {
@@ -385,11 +385,7 @@ public class SqlTesterImpl implements SqlTester {
     for (String sql : buildQueries(expression)) {
       TypeChecker typeChecker =
           new SqlTests.StringTypeChecker(expectedType);
-      check(
-          sql,
-          typeChecker,
-          new Double(expectedResult),
-          delta);
+      check(sql, typeChecker, expectedResult, delta);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/6378fa68/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 db8e654..c877d00 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -33,6 +33,8 @@ import org.apache.calcite.schema.Schema;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.calcite.schema.impl.ViewTable;
+import org.apache.calcite.util.Closer;
+import org.apache.calcite.util.Holder;
 import org.apache.calcite.util.JsonBuilder;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
@@ -458,8 +460,7 @@ public class CalciteAssert {
     final String message =
         "With materializationsEnabled=" + materializationsEnabled
             + ", limit=" + limit;
-    final List<Hook.Closeable> closeableList = Lists.newArrayList();
-    try {
+    try (final Closer closer = new Closer()) {
       if (connection instanceof CalciteConnection) {
         CalciteConnection calciteConnection = (CalciteConnection) connection;
         calciteConnection.getProperties().setProperty(
@@ -470,7 +471,7 @@ public class CalciteAssert {
             Boolean.toString(materializationsEnabled));
       }
       for (Pair<Hook, Function> hook : hooks) {
-        closeableList.add(hook.left.addThread(hook.right));
+        closer.add(hook.left.addThread(hook.right));
       }
       Statement statement = connection.createStatement();
       statement.setMaxRows(limit <= 0 ? limit : Math.max(limit, 1));
@@ -511,10 +512,6 @@ public class CalciteAssert {
       throw e;
     } catch (Throwable e) {
       throw new RuntimeException(message, e);
-    } finally {
-      for (Hook.Closeable closeable : closeableList) {
-        closeable.close();
-      }
     }
   }
 
@@ -526,27 +523,27 @@ public class CalciteAssert {
       final Function<RelNode, Void> substitutionChecker) throws Exception {
     final String message =
         "With materializationsEnabled=" + materializationsEnabled;
-    final Hook.Closeable closeable =
-        convertChecker == null
-            ? Hook.Closeable.EMPTY
-            : Hook.TRIMMED.addThread(
+    try (Closer closer = new Closer()) {
+      if (convertChecker != null) {
+        closer.add(
+            Hook.TRIMMED.addThread(
                 new Function<RelNode, Void>() {
                   public Void apply(RelNode rel) {
                     convertChecker.apply(rel);
                     return null;
                   }
-                });
-    final Hook.Closeable closeable2 =
-        substitutionChecker == null
-            ? Hook.Closeable.EMPTY
-            : Hook.SUB.addThread(
+                }));
+      }
+      if (substitutionChecker != null) {
+        closer.add(
+            Hook.SUB.addThread(
                 new Function<RelNode, Void>() {
                   public Void apply(RelNode rel) {
                     substitutionChecker.apply(rel);
                     return null;
                   }
-                });
-    try {
+                }));
+      }
       ((CalciteConnection) connection).getProperties().setProperty(
           CalciteConnectionProperty.MATERIALIZATIONS_ENABLED.camelName(),
           Boolean.toString(materializationsEnabled));
@@ -558,9 +555,6 @@ public class CalciteAssert {
       connection.close();
     } catch (Throwable e) {
       throw new RuntimeException(message, e);
-    } finally {
-      closeable.close();
-      closeable2.close();
     }
   }
 
@@ -1422,6 +1416,23 @@ public class CalciteAssert {
     private <T> void addHook(Hook hook, Function<T, Void> handler) {
       hooks.add(Pair.of(hook, (Function) handler));
     }
+
+    /** Returns a function that, when a hook is called, will "return" a given
+     * value. (Because of the way hooks work, it "returns" the value by writing
+     * into a {@link Holder}. */
+    private <V> Function<Holder<V>, Void> propertyHook(final V v) {
+      return new Function<Holder<V>, Void>() {
+        public Void apply(Holder<V> holder) {
+          holder.set(v);
+          return null;
+        }
+      };
+    }
+
+    /** Adds a property hook. */
+    public <V> AssertQuery withProperty(Hook hook, V value) {
+      return withHook(hook, propertyHook(value));
+    }
   }
 
   /** Fluent interface for building a metadata query to be tested. */

http://git-wip-us.apache.org/repos/asf/calcite/blob/6378fa68/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 1556094..e405874 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
@@ -28,13 +28,13 @@ 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.Hook;
+import org.apache.calcite.util.Closer;
 import org.apache.calcite.util.Holder;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -241,17 +241,12 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
     }
 
     private void check(boolean unchanged) {
-      final List<Hook.Closeable> closeables = new ArrayList<>();
-      try {
+      try (final Closer closer = new Closer()) {
         for (Map.Entry<Hook, Function> entry : hooks.entrySet()) {
-          closeables.add(entry.getKey().addThread(entry.getValue()));
+          closer.add(entry.getKey().addThread(entry.getValue()));
         }
         checkPlanning(tester.withExpand(expand), null, hepPlanner, sql,
             unchanged);
-      } finally {
-        for (Hook.Closeable closeable : closeables) {
-          closeable.close();
-        }
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/6378fa68/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
index 648786b..01c8f94 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -1021,12 +1021,13 @@ public class PlannerTest {
         .defaultSchema(schema)
         .programs(Programs.ofRules(Programs.RULE_SET))
         .build();
-    Planner p = Frameworks.getPlanner(config);
-    SqlNode n = p.parse(tpchTestQuery);
-    n = p.validate(n);
-    RelNode r = p.rel(n).project();
-    String plan = RelOptUtil.toString(r);
-    p.close();
+    String plan;
+    try (Planner p = Frameworks.getPlanner(config)) {
+      SqlNode n = p.parse(tpchTestQuery);
+      n = p.validate(n);
+      RelNode r = p.rel(n).project();
+      plan = RelOptUtil.toString(r);
+    }
     return plan;
   }
 
@@ -1073,19 +1074,20 @@ public class PlannerTest {
     traitDefs.add(RelCollationTraitDef.INSTANCE);
     final SqlParser.Config parserConfig =
         SqlParser.configBuilder().setLex(Lex.MYSQL).build();
-    Planner p = Frameworks.getPlanner(
-        Frameworks.newConfigBuilder()
-            .parserConfig(parserConfig)
-            .defaultSchema(schema)
-            .traitDefs(traitDefs)
-            .programs(Programs.ofRules(Programs.RULE_SET))
-            .build());
-    SqlNode n = p.parse(query);
-    n = p.validate(n);
-    RelNode r = p.rel(n).project();
-    String plan = RelOptUtil.toString(r);
-    plan = Util.toLinux(plan);
-    p.close();
+    FrameworkConfig config = Frameworks.newConfigBuilder()
+      .parserConfig(parserConfig)
+      .defaultSchema(schema)
+      .traitDefs(traitDefs)
+      .programs(Programs.ofRules(Programs.RULE_SET))
+      .build();
+    String plan;
+    try (Planner p = Frameworks.getPlanner(config)) {
+      SqlNode n = p.parse(query);
+      n = p.validate(n);
+      RelNode r = p.rel(n).project();
+      plan = RelOptUtil.toString(r);
+      plan = Util.toLinux(plan);
+    }
     assertThat(plan,
         equalTo("LogicalSort(sort0=[$0], dir0=[ASC])\n"
         + "  LogicalProject(psPartkey=[$0])\n"


[2/3] calcite git commit: Upgrade Quidem

Posted by jh...@apache.org.
Upgrade Quidem

Allow Hook instances to return values.

Fix some javadoc problems under JDK 1.7.


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

Branch: refs/heads/master
Commit: bfcd4980d2cec1b0d7d998190510c3604e261d4b
Parents: 6378fa6
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Oct 31 15:58:24 2016 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Nov 1 13:30:45 2016 -0700

----------------------------------------------------------------------
 .../calcite/prepare/CalcitePrepareImpl.java     | 32 ++++++++++++--------
 .../org/apache/calcite/prepare/Prepare.java     |  8 ++---
 .../apache/calcite/prepare/RelOptTableImpl.java |  3 +-
 .../java/org/apache/calcite/runtime/Hook.java   | 17 +++++++++++
 .../java/org/apache/calcite/util/Closer.java    |  4 +--
 .../org/apache/calcite/test/CalciteAssert.java  | 15 +--------
 .../java/org/apache/calcite/test/JdbcTest.java  |  7 ++---
 .../org/apache/calcite/test/QuidemTest.java     | 24 ++++++++++++---
 .../org/apache/calcite/test/RelOptTestBase.java | 15 +--------
 .../calcite/adapter/druid/DruidTable.java       |  1 -
 pom.xml                                         |  2 +-
 .../apache/calcite/test/SparkAdapterTest.java   |  8 +++++
 12 files changed, 76 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index fcbee23..cd2ad50 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -172,7 +172,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
 
   /** Whether the bindable convention should be the root convention of any
    * plan. If not, enumerable convention is the default. */
-  public static final boolean ENABLE_BINDABLE = false;
+  public final boolean enableBindable = Hook.ENABLE_BINDABLE.get(false);
 
   /** Whether the enumerable convention is enabled. */
   public static final boolean ENABLE_ENUMERABLE = true;
@@ -294,7 +294,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
       SqlNode sqlNode1) {
     final JavaTypeFactory typeFactory = context.getTypeFactory();
     final Convention resultConvention =
-        ENABLE_BINDABLE ? BindableConvention.INSTANCE
+        enableBindable ? BindableConvention.INSTANCE
             : EnumerableConvention.INSTANCE;
     final HepPlanner planner = new HepPlanner(new HepProgramBuilder().build());
     planner.addRelTraitDef(ConventionTraitDef.INSTANCE);
@@ -503,7 +503,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     if (prepareContext.config().materializationsEnabled()) {
       planner.addRule(MaterializedViewFilterScanRule.INSTANCE);
     }
-    if (ENABLE_BINDABLE) {
+    if (enableBindable) {
       for (RelOptRule rule : Bindables.RULES) {
         planner.addRule(rule);
       }
@@ -519,7 +519,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
       planner.addRule(EnumerableInterpreterRule.INSTANCE);
     }
 
-    if (ENABLE_BINDABLE && ENABLE_ENUMERABLE) {
+    if (enableBindable && ENABLE_ENUMERABLE) {
       planner.addRule(
           EnumerableBindable.EnumerableToBindableConverterRule.INSTANCE);
     }
@@ -683,7 +683,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
       prefer = EnumerableRel.Prefer.CUSTOM;
     }
     final Convention resultConvention =
-        ENABLE_BINDABLE ? BindableConvention.INSTANCE
+        enableBindable ? BindableConvention.INSTANCE
             : EnumerableConvention.INSTANCE;
     final CalcitePreparingStmt preparingStmt =
         new CalcitePreparingStmt(this, context, catalogReader, typeFactory,
@@ -779,17 +779,19 @@ public class CalcitePrepareImpl implements CalcitePrepare {
     if (preparedResult instanceof Typed) {
       resultClazz = (Class) ((Typed) preparedResult).getElementType();
     }
+    final Meta.CursorFactory cursorFactory =
+        preparingStmt.resultConvention == BindableConvention.INSTANCE
+            ? Meta.CursorFactory.ARRAY
+            : Meta.CursorFactory.deduce(columns, resultClazz);
     //noinspection unchecked
-    final Bindable<T> bindable = preparedResult.getBindable();
+    final Bindable<T> bindable = preparedResult.getBindable(cursorFactory);
     return new CalciteSignature<>(
         query.sql,
         parameters,
         preparingStmt.internalParameters,
         jdbcType,
         columns,
-        preparingStmt.resultConvention == BindableConvention.INSTANCE
-            ? Meta.CursorFactory.ARRAY
-            : Meta.CursorFactory.deduce(columns, resultClazz),
+        cursorFactory,
         preparedResult instanceof Prepare.PreparedResultImpl
             ? ((Prepare.PreparedResultImpl) preparedResult).collations
             : ImmutableList.<RelCollation>of(),
@@ -1226,7 +1228,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
           throw new UnsupportedOperationException();
         }
 
-        public Bindable getBindable() {
+        public Bindable getBindable(Meta.CursorFactory cursorFactory) {
           return bindable;
         }
 
@@ -1263,11 +1265,17 @@ public class CalcitePrepareImpl implements CalcitePrepare {
       super(resultType, parameterRowType, root, format, detailLevel);
     }
 
-    public Bindable getBindable() {
+    public Bindable getBindable(final Meta.CursorFactory cursorFactory) {
       final String explanation = getCode();
       return new Bindable() {
         public Enumerable bind(DataContext dataContext) {
-          return Linq4j.singletonEnumerable(explanation);
+          switch (cursorFactory.style) {
+          case ARRAY:
+            return Linq4j.singletonEnumerable(new String[] {explanation});
+          case OBJECT:
+          default:
+            return Linq4j.singletonEnumerable(explanation);
+          }
         }
       };
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/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 0860d16..3532ed3 100644
--- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java
+++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java
@@ -18,6 +18,7 @@ package org.apache.calcite.prepare;
 
 import org.apache.calcite.DataContext;
 import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.jdbc.CalcitePrepare;
 import org.apache.calcite.jdbc.CalciteSchema;
 import org.apache.calcite.jdbc.CalciteSchema.LatticeEntry;
@@ -441,8 +442,6 @@ public abstract class Prepare {
       return Collections.singletonList(
           Collections.<String>nCopies(4, null));
     }
-
-    public abstract Bindable getBindable();
   }
 
   /**
@@ -481,9 +480,10 @@ public abstract class Prepare {
     /**
      * Executes the prepared result.
      *
+     * @param cursorFactory How to map values into a cursor
      * @return producer of rows resulting from execution
      */
-    Bindable getBindable();
+    Bindable getBindable(Meta.CursorFactory cursorFactory);
   }
 
   /**
@@ -546,8 +546,6 @@ public abstract class Prepare {
     public RelNode getRootRel() {
       return rootRel;
     }
-
-    public abstract Bindable getBindable();
   }
 
   /** Describes that a given SQL query is materialized by a given table.

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
index 969fa99..6d7ffac 100644
--- a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
@@ -32,6 +32,7 @@ import org.apache.calcite.rel.logical.LogicalTableScan;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rel.type.RelRecordType;
+import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.schema.ExtensibleTable;
 import org.apache.calcite.schema.FilterableTable;
 import org.apache.calcite.schema.ModifiableTable;
@@ -251,7 +252,7 @@ public class RelOptTableImpl implements Prepare.PreparingTable {
       return ((TranslatableTable) table).toRel(context, this);
     }
     final RelOptCluster cluster = context.getCluster();
-    if (CalcitePrepareImpl.ENABLE_BINDABLE) {
+    if (Hook.ENABLE_BINDABLE.get(false)) {
       return LogicalTableScan.create(cluster, this);
     }
     if (CalcitePrepareImpl.ENABLE_ENUMERABLE

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/core/src/main/java/org/apache/calcite/runtime/Hook.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/Hook.java b/core/src/main/java/org/apache/calcite/runtime/Hook.java
index 6257f4a..efa9004 100644
--- a/core/src/main/java/org/apache/calcite/runtime/Hook.java
+++ b/core/src/main/java/org/apache/calcite/runtime/Hook.java
@@ -39,6 +39,11 @@ public enum Hook {
    * Default true. */
   REL_BUILDER_SIMPLIFY,
 
+  /** Returns a boolean value, whether the return convention should be
+   * {@link org.apache.calcite.interpreter.BindableConvention}.
+   * Default false. */
+  ENABLE_BINDABLE,
+
   /** Called with the SQL string and parse tree, in an array. */
   PARSE_TREE,
 
@@ -125,6 +130,18 @@ public enum Hook {
     return threadHandlers.get().remove(handler);
   }
 
+  /** Returns a function that, when a hook is called, will "return" a given
+   * value. (Because of the way hooks work, it "returns" the value by writing
+   * into a {@link Holder}. */
+  public static <V> Function<Holder<V>, Void> property(final V v) {
+    return new Function<Holder<V>, Void>() {
+      public Void apply(Holder<V> holder) {
+        holder.set(v);
+        return null;
+      }
+    };
+  }
+
   /** Runs all handlers registered for this Hook, with the given argument. */
   public void run(Object arg) {
     for (Function<Object, Object> handler : handlers) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/core/src/main/java/org/apache/calcite/util/Closer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Closer.java b/core/src/main/java/org/apache/calcite/util/Closer.java
index e82fdbc..b816d35 100644
--- a/core/src/main/java/org/apache/calcite/util/Closer.java
+++ b/core/src/main/java/org/apache/calcite/util/Closer.java
@@ -25,8 +25,8 @@ import java.util.List;
 /** Helper that holds onto {@link AutoCloseable} resources and releases them
  * when its {@code #close} method is called.
  *
- * <p>Similar to {@link com.google.common.io.Closer} but can deal with
- * {@link AutoCloseable} and doesn't throw {@link IOException}. */
+ * <p>Similar to {@code com.google.common.io.Closer} but can deal with
+ * {@link AutoCloseable}, and doesn't throw {@link IOException}. */
 public final class Closer implements AutoCloseable {
   private final List<AutoCloseable> list = new ArrayList<>();
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/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 c877d00..c5efd87 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -34,7 +34,6 @@ import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.calcite.schema.impl.ViewTable;
 import org.apache.calcite.util.Closer;
-import org.apache.calcite.util.Holder;
 import org.apache.calcite.util.JsonBuilder;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
@@ -1417,21 +1416,9 @@ public class CalciteAssert {
       hooks.add(Pair.of(hook, (Function) handler));
     }
 
-    /** Returns a function that, when a hook is called, will "return" a given
-     * value. (Because of the way hooks work, it "returns" the value by writing
-     * into a {@link Holder}. */
-    private <V> Function<Holder<V>, Void> propertyHook(final V v) {
-      return new Function<Holder<V>, Void>() {
-        public Void apply(Holder<V> holder) {
-          holder.set(v);
-          return null;
-        }
-      };
-    }
-
     /** Adds a property hook. */
     public <V> AssertQuery withProperty(Hook hook, V value) {
-      return withHook(hook, propertyHook(value));
+      return withHook(hook, Hook.property(value));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/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 0eede43..eaa026b 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -6094,7 +6094,7 @@ public class JdbcTest {
   /** Tests that {@link Hook#PARSE_TREE} works. */
   @Test public void testHook() {
     final int[] callCount = {0};
-    final Hook.Closeable hook = Hook.PARSE_TREE.addThread(
+    try (Hook.Closeable hook = Hook.PARSE_TREE.addThread(
         new Function<Object[], Object>() {
           public Void apply(Object[] args) {
             assertThat(args.length, equalTo(2));
@@ -6107,8 +6107,7 @@ public class JdbcTest {
             ++callCount[0];
             return null;
           }
-        });
-    try {
+        })) {
       // Simple query does not run the hook.
       testSimple();
       assertThat(callCount[0], equalTo(0));
@@ -6116,8 +6115,6 @@ public class JdbcTest {
       // Non-trivial query runs hook once.
       testGroupByNull();
       assertThat(callCount[0], equalTo(1));
-    } finally {
-      hook.close();
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/core/src/test/java/org/apache/calcite/test/QuidemTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/QuidemTest.java b/core/src/test/java/org/apache/calcite/test/QuidemTest.java
index a3dafba..78b202c 100644
--- a/core/src/test/java/org/apache/calcite/test/QuidemTest.java
+++ b/core/src/test/java/org/apache/calcite/test/QuidemTest.java
@@ -22,11 +22,13 @@ import org.apache.calcite.jdbc.CalciteConnection;
 import org.apache.calcite.prepare.Prepare;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.schema.Schema;
 import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.calcite.schema.impl.AbstractTable;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.Bug;
+import org.apache.calcite.util.Closer;
 import org.apache.calcite.util.TryThreadLocal;
 import org.apache.calcite.util.Util;
 
@@ -144,11 +146,22 @@ public class QuidemTest {
       outFile = new File(base, u2n("/surefire/") + path);
     }
     Util.discard(outFile.getParentFile().mkdirs());
-    final FileReader fileReader = new FileReader(inFile);
-    final BufferedReader bufferedReader = new BufferedReader(fileReader);
-    final FileWriter writer = new FileWriter(outFile);
-    new Quidem(bufferedReader, writer, env(), new QuidemConnectionFactory())
-        .execute();
+    try (final FileReader fileReader = new FileReader(inFile);
+         final BufferedReader bufferedReader = new BufferedReader(fileReader);
+         final FileWriter writer = new FileWriter(outFile);
+         final Closer closer = new Closer()) {
+      new Quidem(bufferedReader, writer, env(), new QuidemConnectionFactory())
+          .withPropertyHandler(new Quidem.PropertyHandler() {
+            public void onSet(String propertyName, Object value) {
+              if (propertyName.equals("bindable")) {
+                final boolean b = value instanceof Boolean
+                    && (Boolean) value;
+                closer.add(Hook.ENABLE_BINDABLE.addThread(Hook.property(b)));
+              }
+            }
+          })
+          .execute();
+    }
     final String diff = DiffTestCase.diff(inFile, outFile);
     if (!diff.isEmpty()) {
       fail("Files differ: " + outFile + " " + inFile + "\n"
@@ -314,6 +327,7 @@ public class QuidemTest {
       throw new RuntimeException("unknown connection '" + name + "'");
     }
   }
+
 }
 
 // End QuidemTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/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 e405874..e01fd5b 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
@@ -29,7 +29,6 @@ import org.apache.calcite.rel.metadata.DefaultRelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelMetadataProvider;
 import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.util.Closer;
-import org.apache.calcite.util.Holder;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableMap;
@@ -212,20 +211,8 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
               .put(hook, handler).build());
     }
 
-    /** Returns a function that, when a hook is called, will "return" a given
-     * value. (Because of the way hooks work, it "returns" the value by writing
-     * into a {@link Holder}. */
-    private <V> Function<Holder<V>, Void> propertyHook(final V v) {
-      return new Function<Holder<V>, Void>() {
-        public Void apply(Holder<V> holder) {
-          holder.set(v);
-          return null;
-        }
-      };
-    }
-
     public <V> Sql withProperty(Hook hook, V value) {
-      return withHook(hook, propertyHook(value));
+      return withHook(hook, Hook.property(value));
     }
 
     public Sql expand(boolean expand) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java
----------------------------------------------------------------------
diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java
index 816bec4..182e03a 100644
--- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java
+++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java
@@ -69,7 +69,6 @@ public class DruidTable extends AbstractTable implements TranslatableTable {
    * @param metricFieldNames Names of fields that are metrics
    * @param intervals Default interval if query does not constrain the time, or null
    * @param timestampFieldName Name of the column that contains the time
-   * @param intervals Intervals for the given table
    */
   public DruidTable(DruidSchema schema, String dataSource,
       RelProtoDataType protoRowType, Set<String> metricFieldNames,

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2e46dcb..45d1fdb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -107,7 +107,7 @@ limitations under the License.
     <oracle-jdbc6-driver.version>11.2.0.2.0</oracle-jdbc6-driver.version>
     <aggdesigner.version>6.0</aggdesigner.version>
     <postgresql.version>9.3-1102-jdbc3</postgresql.version>
-    <quidem.version>0.7</quidem.version>
+    <quidem.version>0.8</quidem.version>
     <scala.version>2.10.3</scala.version>
     <scott-data-hsqldb.version>0.1</scott-data-hsqldb.version>
     <servlet.version>3.0.1</servlet.version>

http://git-wip-us.apache.org/repos/asf/calcite/blob/bfcd4980/spark/src/test/java/org/apache/calcite/test/SparkAdapterTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/calcite/test/SparkAdapterTest.java b/spark/src/test/java/org/apache/calcite/test/SparkAdapterTest.java
index 300801b..8f415fb 100644
--- a/spark/src/test/java/org/apache/calcite/test/SparkAdapterTest.java
+++ b/spark/src/test/java/org/apache/calcite/test/SparkAdapterTest.java
@@ -16,6 +16,9 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.adapter.spark.SparkRel;
+import org.apache.calcite.util.Util;
+
 import org.junit.Test;
 
 import java.sql.SQLException;
@@ -30,6 +33,11 @@ public class SparkAdapterTest {
    * There are no data sources.
    */
   @Test public void testValues() throws SQLException {
+    // Insert a spurious reference to a class in Calcite's Spark adapter.
+    // Otherwise this test doesn't depend on the Spark module at all, and
+    // Javadoc gets confused.
+    Util.discard(SparkRel.class);
+
     CalciteAssert.that()
         .with(CalciteAssert.Config.SPARK)
         .query("select *\n"


[3/3] calcite git commit: [CALCITE-1479] AssertionError in ReduceExpressionsRule on multi-column IN subquery (Gian Merlino)

Posted by jh...@apache.org.
[CALCITE-1479] AssertionError in ReduceExpressionsRule on multi-column IN subquery (Gian Merlino)

Close apache/calcite#317


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

Branch: refs/heads/master
Commit: 03d6b00cdadb1b7dd4e4ae6de370c7f4bf5e2207
Parents: bfcd498
Author: Gian Merlino <gi...@gmail.com>
Authored: Fri Oct 21 20:09:59 2016 -0500
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Nov 1 14:19:17 2016 -0700

----------------------------------------------------------------------
 .../rel/rules/ReduceExpressionsRule.java        | 22 +++++++-----
 .../apache/calcite/test/RelOptRulesTest.java    | 20 +++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml | 36 ++++++++++++++++++++
 3 files changed, 70 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/03d6b00c/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 80a1c57..edc13de 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -48,6 +48,7 @@ import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexProgramBuilder;
 import org.apache.calcite.rex.RexRangeRef;
 import org.apache.calcite.rex.RexShuttle;
+import org.apache.calcite.rex.RexSubQuery;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.rex.RexUtil.ExprSimplifier;
 import org.apache.calcite.rex.RexVisitorImpl;
@@ -826,7 +827,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
       return false;
     }
 
-    public Void visitInputRef(RexInputRef inputRef) {
+    @Override public Void visitInputRef(RexInputRef inputRef) {
       if (constants.containsKey(inputRef)) {
         stack.add(Constancy.REDUCIBLE_CONSTANT);
         return null;
@@ -834,27 +835,32 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
       return pushVariable();
     }
 
-    public Void visitLiteral(RexLiteral literal) {
+    @Override public Void visitLiteral(RexLiteral literal) {
       stack.add(Constancy.IRREDUCIBLE_CONSTANT);
       return null;
     }
 
-    public Void visitOver(RexOver over) {
+    @Override public Void visitOver(RexOver over) {
       // assume non-constant (running SUM(1) looks constant but isn't)
       analyzeCall(over, Constancy.NON_CONSTANT);
       return null;
     }
 
-    public Void visitCorrelVariable(RexCorrelVariable correlVariable) {
+    @Override public Void visitCorrelVariable(RexCorrelVariable variable) {
       return pushVariable();
     }
 
-    public Void visitCall(RexCall call) {
+    @Override public Void visitCall(RexCall call) {
       // assume REDUCIBLE_CONSTANT until proven otherwise
       analyzeCall(call, Constancy.REDUCIBLE_CONSTANT);
       return null;
     }
 
+    @Override public Void visitSubQuery(RexSubQuery subQuery) {
+      analyzeCall(subQuery, Constancy.REDUCIBLE_CONSTANT);
+      return null;
+    }
+
     private void analyzeCall(RexCall call, Constancy callConstancy) {
       parentCallTypeStack.push(call.getOperator());
 
@@ -955,15 +961,15 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
       }
     }
 
-    public Void visitDynamicParam(RexDynamicParam dynamicParam) {
+    @Override public Void visitDynamicParam(RexDynamicParam dynamicParam) {
       return pushVariable();
     }
 
-    public Void visitRangeRef(RexRangeRef rangeRef) {
+    @Override public Void visitRangeRef(RexRangeRef rangeRef) {
       return pushVariable();
     }
 
-    public Void visitFieldAccess(RexFieldAccess fieldAccess) {
+    @Override public Void visitFieldAccess(RexFieldAccess fieldAccess) {
       return pushVariable();
     }
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/03d6b00c/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 e0d4a46..c794206 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -175,6 +175,26 @@ public class RelOptRulesTest extends RelOptTestBase {
     checkPlanning(tester, preProgram, hepPlanner, sql);
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-1479">[CALCITE-1479]
+   * AssertionError in ReduceExpressionsRule on multi-column IN subquery</a>. */
+  @Test public void testReduceCompositeInSubQuery() {
+    final HepProgram hepProgram = new HepProgramBuilder()
+        .addRuleInstance(ReduceExpressionsRule.FILTER_INSTANCE)
+        .build();
+    final String sql = "select *\n"
+        + "from emp\n"
+        + "where (empno, deptno) in (\n"
+        + "  select empno, deptno from (\n"
+        + "    select empno, deptno\n"
+        + "    from emp\n"
+        + "    group by empno, deptno))\n"
+        + "or deptno < 40 + 60";
+    checkSubQuery(sql)
+        .with(hepProgram)
+        .check();
+  }
+
   @Test public void testReduceOrCaseWhen() {
     HepProgram preProgram = new HepProgramBuilder()
         .build();

http://git-wip-us.apache.org/repos/asf/calcite/blob/03d6b00c/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 2885f12..36b3dbe 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -4298,6 +4298,42 @@ LogicalProject(EXPR$0=[CAST(12:34:56):TIMESTAMP(0) NOT NULL])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testReduceCompositeInSubQuery">
+        <Resource name="sql">
+            <![CDATA[select *
+from emp
+where (empno, deptno) in (
+  select empno, deptno from (
+    select empno, deptno
+    from emp
+    group by empno, deptno))
+or deptno < 40 + 60]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+  LogicalFilter(condition=[OR(IN($0, $7, {
+LogicalProject(EMPNO=[$0], DEPTNO=[$1])
+  LogicalAggregate(group=[{0, 1}])
+    LogicalProject(EMPNO=[$0], DEPTNO=[$7])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+}), <($7, +(40, 60)))])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <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(IN($0, $7, {
+LogicalProject(EMPNO=[$0], DEPTNO=[$1])
+  LogicalAggregate(group=[{0, 1}])
+    LogicalProject(EMPNO=[$0], DEPTNO=[$7])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+}), <($7, 100))])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testReduceConstantsRequiresExecutor">
         <Resource name="sql">
             <![CDATA[select * from (values (1,2)) where 1 + 2 > 3 + CAST(NULL AS INTEGER)]]>