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/01/26 21:35:40 UTC

[1/4] calcite git commit: [CALCITE-864] Correlation variable has incorrect row type if it is populated by right side of a Join

Repository: calcite
Updated Branches:
  refs/heads/master 999021115 -> f55d10c14


[CALCITE-864] Correlation variable has incorrect row type if it is populated by right side of a Join

Also fixes [CALCITE-559], apparently a duplicate issue.


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

Branch: refs/heads/master
Commit: d80e26c016babcb250e41b0abe94b8b0cfadbbe7
Parents: 9990211
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Jan 22 18:00:40 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jan 26 11:53:24 2016 -0800

----------------------------------------------------------------------
 .../calcite/rel/type/RelDataTypeFactory.java    | 13 ++++
 .../calcite/sql/validate/SqlQualified.java      |  4 ++
 .../apache/calcite/sql2rel/RelDecorrelator.java |  7 +--
 .../calcite/sql2rel/SqlToRelConverter.java      | 64 ++++++++++++++-----
 .../java/org/apache/calcite/test/JdbcTest.java  | 22 ++++---
 .../calcite/test/SqlToRelConverterTest.java     | 15 +++++
 .../calcite/test/SqlToRelConverterTest.xml      | 27 +++++++-
 core/src/test/resources/sql/subquery.iq         | 66 ++++++++++++++++++++
 8 files changed, 186 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/d80e26c0/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactory.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactory.java
index 35272c8..ab9b5bb 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactory.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactory.java
@@ -19,6 +19,7 @@ package org.apache.calcite.rel.type;
 import org.apache.calcite.sql.SqlCollation;
 import org.apache.calcite.sql.SqlIntervalQualifier;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.validate.SqlValidatorUtil;
 
 import java.nio.charset.Charset;
 import java.util.ArrayList;
@@ -418,6 +419,18 @@ public interface RelDataTypeFactory {
     }
 
     /**
+     * Makes sure that field names are unique.
+     */
+    public FieldInfoBuilder uniquify() {
+      final List<String> uniqueNames = SqlValidatorUtil.uniquify(names);
+      if (uniqueNames != names) {
+        names.clear();
+        names.addAll(uniqueNames);
+      }
+      return this;
+    }
+
+    /**
      * Creates a struct type with the current contents of this builder.
      */
     public RelDataType build() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/d80e26c0/core/src/main/java/org/apache/calcite/sql/validate/SqlQualified.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlQualified.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlQualified.java
index 4b99845..067c324 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlQualified.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlQualified.java
@@ -47,6 +47,10 @@ public class SqlQualified {
     this.identifier = identifier;
   }
 
+  @Override public String toString() {
+    return "{id: " + identifier.toString() + ", prefix: " + prefixLength + "}";
+  }
+
   public static SqlQualified create(SqlValidatorScope scope, int prefixLength,
       SqlValidatorNamespace namespace, SqlIdentifier identifier) {
     return new SqlQualified(scope, prefixLength, namespace, identifier);

http://git-wip-us.apache.org/repos/asf/calcite/blob/d80e26c0/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index ba196db..099bb9a 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -35,7 +35,6 @@ import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.core.Correlate;
 import org.apache.calcite.rel.core.CorrelationId;
-import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
@@ -806,11 +805,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
 
   private RelNode getCorRel(Correlation corVar) {
     final RelNode r = cm.mapCorVarToCorRel.get(corVar.corr);
-    RelNode r2 = r.getInput(0);
-    if (r2 instanceof Join) {
-      r2 = r2.getInput(0);
-    }
-    return r2;
+    return r.getInput(0);
   }
 
   private void decorrelateInputWithValueGenerator(RelNode rel) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/d80e26c0/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 d9189a5..a85c79a 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -160,6 +160,7 @@ import org.apache.calcite.util.trace.CalciteTrace;
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
@@ -2246,8 +2247,8 @@ public class SqlToRelConverter {
         }
       }
 
-      RelDataTypeField field =
-          catalogReader.field(foundNs.getRowType(), originalFieldName);
+      final RelDataTypeField field = foundNs.getRowType().getFieldList()
+          .get(fieldAccess.getField().getIndex() - namespaceOffset);
       int pos = namespaceOffset + field.getIndex();
 
       assert field.getType()
@@ -3275,21 +3276,26 @@ public class SqlToRelConverter {
     } else {
       qualified = SqlQualified.create(null, 1, null, identifier);
     }
-    final RexNode e0 = bb.lookupExp(qualified);
-    RexNode e = e0;
+    final Pair<RexNode, Map<String, Integer>> e0 = bb.lookupExp(qualified);
+    RexNode e = e0.left;
     for (String name : qualified.suffixTranslated()) {
-      final boolean caseSensitive = true; // name already fully-qualified
-      e = rexBuilder.makeFieldAccess(e, name, caseSensitive);
+      if (e == e0.left && e0.right != null) {
+        int i = e0.right.get(name);
+        e = rexBuilder.makeFieldAccess(e, i);
+      } else {
+        final boolean caseSensitive = true; // name already fully-qualified
+        e = rexBuilder.makeFieldAccess(e, name, caseSensitive);
+      }
     }
     if (e instanceof RexInputRef) {
       // adjust the type to account for nulls introduced by outer joins
       e = adjustInputRef(bb, (RexInputRef) e);
     }
 
-    if (e0 instanceof RexCorrelVariable) {
+    if (e0.left instanceof RexCorrelVariable) {
       assert e instanceof RexFieldAccess;
       final RexNode prev =
-          bb.mapCorrelateToRex.put(((RexCorrelVariable) e0).id,
+          bb.mapCorrelateToRex.put(((RexCorrelVariable) e0.left).id,
               (RexFieldAccess) e);
       assert prev == null;
     }
@@ -3891,14 +3897,14 @@ public class SqlToRelConverter {
      * @return a {@link RexFieldAccess} or {@link RexRangeRef}, or null if
      * not found
      */
-    RexNode lookupExp(SqlQualified qualified) {
+    Pair<RexNode, Map<String, Integer>> lookupExp(SqlQualified qualified) {
       if (nameToNodeMap != null && qualified.prefixLength == 1) {
         RexNode node = nameToNodeMap.get(qualified.identifier.names.get(0));
         if (node == null) {
           throw Util.newInternal("Unknown identifier '" + qualified.identifier
               + "' encountered while expanding expression");
         }
-        return node;
+        return Pair.of(node, null);
       }
       int[] offsets = {-1};
       final SqlValidatorScope[] ancestorScopes = {null};
@@ -3917,7 +3923,12 @@ public class SqlToRelConverter {
         int offset = offsets[0];
         final LookupContext rels =
             new LookupContext(this, inputs, systemFieldList.size());
-        return lookup(offset, rels);
+        final RexNode node = lookup(offset, rels);
+        if (node == null) {
+          return null;
+        } else {
+          return Pair.of(node, null);
+        }
       } else {
         // We're referencing a relational expression which has not been
         // converted yet. This occurs when from items are correlated,
@@ -3926,10 +3937,33 @@ public class SqlToRelConverter {
         assert isParent;
         DeferredLookup lookup =
             new DeferredLookup(this, qualified.identifier.names.get(0));
-        final CorrelationId correlName = cluster.createCorrel();
-        mapCorrelToDeferred.put(correlName, lookup);
-        final RelDataType rowType = foundNs.getRowType();
-        return rexBuilder.makeCorrel(rowType, correlName);
+        final CorrelationId correlId = cluster.createCorrel();
+        mapCorrelToDeferred.put(correlId, lookup);
+        if (offsets[0] < 0) {
+          return Pair.of(rexBuilder.makeCorrel(foundNs.getRowType(), correlId),
+              null);
+        } else {
+          final RelDataTypeFactory.FieldInfoBuilder builder =
+              typeFactory.builder();
+          final ListScope ancestorScope1 = (ListScope) ancestorScopes[0];
+          final ImmutableMap.Builder<String, Integer> fields =
+              ImmutableMap.builder();
+          int i = 0;
+          int offset = 0;
+          for (SqlValidatorNamespace c : ancestorScope1.getChildren()) {
+            builder.addAll(c.getRowType().getFieldList());
+            if (i == offsets[0]) {
+              for (RelDataTypeField field : c.getRowType().getFieldList()) {
+                fields.put(field.getName(), field.getIndex() + offset);
+              }
+            }
+            ++i;
+            offset += c.getRowType().getFieldCount();
+          }
+          final RexNode c =
+              rexBuilder.makeCorrel(builder.uniquify().build(), correlId);
+          return Pair.<RexNode, Map<String, Integer>>of(c, fields.build());
+        }
       }
     }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/d80e26c0/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 0e10877..0cc70ba 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -4581,19 +4581,21 @@ public class JdbcTest {
     }
   }
 
-  @Ignore("CALCITE-559 Correlated subquery will hit exception in Calcite")
-  @Test public void testJoinCorreScalarSubQ()
-      throws ClassNotFoundException, SQLException {
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-559">[CALCITE-559]
+   * Correlated scalar subquery in WHERE gives error</a>. */
+  @Test public void testJoinCorrelatedScalarSubquery() throws SQLException {
+    final String sql = "select e.employee_id, d.department_id "
+        + " from employee e, department d "
+        + " where e.department_id = d.department_id "
+        + " and e.salary > (select avg(e2.salary) "
+        + "                 from employee e2 "
+        + "                 where e2.store_id = e.store_id)";
     CalciteAssert.that()
         .with(CalciteAssert.Config.FOODMART_CLONE)
         .with(Lex.JAVA)
-        .query("select e.employee_id, d.department_id "
-                + " from employee e, department d "
-                + " where e.department_id = d.department_id and "
-                + "       e.salary > (select avg(e2.salary) "
-                + "                       from employee e2 "
-                + " where e2.store_id = e.store_id)")
-        .returnsCount(0);
+        .query(sql)
+        .returnsCount(599);
   }
 
   @Test public void testLeftJoin() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/d80e26c0/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 2e18dc7..f3cdf68 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -834,6 +834,21 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
     sql(sql).expand(false).convertsTo("${plan}");
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-864">[CALCITE-864]
+   * Correlation variable has incorrect row type if it is populated by right
+   * side of a Join</a>. */
+  @Test public void testCorrelatedSubQueryInJoin() {
+    final String sql = "select *\n"
+        + "from emp as e\n"
+        + "join dept as d using (deptno)\n"
+        + "where d.name = (\n"
+        + "  select max(name)\n"
+        + "  from dept as d2\n"
+        + "  where d2.deptno = d.deptno)";
+    sql(sql).expand(false).convertsTo("${plan}");
+  }
+
   @Test public void testExists() {
     check(
         "select*from emp where exists (select 1 from dept where deptno=55)",

http://git-wip-us.apache.org/repos/asf/calcite/blob/d80e26c0/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 a02eb60..84e1afe 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -117,6 +117,31 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)], EXPR$2=[SUM(DISTINCT $1)], EXPR$
             <![CDATA[select deptno, sum(sal), sum(distinct sal), count(*) from emp group by deptno]]>
         </Resource>
     </TestCase>
+    <TestCase name="testCorrelatedSubQueryInJoin">
+        <Resource name="sql">
+            <![CDATA[select *
+from emp as e
+join dept as d using (deptno)
+where d.name = (
+  select max(name)
+  from dept as d2
+  where d2.deptno = d.deptno)]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
+  LogicalFilter(condition=[=($10, $SCALAR_QUERY({
+LogicalAggregate(group=[{}], EXPR$0=[MAX($0)])
+  LogicalProject(NAME=[$1])
+    LogicalFilter(condition=[=($0, $cor0.DEPTNO0)])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+}))], variablesSet=[[$cor0]])
+    LogicalJoin(condition=[=($7, $9)], joinType=[inner])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+      LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testUnnest">
         <Resource name="plan">
             <![CDATA[
@@ -2859,7 +2884,7 @@ or exists (select deptno from emp where empno > dept.deptno + 5)]]>
             <![CDATA[
 LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
   LogicalJoin(condition=[OR(=($0, 1), EXISTS({
-LogicalFilter(condition=[>($0, +($cor0.DEPTNO, 5))])
+LogicalFilter(condition=[>($0, +($cor0.DEPTNO0, 5))])
   LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 }))], joinType=[left])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])

http://git-wip-us.apache.org/repos/asf/calcite/blob/d80e26c0/core/src/test/resources/sql/subquery.iq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/subquery.iq b/core/src/test/resources/sql/subquery.iq
index cfeb6e5..8f0eb70 100644
--- a/core/src/test/resources/sql/subquery.iq
+++ b/core/src/test/resources/sql/subquery.iq
@@ -319,4 +319,70 @@ where e.job not in (
 !plan
 !}
 
+# [CALCITE-864] Correlation variable has incorrect row type if it is populated
+# by right side of a Join
+select *
+from "scott".emp as e
+join "scott".dept as d using (deptno)
+where sal = (
+  select max(sal)
+  from "scott".emp as e2
+  join "scott".dept as d2 using (deptno)
+  where d2.deptno = d.deptno);
+ EMPNO | ENAME | JOB       | MGR  | HIREDATE   | SAL     | COMM | DEPTNO | DEPTNO0 | DNAME      | LOC
+-------+-------+-----------+------+------------+---------+------+--------+---------+------------+----------
+  7698 | BLAKE | MANAGER   | 7839 | 1981-01-05 | 2850.00 |      |     30 |      30 | SALES      | CHICAGO
+  7788 | SCOTT | ANALYST   | 7566 | 1987-04-19 | 3000.00 |      |     20 |      20 | RESEARCH   | DALLAS
+  7839 | KING  | PRESIDENT |      | 1981-11-17 | 5000.00 |      |     10 |      10 | ACCOUNTING | NEW YORK
+  7902 | FORD  | ANALYST   | 7566 | 1981-12-03 | 3000.00 |      |     20 |      20 | RESEARCH   | DALLAS
+(4 rows)
+
+!ok
+
+# Simpler test case for [CALCITE-864]
+select empno, ename, sal, e.deptno, loc
+from "scott".emp as e
+join "scott".dept as d using (deptno)
+where e.sal = (
+  select max(sal)
+  from "scott".emp as e2
+  where e2.deptno = e.deptno);
+ EMPNO | ENAME | SAL     | DEPTNO | LOC
+-------+-------+---------+--------+----------
+  7698 | BLAKE | 2850.00 |     30 | CHICAGO
+  7788 | SCOTT | 3000.00 |     20 | DALLAS
+  7839 | KING  | 5000.00 |     10 | NEW YORK
+  7902 | FORD  | 3000.00 |     20 | DALLAS
+(4 rows)
+
+!ok
+
+# Simpler test case for [CALCITE-864]
+select *
+from "scott".emp as e
+join "scott".dept as d using (deptno)
+where d.dname = (
+  select max(dname)
+  from "scott".dept as d2
+  where d2.deptno = d.deptno);
+ EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO | DEPTNO0 | DNAME      | LOC
+-------+--------+-----------+------+------------+---------+---------+--------+---------+------------+----------
+  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800.00 |         |     20 |      20 | RESEARCH   | DALLAS
+  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600.00 |  300.00 |     30 |      30 | SALES      | CHICAGO
+  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250.00 |  500.00 |     30 |      30 | SALES      | CHICAGO
+  7566 | JONES  | MANAGER   | 7839 | 1981-02-04 | 2975.00 |         |     20 |      20 | RESEARCH   | DALLAS
+  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250.00 | 1400.00 |     30 |      30 | SALES      | CHICAGO
+  7698 | BLAKE  | MANAGER   | 7839 | 1981-01-05 | 2850.00 |         |     30 |      30 | SALES      | CHICAGO
+  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450.00 |         |     10 |      10 | ACCOUNTING | NEW YORK
+  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000.00 |         |     20 |      20 | RESEARCH   | DALLAS
+  7839 | KING   | PRESIDENT |      | 1981-11-17 | 5000.00 |         |     10 |      10 | ACCOUNTING | NEW YORK
+  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500.00 |    0.00 |     30 |      30 | SALES      | CHICAGO
+  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100.00 |         |     20 |      20 | RESEARCH   | DALLAS
+  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950.00 |         |     30 |      30 | SALES      | CHICAGO
+  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000.00 |         |     20 |      20 | RESEARCH   | DALLAS
+  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300.00 |         |     10 |      10 | ACCOUNTING | NEW YORK
+(14 rows)
+
+!ok
+
 # End subquery.iq


[3/4] calcite git commit: [CALCITE-1067] Test failures due to clashing temporary table names

Posted by jh...@apache.org.
[CALCITE-1067] Test failures due to clashing temporary table names


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

Branch: refs/heads/master
Commit: 4ec47270b199cef58c39f6bf07209c5fb40875ef
Parents: 82b5860
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jan 25 18:08:52 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jan 26 11:53:33 2016 -0800

----------------------------------------------------------------------
 .../calcite/avatica/RemoteDriverTest.java       | 23 ++++++++++++--------
 .../calcite/avatica/remote/RemoteMetaTest.java  | 15 ++++++++-----
 .../apache/calcite/avatica/AvaticaUtils.java    | 18 +++++++++++++++
 .../calcite/avatica/test/AvaticaUtilsTest.java  | 22 +++++++++++++++++++
 4 files changed, 63 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/4ec47270/avatica-server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java
index 7e50dee..228ba8d 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java
@@ -346,10 +346,12 @@ public class RemoteDriverTest {
   }
 
   @Test public void testInsertDrop() throws Exception {
-    final String create = "create table if not exists TEST_TABLE2 ("
-        + "id int not null, "
-        + "msg varchar(3) not null)";
-    final String insert = "insert into TEST_TABLE2 values(1, 'foo')";
+    final String t = AvaticaUtils.unique("TEST_TABLE2");
+    final String create =
+        String.format("create table if not exists %s ("
+            + "id int not null, "
+            + "msg varchar(3) not null)", t);
+    final String insert = String.format("insert into %s values(1, 'foo')", t);
     Connection connection = ljs();
     Statement statement = connection.createStatement();
     statement.execute(create);
@@ -540,12 +542,15 @@ public class RemoteDriverTest {
 
   @Test public void testCreateInsertUpdateDrop() throws Exception {
     ConnectionSpec.getDatabaseLock().lock();
-    final String drop = "drop table TEST_TABLE if exists";
-    final String create = "create table TEST_TABLE("
+    final String t = AvaticaUtils.unique("TEST_TABLE");
+    final String drop = String.format("drop table %s if exists", t);
+    final String create = String.format("create table %s("
         + "id int not null, "
-        + "msg varchar(3) not null)";
-    final String insert = "insert into TEST_TABLE values(1, 'foo')";
-    final String update = "update TEST_TABLE set msg='bar' where id=1";
+        + "msg varchar(3) not null)",
+        t);
+    final String insert = String.format("insert into %s values(1, 'foo')", t);
+    final String update =
+        String.format("update %s set msg='bar' where id=1", t);
     try (Connection connection = getLocalConnection();
         Statement statement = connection.createStatement();
         PreparedStatement pstmt = connection.prepareStatement("values 1")) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ec47270/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index 49a88e7..ff95a45 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -19,6 +19,7 @@ package org.apache.calcite.avatica.remote;
 import org.apache.calcite.avatica.AvaticaConnection;
 import org.apache.calcite.avatica.AvaticaSqlException;
 import org.apache.calcite.avatica.AvaticaStatement;
+import org.apache.calcite.avatica.AvaticaUtils;
 import org.apache.calcite.avatica.ConnectionPropertiesImpl;
 import org.apache.calcite.avatica.ConnectionSpec;
 import org.apache.calcite.avatica.Meta;
@@ -262,17 +263,19 @@ public class RemoteMetaTest {
   }
 
   @Test public void testRemoteStatementInsert() throws Exception {
-    System.out.println(url);
+    final String t = AvaticaUtils.unique("TEST_TABLE2");
     AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url);
     Statement statement = conn.createStatement();
-    int status = statement.executeUpdate(
-        "create table if not exists "
-        + "TEST_TABLE2 (id int not null, msg varchar(255) not null)");
+    final String create =
+        String.format("create table if not exists %s ("
+            + "  id int not null, msg varchar(255) not null)", t);
+    int status = statement.executeUpdate(create);
     assertEquals(status, 0);
 
     statement = conn.createStatement();
-    status = statement.executeUpdate("insert into TEST_TABLE2 values ("
-        + "'" + RANDOM.nextInt(Integer.MAX_VALUE) + "', '" + UUID.randomUUID() + "')");
+    final String update = String.format("insert into %s values ('%d', '%s')",
+        t, RANDOM.nextInt(Integer.MAX_VALUE), UUID.randomUUID());
+    status = statement.executeUpdate(update);
     assertEquals(status, 1);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ec47270/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
index 6dd076b..9382f87 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
@@ -27,8 +27,10 @@ import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.AbstractList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /** Avatica utilities. */
 public class AvaticaUtils {
@@ -41,6 +43,8 @@ public class AvaticaUtils {
   private static final MethodHandle GET_LARGE_UPDATE_COUNT =
       method(void.class, Statement.class, "getLargeUpdateCount");
 
+  private static final Set<String> UNIQUE_STRINGS = new HashSet<>();
+
   private AvaticaUtils() {}
 
   static {
@@ -277,6 +281,20 @@ public class AvaticaUtils {
     }
     return statement.getUpdateCount();
   }
+
+  /** Generates a string that is unique in the execution of the JVM.
+   * It is used by tests to ensure that they create distinct temporary tables.
+   * The strings are never thrown away, so don't put too much in there!
+   * Thread safe. */
+  public static String unique(String base) {
+    synchronized (UNIQUE_STRINGS) {
+      String s = base;
+      while (!UNIQUE_STRINGS.add(s)) {
+        s = base + "_" + UNIQUE_STRINGS.size();
+      }
+      return s;
+    }
+  }
 }
 
 // End AvaticaUtils.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/4ec47270/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java b/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java
index ca548a6..850cbfd 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/test/AvaticaUtilsTest.java
@@ -21,6 +21,8 @@ import org.apache.calcite.avatica.AvaticaUtils;
 import org.junit.Test;
 
 import java.math.BigInteger;
+import java.util.LinkedHashSet;
+import java.util.Set;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
@@ -59,6 +61,26 @@ public class AvaticaUtilsTest {
           is("Property 'java.math.BigInteger.ONE' not valid for plugin type java.math.BigInteger"));
     }
   }
+
+  /** Unit test for
+   * {@link org.apache.calcite.avatica.AvaticaUtils#unique(java.lang.String)}. */
+  @Test public void testUnique() {
+    // Below, the "probably" comments indicate the strings that will be
+    // generated the first time you run the test.
+    final Set<String> list = new LinkedHashSet<>();
+    list.add(AvaticaUtils.unique("a")); // probably "a"
+    assertThat(list.size(), is(1));
+    list.add(AvaticaUtils.unique("a")); // probably "a_1"
+    assertThat(list.size(), is(2));
+    list.add(AvaticaUtils.unique("b")); // probably "b"
+    assertThat(list.size(), is(3));
+    list.add(AvaticaUtils.unique("a_1")); // probably "a_1_3"
+    assertThat(list.size(), is(4));
+    list.add(AvaticaUtils.unique("A")); // probably "A"
+    assertThat(list.size(), is(5));
+    list.add(AvaticaUtils.unique("a")); // probably "a_5"
+    assertThat(list.size(), is(6));
+  }
 }
 
 // End AvaticaUtilsTest.java


[4/4] calcite git commit: [CALCITE-1068] Deprecate Stacks

Posted by jh...@apache.org.
[CALCITE-1068] Deprecate Stacks


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

Branch: refs/heads/master
Commit: f55d10c147746d6299fb713adc184576380a1f49
Parents: 4ec4727
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jan 25 21:42:14 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jan 26 11:53:34 2016 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/jdbc/CalcitePrepare.java |  19 +--
 .../org/apache/calcite/model/ModelHandler.java  |  25 ++--
 .../apache/calcite/plan/volcano/RuleQueue.java  |  29 ++--
 .../calcite/plan/volcano/VolcanoPlanner.java    |  16 +--
 .../org/apache/calcite/rel/RelShuttleImpl.java  |  12 +-
 .../rel/rules/ReduceExpressionsRule.java        |  12 +-
 .../apache/calcite/sql/SqlIntervalLiteral.java  |   7 +-
 .../apache/calcite/sql/validate/AggChecker.java |  25 ++--
 .../sql/validate/AggregatingSelectScope.java    |   5 +-
 .../apache/calcite/sql/validate/OverScope.java  |   3 +-
 .../calcite/sql/validate/SelectScope.java       |   5 +-
 .../calcite/sql/validate/SqlValidatorImpl.java  |   5 +-
 .../calcite/sql/validate/SqlValidatorUtil.java  |  12 +-
 .../apache/calcite/sql2rel/RelDecorrelator.java |  17 +--
 .../calcite/sql2rel/SqlToRelConverter.java      |  16 +--
 .../org/apache/calcite/tools/RelBuilder.java    |  45 +++---
 .../calcite/util/PartiallyOrderedSet.java       | 141 ++++---------------
 .../org/apache/calcite/util/StackWriter.java    |  11 +-
 .../java/org/apache/calcite/util/Stacks.java    |   1 +
 .../java/org/apache/calcite/util/XmlOutput.java |  10 +-
 .../calcite/sql/test/SqlPrettyWriterTest.java   |  12 +-
 .../apache/calcite/test/MockCatalogReader.java  |   5 +-
 22 files changed, 178 insertions(+), 255 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
index 0aa47bc..31b6b70 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java
@@ -43,7 +43,6 @@ import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.util.ImmutableIntList;
-import org.apache.calcite.util.Stacks;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 
@@ -52,7 +51,8 @@ import com.google.common.collect.ImmutableList;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
-import java.util.ArrayList;
+import java.util.ArrayDeque;
+import java.util.Deque;
 import java.util.List;
 import java.util.Map;
 
@@ -66,10 +66,10 @@ public interface CalcitePrepare {
           return new CalcitePrepareImpl();
         }
       };
-  ThreadLocal<ArrayList<Context>> THREAD_CONTEXT_STACK =
-      new ThreadLocal<ArrayList<Context>>() {
-        @Override protected ArrayList<Context> initialValue() {
-          return new ArrayList<>();
+  ThreadLocal<Deque<Context>> THREAD_CONTEXT_STACK =
+      new ThreadLocal<Deque<Context>>() {
+        @Override protected Deque<Context> initialValue() {
+          return new ArrayDeque<>();
         }
       };
 
@@ -174,15 +174,16 @@ public interface CalcitePrepare {
     }
 
     public static void push(Context context) {
-      Stacks.push(THREAD_CONTEXT_STACK.get(), context);
+      THREAD_CONTEXT_STACK.get().push(context);
     }
 
     public static Context peek() {
-      return Stacks.peek(THREAD_CONTEXT_STACK.get());
+      return THREAD_CONTEXT_STACK.get().peek();
     }
 
     public static void pop(Context context) {
-      Stacks.pop(THREAD_CONTEXT_STACK.get(), context);
+      Context x = THREAD_CONTEXT_STACK.get().pop();
+      assert x == context;
     }
 
     /** Implementation of {@link SparkHandler} that either does nothing or

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/model/ModelHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/model/ModelHandler.java b/core/src/main/java/org/apache/calcite/model/ModelHandler.java
index 6b04a91..f7aa5c6 100644
--- a/core/src/main/java/org/apache/calcite/model/ModelHandler.java
+++ b/core/src/main/java/org/apache/calcite/model/ModelHandler.java
@@ -47,22 +47,19 @@ import com.google.common.collect.ImmutableMap;
 import java.io.File;
 import java.io.IOException;
 import java.sql.SQLException;
-import java.util.ArrayList;
+import java.util.ArrayDeque;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.List;
 import java.util.Map;
 import javax.sql.DataSource;
 
-import static org.apache.calcite.util.Stacks.peek;
-import static org.apache.calcite.util.Stacks.pop;
-import static org.apache.calcite.util.Stacks.push;
-
 /**
  * Reads a model and creates schema objects accordingly.
  */
 public class ModelHandler {
   private final CalciteConnection connection;
-  private final List<Pair<String, SchemaPlus>> schemaStack = new ArrayList<>();
+  private final Deque<Pair<String, SchemaPlus>> schemaStack = new ArrayDeque<>();
   private final String modelUri;
   Lattice.Builder latticeBuilder;
   Lattice.TileBuilder tileBuilder;
@@ -139,11 +136,12 @@ public class ModelHandler {
   public void visit(JsonRoot root) {
     final Pair<String, SchemaPlus> pair =
         Pair.of(null, connection.getRootSchema());
-    push(schemaStack, pair);
+    schemaStack.push(pair);
     for (JsonSchema schema : root.schemas) {
       schema.accept(this);
     }
-    pop(schemaStack, pair);
+    final Pair<String, SchemaPlus> p = schemaStack.pop();
+    assert p == pair;
     if (root.defaultSchema != null) {
       try {
         connection.setSchema(root.defaultSchema);
@@ -199,9 +197,10 @@ public class ModelHandler {
       schema.setCacheEnabled(jsonSchema.cache);
     }
     final Pair<String, SchemaPlus> pair = Pair.of(jsonSchema.name, schema);
-    push(schemaStack, pair);
+    schemaStack.push(pair);
     jsonSchema.visitChildren(this);
-    pop(schemaStack, pair);
+    final Pair<String, SchemaPlus> p = schemaStack.pop();
+    assert p == pair;
   }
 
   public void visit(JsonCustomSchema jsonSchema) {
@@ -356,15 +355,15 @@ public class ModelHandler {
   }
 
   private List<String> currentSchemaPath() {
-    return Collections.singletonList(peek(schemaStack).left);
+    return Collections.singletonList(schemaStack.peek().left);
   }
 
   private SchemaPlus currentSchema() {
-    return peek(schemaStack).right;
+    return schemaStack.peek().right;
   }
 
   private String currentSchemaName() {
-    return peek(schemaStack).left;
+    return schemaStack.peek().left;
   }
 
   private SchemaPlus currentMutableSchema(String elementType) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java b/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java
index f14a681..9fa5b2b 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RuleQueue.java
@@ -22,7 +22,6 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelNodes;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.util.ChunkList;
-import org.apache.calcite.util.Stacks;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.trace.CalciteTrace;
 
@@ -32,11 +31,13 @@ import com.google.common.collect.Multimap;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Deque;
 import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -68,15 +69,14 @@ class RuleQueue {
   /**
    * The importance of each subset.
    */
-  final Map<RelSubset, Double> subsetImportances =
-      new HashMap<RelSubset, Double>();
+  final Map<RelSubset, Double> subsetImportances = new HashMap<>();
 
   /**
    * The set of RelSubsets whose importance is currently in an artificially
    * raised state. Typically this only includes RelSubsets which have only
    * logical RelNodes.
    */
-  final Set<RelSubset> boostedSubsets = new HashSet<RelSubset>();
+  final Set<RelSubset> boostedSubsets = new HashSet<>();
 
   /**
    * Map of {@link VolcanoPlannerPhase} to a list of rule-matches. Initially,
@@ -87,8 +87,7 @@ class RuleQueue {
    * work.
    */
   final Map<VolcanoPlannerPhase, PhaseMatchList> matchListMap =
-      new EnumMap<VolcanoPlannerPhase, PhaseMatchList>(
-          VolcanoPlannerPhase.class);
+      new EnumMap<>(VolcanoPlannerPhase.class);
 
   /**
    * Sorts rule-matches into decreasing order of importance.
@@ -115,8 +114,7 @@ class RuleQueue {
   RuleQueue(VolcanoPlanner planner) {
     this.planner = planner;
 
-    phaseRuleMapping = new EnumMap<VolcanoPlannerPhase, Set<String>>(
-        VolcanoPlannerPhase.class);
+    phaseRuleMapping = new EnumMap<>(VolcanoPlannerPhase.class);
 
     // init empty sets for all phases
     for (VolcanoPlannerPhase phase : VolcanoPlannerPhase.values()) {
@@ -225,8 +223,8 @@ class RuleQueue {
     if (LOGGER.isLoggable(Level.FINER)) {
       LOGGER.finer("boostImportance(" + factor + ", " + subsets + ")");
     }
-    ArrayList<RelSubset> boostRemovals = new ArrayList<RelSubset>();
-    Iterator<RelSubset> iter = boostedSubsets.iterator();
+    final List<RelSubset> boostRemovals = new ArrayList<>();
+    final Iterator<RelSubset> iter = boostedSubsets.iterator();
     while (iter.hasNext()) {
       RelSubset subset = iter.next();
 
@@ -538,7 +536,7 @@ class RuleQueue {
     //   Project(A, X = X + 0 + 0)
     //   Project(A, X = X + 0 + 0 + 0)
     // also in the same subset. They are valid but useless.
-    final List<RelSubset> subsets = new ArrayList<RelSubset>();
+    final Deque<RelSubset> subsets = new ArrayDeque<>();
     try {
       checkDuplicateSubsets(subsets, match.rule.getOperand(), match.rels);
     } catch (Util.FoundOne e) {
@@ -563,18 +561,19 @@ class RuleQueue {
    *
    * @throws org.apache.calcite.util.Util.FoundOne on match
    */
-  private void checkDuplicateSubsets(List<RelSubset> subsets,
+  private void checkDuplicateSubsets(Deque<RelSubset> subsets,
       RelOptRuleOperand operand, RelNode[] rels) {
     final RelSubset subset = planner.getSubset(rels[operand.ordinalInRule]);
     if (subsets.contains(subset)) {
       throw Util.FoundOne.NULL;
     }
     if (!operand.getChildOperands().isEmpty()) {
-      Stacks.push(subsets, subset);
+      subsets.push(subset);
       for (RelOptRuleOperand childOperand : operand.getChildOperands()) {
         checkDuplicateSubsets(subsets, childOperand, rels);
       }
-      Stacks.pop(subsets, subset);
+      final RelSubset x = subsets.pop();
+      assert x == subset;
     }
   }
 
@@ -696,7 +695,7 @@ class RuleQueue {
      * A set of rule-match names contained in {@link #list}. Allows fast
      * detection of duplicate rule-matches.
      */
-    final Set<String> names = new HashSet<String>();
+    final Set<String> names = new HashSet<>();
 
     /**
      * Multi-map of RelSubset to VolcanoRuleMatches. Used to

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
index 530148c..74af6ce 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
@@ -91,11 +91,13 @@ import com.google.common.collect.Sets;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
@@ -108,10 +110,6 @@ import java.util.logging.Level;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static org.apache.calcite.util.Stacks.peek;
-import static org.apache.calcite.util.Stacks.pop;
-import static org.apache.calcite.util.Stacks.push;
-
 /**
  * VolcanoPlanner optimizes queries by transforming expressions selectively
  * according to a dynamic programming algorithm.
@@ -263,7 +261,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
 
   final Map<RelNode, Provenance> provenanceMap = new HashMap<>();
 
-  private final List<VolcanoRuleCall> ruleCallStack = new ArrayList<>();
+  private final Deque<VolcanoRuleCall> ruleCallStack = new ArrayDeque<>();
 
   /** Zero cost, according to {@link #costFactory}. Not necessarily a
    * {@link org.apache.calcite.plan.volcano.VolcanoCost}. */
@@ -1678,12 +1676,10 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
     rel = rel.onRegister(this);
 
     // Record its provenance. (Rule call may be null.)
-    final VolcanoRuleCall ruleCall;
     if (ruleCallStack.isEmpty()) {
-      ruleCall = null;
       provenanceMap.put(rel, Provenance.EMPTY);
     } else {
-      ruleCall = peek(ruleCallStack);
+      final VolcanoRuleCall ruleCall = ruleCallStack.peek();
       provenanceMap.put(
           rel,
           new RuleProvenance(
@@ -1957,9 +1953,9 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
       RelNode rel,
       RelNode equivRel,
       VolcanoRuleCall ruleCall) {
-    push(ruleCallStack, ruleCall);
+    ruleCallStack.push(ruleCall);
     ensureRegistered(rel, equivRel);
-    pop(ruleCallStack, ruleCall);
+    ruleCallStack.pop();
   }
 
   //~ Inner Classes ----------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/rel/RelShuttleImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelShuttleImpl.java b/core/src/main/java/org/apache/calcite/rel/RelShuttleImpl.java
index bd83126..a28f2b5 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelShuttleImpl.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelShuttleImpl.java
@@ -30,9 +30,10 @@ import org.apache.calcite.rel.logical.LogicalProject;
 import org.apache.calcite.rel.logical.LogicalSort;
 import org.apache.calcite.rel.logical.LogicalUnion;
 import org.apache.calcite.rel.logical.LogicalValues;
-import org.apache.calcite.util.Stacks;
 
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Deque;
 import java.util.List;
 
 /**
@@ -42,24 +43,23 @@ import java.util.List;
  * any children change.
  */
 public class RelShuttleImpl implements RelShuttle {
-  protected final List<RelNode> stack = new ArrayList<RelNode>();
+  protected final Deque<RelNode> stack = new ArrayDeque<>();
 
   /**
    * Visits a particular child of a parent.
    */
   protected RelNode visitChild(RelNode parent, int i, RelNode child) {
-    Stacks.push(stack, parent);
+    stack.push(parent);
     try {
       RelNode child2 = child.accept(this);
       if (child2 != child) {
-        final List<RelNode> newInputs =
-            new ArrayList<RelNode>(parent.getInputs());
+        final List<RelNode> newInputs = new ArrayList<>(parent.getInputs());
         newInputs.set(i, child2);
         return parent.copy(parent.getTraitSet(), newInputs);
       }
       return parent;
     } finally {
-      Stacks.pop(stack, parent);
+      stack.pop();
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/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 1036ea4..1fe0218 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
@@ -58,14 +58,15 @@ import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.Pair;
-import org.apache.calcite.util.Stacks;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -844,7 +845,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
 
     private final List<RexNode> removableCasts;
 
-    private final List<SqlOperator> parentCallTypeStack;
+    private final Deque<SqlOperator> parentCallTypeStack = new ArrayDeque<>();
 
     ReducibleExprLocator(RelDataTypeFactory typeFactory,
         ImmutableMap<RexNode, ? extends RexNode> constants,
@@ -858,7 +859,6 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
       this.addCasts = addCasts;
       this.removableCasts = removableCasts;
       this.stack = Lists.newArrayList();
-      this.parentCallTypeStack = Lists.newArrayList();
     }
 
     public void analyze(RexNode exp) {
@@ -904,7 +904,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
       if (parentCallTypeStack.isEmpty()) {
         addCasts.add(false);
       } else {
-        addCasts.add(isUdf(Stacks.peek(parentCallTypeStack)));
+        addCasts.add(isUdf(parentCallTypeStack.peek()));
       }
     }
 
@@ -943,7 +943,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
     }
 
     private void analyzeCall(RexCall call, Constancy callConstancy) {
-      Stacks.push(parentCallTypeStack, call.getOperator());
+      parentCallTypeStack.push(call.getOperator());
 
       // visit operands, pushing their states onto stack
       super.visitCall(call);
@@ -997,7 +997,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
       operandStack.clear();
 
       // pop this parent call operator off the stack
-      Stacks.pop(parentCallTypeStack, call.getOperator());
+      parentCallTypeStack.pop();
 
       // push constancy result for this call onto stack
       stack.add(callConstancy);

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/sql/SqlIntervalLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIntervalLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlIntervalLiteral.java
index 119c73e..ff47657 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlIntervalLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlIntervalLiteral.java
@@ -18,6 +18,7 @@ package org.apache.calcite.sql;
 
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Util;
 
 /**
@@ -122,13 +123,13 @@ public class SqlIntervalLiteral extends SqlLiteral {
       IntervalValue that = (IntervalValue) obj;
       return this.intervalStr.equals(that.intervalStr)
           && (this.sign == that.sign)
-          && this.intervalQualifier.equalsDeep(that.intervalQualifier, false);
+          && this.intervalQualifier.equalsDeep(that.intervalQualifier,
+              Litmus.IGNORE);
     }
 
     public int hashCode() {
       int h = Util.hash(sign, intervalStr);
-      int i = Util.hash(h, intervalQualifier);
-      return i;
+      return Util.hash(h, intervalQualifier);
     }
 
     public SqlIntervalQualifier getIntervalQualifier() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java b/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
index 39a7f3c..ca5138a 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
@@ -24,10 +24,10 @@ import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlSelect;
 import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.util.SqlBasicVisitor;
-import org.apache.calcite.util.Stacks;
-
-import com.google.common.collect.Lists;
+import org.apache.calcite.util.Litmus;
 
+import java.util.ArrayDeque;
+import java.util.Deque;
 import java.util.List;
 
 import static org.apache.calcite.util.Static.RESOURCE;
@@ -39,7 +39,7 @@ import static org.apache.calcite.util.Static.RESOURCE;
 class AggChecker extends SqlBasicVisitor<Void> {
   //~ Instance fields --------------------------------------------------------
 
-  private final List<SqlValidatorScope> scopes = Lists.newArrayList();
+  private final Deque<SqlValidatorScope> scopes = new ArrayDeque<>();
   private final List<SqlNode> groupExprs;
   private boolean distinct;
   private SqlValidatorImpl validator;
@@ -64,14 +64,14 @@ class AggChecker extends SqlBasicVisitor<Void> {
     this.validator = validator;
     this.groupExprs = groupExprs;
     this.distinct = distinct;
-    Stacks.push(this.scopes, scope);
+    this.scopes.push(scope);
   }
 
   //~ Methods ----------------------------------------------------------------
 
   boolean isGroupExpr(SqlNode expr) {
     for (SqlNode groupExpr : groupExprs) {
-      if (groupExpr.equalsDeep(expr, false)) {
+      if (groupExpr.equalsDeep(expr, Litmus.IGNORE)) {
         return true;
       }
     }
@@ -101,7 +101,7 @@ class AggChecker extends SqlBasicVisitor<Void> {
     // it fully-qualified.
     // TODO: It would be better if we always compared fully-qualified
     // to fully-qualified.
-    final SqlQualified fqId = Stacks.peek(scopes).fullyQualify(id);
+    final SqlQualified fqId = scopes.peek().fullyQualify(id);
     if (isGroupExpr(fqId.identifier)) {
       return null;
     }
@@ -114,7 +114,7 @@ class AggChecker extends SqlBasicVisitor<Void> {
   }
 
   public Void visit(SqlCall call) {
-    final SqlValidatorScope scope = Stacks.peek(scopes);
+    final SqlValidatorScope scope = scopes.peek();
     if (call.getOperator().isAggregator()) {
       if (distinct) {
         if (scope instanceof AggregatingSelectScope) {
@@ -127,7 +127,8 @@ class AggChecker extends SqlBasicVisitor<Void> {
               sqlNode = ((SqlCall) sqlNode).operand(0);
             }
 
-            if (validator.expand(sqlNode, scope).equalsDeep(call, false)) {
+            if (validator.expand(sqlNode, scope)
+                .equalsDeep(call, Litmus.IGNORE)) {
               return null;
             }
           }
@@ -150,7 +151,7 @@ class AggChecker extends SqlBasicVisitor<Void> {
     }
     // Visit the operand in window function
     if (call.getOperator().getKind() == SqlKind.OVER) {
-      SqlCall windowFunction = (SqlCall) call.operand(0);
+      SqlCall windowFunction = call.operand(0);
       if (windowFunction.getOperandList().size() != 0) {
         windowFunction.operand(0).accept(this);
       }
@@ -167,14 +168,14 @@ class AggChecker extends SqlBasicVisitor<Void> {
 
     // Switch to new scope.
     SqlValidatorScope newScope = scope.getOperandScope(call);
-    Stacks.push(scopes, newScope);
+    scopes.push(newScope);
 
     // Visit the operands (only expressions).
     call.getOperator()
         .acceptCall(this, call, true, ArgHandlerImpl.<Void>instance());
 
     // Restore scope.
-    Stacks.pop(scopes, newScope);
+    scopes.pop();
     return null;
   }
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/sql/validate/AggregatingSelectScope.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AggregatingSelectScope.java b/core/src/main/java/org/apache/calcite/sql/validate/AggregatingSelectScope.java
index 580e71c..cc884ee 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/AggregatingSelectScope.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/AggregatingSelectScope.java
@@ -24,6 +24,7 @@ import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlSelect;
 import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.Litmus;
 
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
@@ -176,7 +177,7 @@ public class AggregatingSelectScope
   @Override public RelDataType nullifyType(SqlNode node, RelDataType type) {
     final Resolved r = this.resolved.get();
     for (Ord<SqlNode> groupExpr : Ord.zip(r.groupExprList)) {
-      if (groupExpr.e.equalsDeep(node, false)) {
+      if (groupExpr.e.equalsDeep(node, Litmus.IGNORE)) {
         if (r.isNullable(groupExpr.i)) {
           return validator.getTypeFactory().createTypeWithNullability(type,
               true);
@@ -272,7 +273,7 @@ public class AggregatingSelectScope
 
     public int lookupGroupingExpr(SqlNode operand) {
       for (Ord<SqlNode> groupExpr : Ord.zip(groupExprList)) {
-        if (operand.equalsDeep(groupExpr.e, false)) {
+        if (operand.equalsDeep(groupExpr.e, Litmus.IGNORE)) {
           return groupExpr.i;
         }
       }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/sql/validate/OverScope.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/OverScope.java b/core/src/main/java/org/apache/calcite/sql/validate/OverScope.java
index 7f980e2..9d95513 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/OverScope.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/OverScope.java
@@ -18,6 +18,7 @@ package org.apache.calcite.sql.validate;
 
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Pair;
 
 import java.util.List;
@@ -78,7 +79,7 @@ public class OverScope extends ListScope {
       final List<Pair<SqlNode, SqlMonotonicity>> monotonicExprs =
           child.getMonotonicExprs();
       for (Pair<SqlNode, SqlMonotonicity> pair : monotonicExprs) {
-        if (expr.equalsDeep(pair.left, false)) {
+        if (expr.equalsDeep(pair.left, Litmus.IGNORE)) {
           return pair.right;
         }
       }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/sql/validate/SelectScope.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SelectScope.java b/core/src/main/java/org/apache/calcite/sql/validate/SelectScope.java
index ea6db19..c53cb99 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SelectScope.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SelectScope.java
@@ -24,6 +24,7 @@ import org.apache.calcite.sql.SqlSelect;
 import org.apache.calcite.sql.SqlWindow;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Pair;
 
 import java.util.ArrayList;
@@ -88,7 +89,7 @@ public class SelectScope extends ListScope {
   //~ Instance fields --------------------------------------------------------
 
   private final SqlSelect select;
-  protected final List<String> windowNames = new ArrayList<String>();
+  protected final List<String> windowNames = new ArrayList<>();
 
   private List<SqlNode> expandedSelectList = null;
 
@@ -167,7 +168,7 @@ public class SelectScope extends ListScope {
         monotonicity = monotonicity.reverse();
         order0 = ((SqlCall) order0).operand(0);
       }
-      if (expr.equalsDeep(order0, false)) {
+      if (expr.equalsDeep(order0, Litmus.IGNORE)) {
         return monotonicity;
       }
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index 00b8611..ebc7ad0 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -77,6 +77,7 @@ import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.util.SqlShuttle;
 import org.apache.calcite.sql.util.SqlVisitor;
 import org.apache.calcite.util.BitString;
+import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Static;
 import org.apache.calcite.util.Util;
@@ -1071,7 +1072,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
           SqlNode sqlNode = orderList.get(i);
           SqlNodeList selectList2 = getInnerSelect(node).getSelectList();
           for (Ord<SqlNode> sel : Ord.zip(selectList2)) {
-            if (stripAs(sel.e).equalsDeep(sqlNode, false)) {
+            if (stripAs(sel.e).equalsDeep(sqlNode, Litmus.IGNORE)) {
               orderList.set(i,
                   SqlLiteral.createExactNumeric(Integer.toString(sel.i + 1),
                       SqlParserPos.ZERO));
@@ -3163,7 +3164,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
       SqlNode window1 = windowList.get(i);
       for (int j = i + 1; j < windowList.size(); j++) {
         SqlNode window2 = windowList.get(j);
-        if (window1.equalsDeep(window2, false)) {
+        if (window1.equalsDeep(window2, Litmus.IGNORE)) {
           throw newValidationError(window2, RESOURCE.dupWindowSpec());
         }
       }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
index 3ddeed4..ac03caa 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
@@ -38,6 +38,7 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Util;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -242,7 +243,7 @@ public class SqlValidatorUtil {
   public static List<String> uniquify(
       List<String> nameList,
       Suggester suggester) {
-    Set<String> used = new LinkedHashSet<String>();
+    final Set<String> used = new LinkedHashSet<>();
     int changeCount = 0;
     for (String name : nameList) {
       String uniqueName = uniquify(name, used, suggester);
@@ -252,7 +253,7 @@ public class SqlValidatorUtil {
     }
     return changeCount == 0
         ? nameList
-        : new ArrayList<String>(used);
+        : new ArrayList<>(used);
   }
 
   /**
@@ -329,7 +330,7 @@ public class SqlValidatorUtil {
   public static List<String> deriveNaturalJoinColumnList(
       RelDataType leftRowType,
       RelDataType rightRowType) {
-    List<String> naturalColumnNames = new ArrayList<String>();
+    final List<String> naturalColumnNames = new ArrayList<>();
     final List<String> leftNames = leftRowType.getFieldNames();
     final List<String> rightNames = rightRowType.getFieldNames();
     for (String name : leftNames) {
@@ -348,7 +349,7 @@ public class SqlValidatorUtil {
     // the resulting type will use those from type. These are presumably more
     // canonical.
     final List<RelDataTypeField> fields =
-        new ArrayList<RelDataTypeField>(columnNameList.size());
+        new ArrayList<>(columnNameList.size());
     for (String name : columnNameList) {
       RelDataTypeField field = type.getField(name, caseSensitive, elideRecord);
       fields.add(type.getFieldList().get(field.getIndex()));
@@ -516,7 +517,7 @@ public class SqlValidatorUtil {
 
   private static int lookupGroupExpr(List<SqlNode> groupExprs, SqlNode expr) {
     for (Ord<SqlNode> node : Ord.zip(groupExprs)) {
-      if (node.e.equalsDeep(expr, false)) {
+      if (node.e.equalsDeep(expr, Litmus.IGNORE)) {
         return node.i;
       }
     }
@@ -616,6 +617,7 @@ public class SqlValidatorUtil {
    * Walks over an expression, copying every node, and fully-qualifying every
    * identifier.
    */
+  @Deprecated // to be removed before 2.0
   public static class DeepCopier extends SqlScopedShuttle {
     DeepCopier(SqlValidatorScope scope) {
       super(scope);

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index 099bb9a..5d58f3f 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -80,7 +80,6 @@ import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.ReflectUtil;
 import org.apache.calcite.util.ReflectiveVisitor;
-import org.apache.calcite.util.Stacks;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.mapping.Mappings;
 import org.apache.calcite.util.trace.CalciteTrace;
@@ -99,9 +98,11 @@ import com.google.common.collect.Sets;
 import com.google.common.collect.SortedSetMultimap;
 
 import java.math.BigDecimal;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -2469,7 +2470,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
     final Holder<Integer> offset = Holder.of(0);
     int corrIdGenerator = 0;
 
-    final List<RelNode> stack = new ArrayList<>();
+    final Deque<RelNode> stack = new ArrayDeque<>();
 
     /** Creates a CorelMap by iterating over a {@link RelNode} tree. */
     CorelMap build(RelNode rel) {
@@ -2480,10 +2481,10 @@ public class RelDecorrelator implements ReflectiveVisitor {
 
     @Override public RelNode visit(LogicalJoin join) {
       try {
-        Stacks.push(stack, join);
+        stack.push(join);
         join.getCondition().accept(rexVisitor(join));
       } finally {
-        Stacks.pop(stack, join);
+        stack.pop();
       }
       return visitJoin(join);
     }
@@ -2509,22 +2510,22 @@ public class RelDecorrelator implements ReflectiveVisitor {
 
     @Override public RelNode visit(final LogicalFilter filter) {
       try {
-        Stacks.push(stack, filter);
+        stack.push(filter);
         filter.getCondition().accept(rexVisitor(filter));
       } finally {
-        Stacks.pop(stack, filter);
+        stack.pop();
       }
       return super.visit(filter);
     }
 
     @Override public RelNode visit(LogicalProject project) {
       try {
-        Stacks.push(stack, project);
+        stack.push(project);
         for (RexNode node : project.getProjects()) {
           node.accept(rexVisitor(project));
         }
       } finally {
-        Stacks.pop(stack, project);
+        stack.pop();
       }
       return super.visit(project);
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/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 a85c79a..a17df51 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -2792,17 +2792,15 @@ public class SqlToRelConverter {
     int ordinal = -1;
     for (SqlNode selectItem : selectScope.getExpandedSelectList()) {
       ++ordinal;
-      if (converted.equalsDeep(stripAs(selectItem), false)) {
-        return new RelFieldCollation(
-            ordinal, direction, nullDirection);
+      if (converted.equalsDeep(stripAs(selectItem), Litmus.IGNORE)) {
+        return new RelFieldCollation(ordinal, direction, nullDirection);
       }
     }
 
     for (SqlNode extraExpr : extraExprs) {
       ++ordinal;
-      if (converted.equalsDeep(extraExpr, false)) {
-        return new RelFieldCollation(
-            ordinal, direction, nullDirection);
+      if (converted.equalsDeep(extraExpr, Litmus.IGNORE)) {
+        return new RelFieldCollation(ordinal, direction, nullDirection);
       }
     }
 
@@ -4024,7 +4022,7 @@ public class SqlToRelConverter {
 
     void registerSubquery(SqlNode node, RelOptUtil.Logic logic) {
       for (SubQuery subQuery : subqueryList) {
-        if (node.equalsDeep(subQuery.node, false)) {
+        if (node.equalsDeep(subQuery.node, Litmus.IGNORE)) {
           return;
         }
       }
@@ -4033,7 +4031,7 @@ public class SqlToRelConverter {
 
     SubQuery getSubquery(SqlNode expr) {
       for (SubQuery subQuery : subqueryList) {
-        if (expr.equalsDeep(subQuery.node, false)) {
+        if (expr.equalsDeep(subQuery.node, Litmus.IGNORE)) {
           return subQuery;
         }
       }
@@ -4663,7 +4661,7 @@ public class SqlToRelConverter {
     public int lookupGroupExpr(SqlNode expr) {
       for (int i = 0; i < groupExprs.size(); i++) {
         SqlNode groupExpr = groupExprs.get(i);
-        if (expr.equalsDeep(groupExpr, false)) {
+        if (expr.equalsDeep(groupExpr, Litmus.IGNORE)) {
           return i;
         }
       }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index 32d3b6b..54398a6 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -58,7 +58,6 @@ import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Pair;
-import org.apache.calcite.util.Stacks;
 import org.apache.calcite.util.Static;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.mapping.Mapping;
@@ -73,7 +72,9 @@ import com.google.common.collect.Lists;
 
 import java.math.BigDecimal;
 import java.util.AbstractList;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Deque;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -118,7 +119,7 @@ public class RelBuilder {
   private final RelFactories.CorrelateFactory correlateFactory;
   private final RelFactories.ValuesFactory valuesFactory;
   private final RelFactories.TableScanFactory scanFactory;
-  private final List<Frame> stack = new ArrayList<>();
+  private final Deque<Frame> stack = new ArrayDeque<>();
 
   protected RelBuilder(Context context, RelOptCluster cluster,
       RelOptSchema relOptSchema) {
@@ -210,7 +211,7 @@ public class RelBuilder {
    * you need to use previously built expressions as inputs, call
    * {@link #build()} to pop those inputs. */
   public RelBuilder push(RelNode node) {
-    Stacks.push(stack, new Frame(node));
+    stack.push(new Frame(node));
     return this;
   }
 
@@ -227,25 +228,25 @@ public class RelBuilder {
    * <p>Throws if the stack is empty.
    */
   public RelNode build() {
-    return Stacks.pop(stack).rel;
+    return stack.pop().rel;
   }
 
   /** Returns the relational expression at the top of the stack, but does not
    * remove it. */
   public RelNode peek() {
-    return Stacks.peek(stack).rel;
+    return stack.peek().rel;
   }
 
   /** Returns the relational expression {@code n} positions from the top of the
    * stack, but does not remove it. */
   public RelNode peek(int n) {
-    return Stacks.peek(n, stack).rel;
+    return Iterables.get(stack, n).rel;
   }
 
   /** Returns the relational expression {@code n} positions from the top of the
    * stack, but does not remove it. */
   public RelNode peek(int inputCount, int inputOrdinal) {
-    return Stacks.peek(inputCount - 1 - inputOrdinal, stack).rel;
+    return peek(inputCount - 1 - inputOrdinal);
   }
 
   // Methods that return scalar expressions
@@ -333,7 +334,7 @@ public class RelBuilder {
   public RexNode field(String alias, String fieldName) {
     Preconditions.checkNotNull(alias);
     Preconditions.checkNotNull(fieldName);
-    final Frame frame = Stacks.peek(stack);
+    final Frame frame = stack.peek();
     final List<String> aliases = new ArrayList<>();
     int offset = 0;
     for (Pair<String, RelDataType> pair : frame.right) {
@@ -701,9 +702,9 @@ public class RelBuilder {
       return empty();
     }
     if (!x.isAlwaysTrue()) {
-      final Frame frame = Stacks.pop(stack);
+      final Frame frame = stack.pop();
       final RelNode filter = filterFactory.createFilter(frame.rel, x);
-      Stacks.push(stack, new Frame(filter, frame.right));
+      stack.push(new Frame(filter, frame.right));
     }
     return this;
   }
@@ -1009,8 +1010,8 @@ public class RelBuilder {
    * variables. */
   public RelBuilder join(JoinRelType joinType, RexNode condition,
       Set<CorrelationId> variablesSet) {
-    final Frame right = Stacks.pop(stack);
-    final Frame left = Stacks.pop(stack);
+    final Frame right = stack.pop();
+    final Frame left = stack.pop();
     final RelNode join;
     final boolean correlate = variablesSet.size() == 1;
     if (correlate) {
@@ -1030,7 +1031,7 @@ public class RelBuilder {
     final List<Pair<String, RelDataType>> pairs = new ArrayList<>();
     pairs.addAll(left.right);
     pairs.addAll(right.right);
-    Stacks.push(stack, new Frame(join, ImmutableList.copyOf(pairs)));
+    stack.push(new Frame(join, ImmutableList.copyOf(pairs)));
     if (correlate) {
       filter(condition);
     }
@@ -1059,11 +1060,11 @@ public class RelBuilder {
 
   /** Creates a {@link org.apache.calcite.rel.core.SemiJoin}. */
   public RelBuilder semiJoin(Iterable<? extends RexNode> conditions) {
-    final Frame right = Stacks.pop(stack);
-    final Frame left = Stacks.pop(stack);
+    final Frame right = stack.pop();
+    final Frame left = stack.pop();
     final RelNode semiJoin =
         semiJoinFactory.createSemiJoin(left.rel, right.rel, and(conditions));
-    Stacks.push(stack, new Frame(semiJoin, left.right));
+    stack.push(new Frame(semiJoin, left.right));
     return this;
   }
 
@@ -1074,8 +1075,8 @@ public class RelBuilder {
 
   /** Assigns a table alias to the top entry on the stack. */
   public RelBuilder as(String alias) {
-    final Frame pair = Stacks.pop(stack);
-    Stacks.push(stack,
+    final Frame pair = stack.pop();
+    stack.push(
         new Frame(pair.rel,
             ImmutableList.of(Pair.of(alias, pair.rel.getRowType()))));
     return this;
@@ -1172,7 +1173,7 @@ public class RelBuilder {
    * schema.
    */
   public RelBuilder empty() {
-    final Frame frame = Stacks.pop(stack);
+    final Frame frame = stack.pop();
     return values(frame.rel.getRowType());
   }
 
@@ -1309,7 +1310,7 @@ public class RelBuilder {
       if (top instanceof Sort) {
         final Sort sort2 = (Sort) top;
         if (sort2.offset == null && sort2.fetch == null) {
-          Stacks.pop(stack);
+          stack.pop();
           push(sort2.getInput());
           final RelNode sort =
               sortFactory.createSort(build(), sort2.collation,
@@ -1323,7 +1324,7 @@ public class RelBuilder {
         if (project.getInput() instanceof Sort) {
           final Sort sort2 = (Sort) project.getInput();
           if (sort2.offset == null && sort2.fetch == null) {
-            Stacks.pop(stack);
+            stack.pop();
             push(sort2.getInput());
             final RelNode sort =
                 sortFactory.createSort(build(), sort2.collation,
@@ -1421,7 +1422,7 @@ public class RelBuilder {
   }
 
   protected String getAlias() {
-    final Frame frame = Stacks.peek(stack);
+    final Frame frame = stack.peek();
     return frame.right.size() == 1
         ? frame.right.get(0).left
         : null;

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/util/PartiallyOrderedSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/PartiallyOrderedSet.java b/core/src/main/java/org/apache/calcite/util/PartiallyOrderedSet.java
index 200e1c9..b73a257 100644
--- a/core/src/main/java/org/apache/calcite/util/PartiallyOrderedSet.java
+++ b/core/src/main/java/org/apache/calcite/util/PartiallyOrderedSet.java
@@ -18,15 +18,16 @@ package org.apache.calcite.util;
 
 import java.util.AbstractList;
 import java.util.AbstractSet;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
@@ -102,8 +103,8 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
   private PartiallyOrderedSet(Ordering<E> ordering, Map<E, Node<E>> map) {
     this.ordering = ordering;
     this.map = map;
-    this.topNode = new TopBottomNode<E>(true);
-    this.bottomNode = new TopBottomNode<E>(false);
+    this.topNode = new TopBottomNode<>(true);
+    this.bottomNode = new TopBottomNode<>(false);
     this.topNode.childList.add(bottomNode);
     this.bottomNode.parentList.add(topNode);
   }
@@ -186,7 +187,7 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
     Set<Node<E>> parents = findParents(e);
     Set<Node<E>> children = findChildren(e);
 
-    node = new Node<E>(e);
+    node = new Node<>(e);
 
     for (Node<E> parent : parents) {
       node.parentList.add(parent);
@@ -213,7 +214,7 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
     }
 
     // Nodes reachable from parents.
-    final Set<Node<E>> childSet = new HashSet<Node<E>>(node.childList);
+    final Set<Node<E>> childSet = new HashSet<>(node.childList);
     for (Node<E> child : children) {
       if (!isDescendantOfAny(child, childSet)) {
         node.childList.add(child);
@@ -239,8 +240,8 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
   private boolean isDescendantOfAny(
       Node<E> node,
       Set<Node<E>> nodeSet) {
-    final ArrayDeque<Node<E>> deque = new ArrayDeque<Node<E>>();
-    final Set<Node<E>> seen = new HashSet<Node<E>>();
+    final Deque<Node<E>> deque = new ArrayDeque<>();
+    final Set<Node<E>> seen = new HashSet<>();
     deque.add(node);
     while (!deque.isEmpty()) {
       final Node<E> node1 = deque.pop();
@@ -257,22 +258,22 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
   }
 
   private Set<Node<E>> findChildren(E e) {
-    ArrayDeque<Node<E>> descendants = new ArrayDeque<Node<E>>();
+    final Deque<Node<E>> descendants = new ArrayDeque<>();
     descendants.add(bottomNode);
     return findParentsChildren(e, descendants, false);
   }
 
   private Set<Node<E>> findParents(E e) {
-    ArrayDeque<Node<E>> ancestors = new ArrayDeque<Node<E>>();
+    final Deque<Node<E>> ancestors = new ArrayDeque<>();
     ancestors.add(topNode);
     return findParentsChildren(e, ancestors, true);
   }
 
   private Set<Node<E>> findParentsChildren(
       E e,
-      ArrayDeque<Node<E>> ancestors,
+      Deque<Node<E>> ancestors,
       boolean up) {
-    final Set<Node<E>> parents = new HashSet<Node<E>>();
+    final Set<Node<E>> parents = new HashSet<>();
     while (!ancestors.isEmpty()) {
       final Node<E> ancestor = ancestors.pop();
       assert ancestor.e == null
@@ -400,8 +401,7 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
         }
       }
     }
-    final Map<Node, Integer> distanceToRoot =
-        new HashMap<Node, Integer>();
+    final Map<Node, Integer> distanceToRoot = new HashMap<>();
     distanceRecurse(distanceToRoot, topNode, 0);
     for (Node<E> node : map.values()) {
       if (!distanceToRoot.containsKey(node)) {
@@ -412,15 +412,11 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
 
     // For each pair of elements, ensure that elements are related if and
     // only if they are in the ancestors or descendants lists.
-    Map<Node<E>, Set<E>> nodeAncestors = new HashMap<Node<E>, Set<E>>();
-    Map<Node<E>, Set<E>> nodeDescendants = new HashMap<Node<E>, Set<E>>();
+    final Map<Node<E>, Set<E>> nodeAncestors = new HashMap<>();
+    final Map<Node<E>, Set<E>> nodeDescendants = new HashMap<>();
     for (Node<E> node : map.values()) {
-      nodeAncestors.put(
-          node,
-          new HashSet<E>(getAncestors(node.e)));
-      nodeDescendants.put(
-          node,
-          new HashSet<E>(getDescendants(node.e)));
+      nodeAncestors.put(node, new HashSet<>(getAncestors(node.e)));
+      nodeDescendants.put(node, new HashSet<>(getDescendants(node.e)));
     }
     for (Node<E> node1 : map.values()) {
       for (Node<E> node2 : map.values()) {
@@ -504,8 +500,8 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
 
     // breadth-first search, to iterate over every element once, printing
     // those nearest the top element first
-    final HashSet<E> seen = new HashSet<E>();
-    final ArrayDeque<E> unseen = new ArrayDeque<E>();
+    final Set<E> seen = new HashSet<>();
+    final Deque<E> unseen = new ArrayDeque<>();
     unseen.addAll(getNonChildren());
     while (!unseen.isEmpty()) {
       E e = unseen.pop();
@@ -549,7 +545,7 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
       // children
       return Collections.emptyList();
     } else {
-      return new StripList<E>(node.childList);
+      return new StripList<>(node.childList);
     }
   }
 
@@ -574,7 +570,7 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
       // parents
       return Collections.emptyList();
     } else {
-      return new StripList<E>(node.parentList);
+      return new StripList<>(node.parentList);
     }
   }
 
@@ -583,7 +579,7 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
         && topNode.childList.get(0).e == null) {
       return Collections.emptyList();
     }
-    return new StripList<E>(topNode.childList);
+    return new StripList<>(topNode.childList);
   }
 
   public List<E> getNonParents() {
@@ -591,7 +587,7 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
         && bottomNode.parentList.get(0).e == null) {
       return Collections.emptyList();
     }
-    return new StripList<E>(bottomNode.parentList);
+    return new StripList<>(bottomNode.parentList);
   }
 
   @Override public void clear() {
@@ -639,10 +635,10 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
     if (c.size() == 1 && c.iterator().next().e == null) {
       return Collections.emptyList();
     }
-    ArrayDeque<Node<E>> deque = new ArrayDeque<Node<E>>(c);
+    final Deque<Node<E>> deque = new ArrayDeque<>(c);
 
-    final Set<Node<E>> seen = new HashSet<Node<E>>();
-    final List<E> list = new ArrayList<E>();
+    final Set<Node<E>> seen = new HashSet<>();
+    final List<E> list = new ArrayList<>();
     while (!deque.isEmpty()) {
       Node<E> node1 = deque.pop();
       list.add(node1.e);
@@ -670,8 +666,8 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
    * @param <E> Element type
    */
   private static class Node<E> {
-    final List<Node<E>> parentList = new ArrayList<Node<E>>();
-    final List<Node<E>> childList = new ArrayList<Node<E>>();
+    final List<Node<E>> parentList = new ArrayList<>();
+    final List<Node<E>> childList = new ArrayList<>();
     final E e;
 
     public Node(E e) {
@@ -750,87 +746,6 @@ public class PartiallyOrderedSet<E> extends AbstractSet<E> {
       return list.size();
     }
   }
-
-  /**
-   * Cut-down version of java.util.ArrayDeque, which is not available until
-   * JDK 1.6.
-   *
-   * @param <E> Element type
-   */
-  private static class ArrayDeque<E> {
-    private E[] es; // length must be multiple of 2
-    private int first;
-    private int last;
-
-    public ArrayDeque() {
-      this(16);
-    }
-
-    public ArrayDeque(Collection<E> nodes) {
-      this(nextPowerOf2(nodes.size()));
-      addAll(nodes);
-    }
-
-    private ArrayDeque(int capacity) {
-      first = last = 0;
-      //noinspection unchecked
-      es = (E[]) new Object[capacity];
-    }
-
-    private static int nextPowerOf2(int v) {
-      // Algorithm from
-      // http://graphics.stanford.edu/~seander/bithacks.html
-      v--;
-      v |= v >> 1;
-      v |= v >> 2;
-      v |= v >> 4;
-      v |= v >> 8;
-      v |= v >> 16;
-      v++;
-      return v;
-    }
-
-    @SuppressWarnings({"SuspiciousSystemArraycopy", "unchecked" })
-    private void expand() {
-      Object[] olds = es;
-      es = (E[]) new Object[es.length * 2];
-      System.arraycopy(olds, 0, es, 0, olds.length);
-      if (last <= first) {
-        final int x = last & (olds.length - 1);
-        System.arraycopy(olds, 0, es, olds.length, x);
-        last += olds.length;
-      }
-    }
-
-    public void add(E e) {
-      es[last] = e;
-      last = (last + 1) & (es.length - 1);
-      if (last == first) {
-        expand();
-      }
-    }
-
-    public boolean isEmpty() {
-      return last == first;
-    }
-
-
-    public E pop() {
-      if (last == first) {
-        throw new NoSuchElementException();
-      }
-      E e = es[first];
-      first = (first + 1) & (es.length - 1);
-      return e;
-    }
-
-
-    public void addAll(Collection<E> list) {
-      for (E e : list) {
-        add(e);
-      }
-    }
-  }
 }
 
 // End PartiallyOrderedSet.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/util/StackWriter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/StackWriter.java b/core/src/main/java/org/apache/calcite/util/StackWriter.java
index da2295c..3e42f50 100644
--- a/core/src/main/java/org/apache/calcite/util/StackWriter.java
+++ b/core/src/main/java/org/apache/calcite/util/StackWriter.java
@@ -20,8 +20,8 @@ import java.io.FilterWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Writer;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.ArrayDeque;
+import java.util.Deque;
 
 /**
  * A helper class for generating formatted text. StackWriter keeps track of
@@ -106,7 +106,7 @@ public class StackWriter extends FilterWriter {
   private int indentationDepth;
   private String indentation;
   private boolean needIndent;
-  private final List<Character> quoteStack = new ArrayList<Character>();
+  private final Deque<Character> quoteStack = new ArrayDeque<>();
 
   //~ Constructors -----------------------------------------------------------
 
@@ -149,11 +149,12 @@ public class StackWriter extends FilterWriter {
 
   private void pushQuote(Character quoteChar) throws IOException {
     writeQuote(quoteChar);
-    Stacks.push(quoteStack, quoteChar);
+    quoteStack.push(quoteChar);
   }
 
   private void popQuote(Character quoteChar) throws IOException {
-    Stacks.pop(quoteStack, quoteChar);
+    final Character pop = quoteStack.pop();
+    assert pop == quoteChar;
     writeQuote(quoteChar);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/util/Stacks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Stacks.java b/core/src/main/java/org/apache/calcite/util/Stacks.java
index 2a41368..408747f 100644
--- a/core/src/main/java/org/apache/calcite/util/Stacks.java
+++ b/core/src/main/java/org/apache/calcite/util/Stacks.java
@@ -21,6 +21,7 @@ import java.util.List;
 /**
  * Utilities to make vanilla lists look like stacks.
  */
+@Deprecated // to be removed before 2.0
 public class Stacks {
   private Stacks() {
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/main/java/org/apache/calcite/util/XmlOutput.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/XmlOutput.java b/core/src/main/java/org/apache/calcite/util/XmlOutput.java
index 4be5669..9392b5a 100644
--- a/core/src/main/java/org/apache/calcite/util/XmlOutput.java
+++ b/core/src/main/java/org/apache/calcite/util/XmlOutput.java
@@ -23,9 +23,10 @@ import java.io.LineNumberReader;
 import java.io.PrintWriter;
 import java.io.StringReader;
 import java.io.Writer;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.List;
+import java.util.Deque;
 
 /**
  * Streaming XML output.
@@ -42,7 +43,7 @@ public class XmlOutput {
   private final PrintWriter out;
 
   // The tagStack is maintained to check that tags are balanced.
-  private final List<String> tagStack = new ArrayList<String>();
+  private final Deque<String> tagStack = new ArrayDeque<>();
 
   // The class maintains an indentation level to improve output quality.
   private int indent;
@@ -210,7 +211,7 @@ public class XmlOutput {
       out.println(">");
     }
     out.flush();
-    Stacks.push(tagStack, tagName);
+    tagStack.push(tagName);
     indent++;
     tagsWritten++;
   }
@@ -245,7 +246,8 @@ public class XmlOutput {
    */
   public void endTag(String tagName) {
     // Check that the end tag matches the corresponding start tag
-    Stacks.pop(tagStack, tagName);
+    String x = tagStack.pop();
+    assert x.equals(tagName);
 
     // Lower the indent and display the end tag
     indent--;

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java
index 26df28d..f66fd86 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java
@@ -24,7 +24,9 @@ import org.apache.calcite.sql.parser.SqlParseException;
 import org.apache.calcite.sql.parser.SqlParser;
 import org.apache.calcite.sql.pretty.SqlPrettyWriter;
 import org.apache.calcite.test.DiffRepository;
+import org.apache.calcite.util.Litmus;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.io.PrintWriter;
@@ -88,7 +90,7 @@ public class SqlPrettyWriterTest {
     // to the original.
     final String actual2 = actual.replaceAll("`", "\"");
     final SqlNode node2 = parseQuery(actual2);
-    assertTrue(node.equalsDeep(node2, true));
+    assertTrue(node.equalsDeep(node2, Litmus.THROW));
   }
 
   protected void assertExprPrintsTo(
@@ -111,7 +113,7 @@ public class SqlPrettyWriterTest {
     // to the original.
     final String actual2 = actual.replaceAll("`", "\"");
     final SqlNode valuesCall2 = parseQuery("VALUES (" + actual2 + ")");
-    assertTrue(valuesCall.equalsDeep(valuesCall2, true));
+    assertTrue(valuesCall.equalsDeep(valuesCall2, Litmus.THROW));
   }
 
   // ~ Tests ----------------------------------------------------------------
@@ -214,8 +216,8 @@ public class SqlPrettyWriterTest {
     checkSimple(prettyWriter, "${desc}", "${formatted}");
   }
 
-  // test disabled because default SQL parser cannot parse DDL
-  public void _testExplain() {
+  @Ignore("default SQL parser cannot parse DDL")
+  @Test public void testExplain() {
     assertPrintsTo(false, "explain select * from t", "foo");
   }
 
@@ -286,7 +288,7 @@ public class SqlPrettyWriterTest {
             + "union select * from w "
             + "order by a, b",
 
-        // todo: SELECT should not be indended from UNION, like this:
+        // todo: SELECT should not be indented from UNION, like this:
         // UNION
         //     SELECT *
         //     FROM `W`

http://git-wip-us.apache.org/repos/asf/calcite/blob/f55d10c1/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
index 529df04..f8f68d0 100644
--- a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
+++ b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
@@ -65,6 +65,7 @@ import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
@@ -439,9 +440,7 @@ public class MockCatalogReader implements Prepare.CatalogReader {
   }
 
   public RelDataType getNamedType(SqlIdentifier typeName) {
-    if (typeName.equalsDeep(
-        addressType.getSqlIdentifier(),
-        false)) {
+    if (typeName.equalsDeep(addressType.getSqlIdentifier(), Litmus.IGNORE)) {
       return addressType;
     } else {
       return null;


[2/4] calcite git commit: [CALCITE-551] Sub-query inside aggregate function

Posted by jh...@apache.org.
[CALCITE-551] Sub-query inside aggregate function

The bug seems to have been fixed by recent changes; this commit adds test cases.


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

Branch: refs/heads/master
Commit: 82b586040ffbb4a7e46544b39b2dcc165d642430
Parents: d80e26c
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Jan 13 09:51:31 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jan 26 11:53:33 2016 -0800

----------------------------------------------------------------------
 .../calcite/test/SqlToRelConverterTest.java     | 102 +++++++++++--------
 .../calcite/test/SqlToRelConverterTest.xml      |  89 ++++++++++------
 core/src/test/resources/sql/agg.iq              |  48 +++++++++
 3 files changed, 164 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/82b58604/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 f3cdf68..a527722 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -685,7 +685,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         .convertsTo("${plan}");
   }
 
-  @Test public void testWithInsideScalarSubquery() {
+  @Test public void testWithInsideScalarSubQuery() {
     final String sql = "select (\n"
         + " with dept2 as (select * from dept where deptno > 10)"
         + " select count(*) from dept2) as c\n"
@@ -694,7 +694,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         .convertsTo("${plan}");
   }
 
-  @Test public void testWithInsideScalarSubqueryRex() {
+  @Test public void testWithInsideScalarSubQueryRex() {
     final String sql = "select (\n"
         + " with dept2 as (select * from dept where deptno > 10)"
         + " select count(*) from dept2) as c\n"
@@ -783,7 +783,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         "${plan}");
   }
 
-  @Test public void testUnnestSubquery() {
+  @Test public void testUnnestSubQuery() {
     check("select*from unnest(multiset(select*from dept))", "${plan}");
   }
 
@@ -797,7 +797,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         .convertsTo("${plan}");
   }
 
-  @Test public void testMultisetSubquery() {
+  @Test public void testMultisetSubQuery() {
     check(
         "select multiset(select deptno from dept) from (values(true))",
         "${plan}");
@@ -911,21 +911,21 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   }
 
   @Test public void testInValueListLong() {
-    // Go over the default threshold of 20 to force a subquery.
+    // Go over the default threshold of 20 to force a subQuery.
     check("select empno from emp where deptno in"
             + " (10, 20, 30, 40, 50, 60, 70, 80, 90, 100"
             + ", 110, 120, 130, 140, 150, 160, 170, 180, 190"
             + ", 200, 210, 220, 230)", "${plan}");
   }
 
-  @Test public void testInUncorrelatedSubquery() {
+  @Test public void testInUncorrelatedSubQuery() {
     final String sql = "select empno from emp where deptno in"
         + " (select deptno from dept)";
     sql(sql)
         .convertsTo("${plan}");
   }
 
-  @Test public void testInUncorrelatedSubqueryRex() {
+  @Test public void testInUncorrelatedSubQueryRex() {
     final String sql = "select empno from emp where deptno in"
         + " (select deptno from dept)";
     sql(sql)
@@ -933,7 +933,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         .convertsTo("${plan}");
   }
 
-  @Test public void testCompositeInUncorrelatedSubqueryRex() {
+  @Test public void testCompositeInUncorrelatedSubQueryRex() {
     final String sql = "select empno from emp where (empno, deptno) in"
         + " (select deptno - 10, deptno from dept)";
     sql(sql)
@@ -941,14 +941,14 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         .convertsTo("${plan}");
   }
 
-  @Test public void testNotInUncorrelatedSubquery() {
+  @Test public void testNotInUncorrelatedSubQuery() {
     final String sql = "select empno from emp where deptno not in"
         + " (select deptno from dept)";
     sql(sql)
         .convertsTo("${plan}");
   }
 
-  @Test public void testNotInUncorrelatedSubqueryRex() {
+  @Test public void testNotInUncorrelatedSubQueryRex() {
     final String sql = "select empno from emp where deptno not in"
         + " (select deptno from dept)";
     sql(sql)
@@ -966,7 +966,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         .convertsTo("${plan}");
   }
 
-  @Test public void testInUncorrelatedSubqueryInSelect() {
+  @Test public void testInUncorrelatedSubQueryInSelect() {
     // In the SELECT clause, the value of IN remains in 3-valued logic
     // -- it's not forced into 2-valued by the "... IS TRUE" wrapper as in the
     // WHERE clause -- so the translation is more complicated.
@@ -977,7 +977,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         .convertsTo("${plan}");
   }
 
-  @Test public void testInUncorrelatedSubqueryInSelectRex() {
+  @Test public void testInUncorrelatedSubQueryInSelectRex() {
     // In the SELECT clause, the value of IN remains in 3-valued logic
     // -- it's not forced into 2-valued by the "... IS TRUE" wrapper as in the
     // WHERE clause -- so the translation is more complicated.
@@ -989,7 +989,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         .convertsTo("${plan}");
   }
 
-  @Test public void testInUncorrelatedSubqueryInHavingRex() {
+  @Test public void testInUncorrelatedSubQueryInHavingRex() {
     final String sql = "select sum(sal) as s\n"
         + "from emp\n"
         + "group by deptno\n"
@@ -999,7 +999,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
     sql(sql).expand(false).convertsTo("${plan}");
   }
 
-  @Test public void testUncorrelatedScalarSubqueryInOrderRex() {
+  @Test public void testUncorrelatedScalarSubQueryInOrderRex() {
     final String sql = "select ename\n"
         + "from emp\n"
         + "order by (select case when true then deptno else null end from emp) desc,\n"
@@ -1007,7 +1007,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
     sql(sql).expand(false).convertsTo("${plan}");
   }
 
-  @Test public void testUncorrelatedScalarSubqueryInGroupOrderRex() {
+  @Test public void testUncorrelatedScalarSubQueryInGroupOrderRex() {
     final String sql = "select sum(sal) as s\n"
         + "from emp\n"
         + "group by deptno\n"
@@ -1016,16 +1016,16 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
     sql(sql).expand(false).convertsTo("${plan}");
   }
 
-  @Test public void testUncorrelatedScalarSubqueryInAggregateRex() {
+  @Test public void testUncorrelatedScalarSubQueryInAggregateRex() {
     final String sql = "select sum((select min(deptno) from emp)) as s\n"
         + "from emp\n"
         + "group by deptno\n";
     sql(sql).expand(false).convertsTo("${plan}");
   }
 
-  /** Plan should be as {@link #testInUncorrelatedSubqueryInSelect}, but with
+  /** Plan should be as {@link #testInUncorrelatedSubQueryInSelect}, but with
    * an extra NOT. Both queries require 3-valued logic. */
-  @Test public void testNotInUncorrelatedSubqueryInSelect() {
+  @Test public void testNotInUncorrelatedSubQueryInSelect() {
     final String sql = "select empno, deptno not in (\n"
         + "  select case when true then deptno else null end from dept)\n"
         + "from emp";
@@ -1033,7 +1033,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         .convertsTo("${plan}");
   }
 
-  @Test public void testNotInUncorrelatedSubqueryInSelectRex() {
+  @Test public void testNotInUncorrelatedSubQueryInSelectRex() {
     final String sql = "select empno, deptno not in (\n"
         + "  select case when true then deptno else null end from dept)\n"
         + "from emp";
@@ -1044,7 +1044,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
 
   /** Since 'deptno NOT IN (SELECT deptno FROM dept)' can not be null, we
    * generate a simpler plan. */
-  @Test public void testNotInUncorrelatedSubqueryInSelectNotNull() {
+  @Test public void testNotInUncorrelatedSubQueryInSelectNotNull() {
     final String sql = "select empno, deptno not in (\n"
         + "  select deptno from dept)\n"
         + "from emp";
@@ -1052,7 +1052,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         .convertsTo("${plan}");
   }
 
-  @Test public void testNotInUncorrelatedSubqueryInSelectNotNullRex() {
+  @Test public void testNotInUncorrelatedSubQueryInSelectNotNullRex() {
     final String sql = "select empno, deptno not in (\n"
         + "  select deptno from dept)\n"
         + "from emp";
@@ -1160,8 +1160,8 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
         "${plan}");
   }
 
-  @Test public void testUnionSubquery() {
-    // union of subquery, inside from list, also values
+  @Test public void testUnionSubQuery() {
+    // union of subQuery, inside from list, also values
     check(
         "select deptno from emp as emp0 cross join\n"
             + " (select empno from emp union all\n"
@@ -1368,7 +1368,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   /**
    * Test group-by CASE expression involving a non-query IN
    */
-  @Test public void testGroupByCaseSubquery() {
+  @Test public void testGroupByCaseSubQuery() {
     sql("SELECT CASE WHEN emp.empno IN (3) THEN 0 ELSE 1 END\n"
         + "FROM emp\n"
         + "GROUP BY (CASE WHEN emp.empno IN (3) THEN 0 ELSE 1 END)")
@@ -1378,7 +1378,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   /**
    * Test aggregate function on a CASE expression involving a non-query IN
    */
-  @Test public void testAggCaseSubquery() {
+  @Test public void testAggCaseSubQuery() {
     sql("SELECT SUM(CASE WHEN empno IN (3) THEN 0 ELSE 1 END) FROM emp")
         .convertsTo("${plan}");
   }
@@ -1391,19 +1391,31 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
             + "FROM emp) GROUP BY empno, EXPR$2").convertsTo("${plan}");
   }
 
-  @Test public void testAggScalarSubquery() {
+  @Test public void testAggScalarSubQuery() {
     sql("SELECT SUM(SELECT min(deptno) FROM dept) FROM emp")
         .convertsTo("${plan}");
   }
 
   /** Test aggregate function on a CASE expression involving IN with a
-   * sub-query */
-  @Ignore("[CALCITE-551] Sub-query inside aggregate function")
-  @Test public void testAggCaseInSubquery() {
-    sql("SELECT SUM(\n"
+   * sub-query.
+   *
+   * <p>Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-551">[CALCITE-551]
+   * Sub-query inside aggregate function</a>.
+   */
+  @Test public void testAggCaseInSubQuery() {
+    final String sql = "SELECT SUM(\n"
         + "  CASE WHEN deptno IN (SELECT deptno FROM dept) THEN 1 ELSE 0 END)\n"
-        + "FROM emp")
-        .convertsTo("${plan}");
+        + "FROM emp";
+    sql(sql).expand(false).convertsTo("${plan}");
+  }
+
+  @Test public void testCorrelatedSubQueryInAggregate() {
+    final String sql = "SELECT SUM(\n"
+        + "  (select char_length(name) from dept\n"
+        + "   where dept.deptno = emp.empno))\n"
+        + "FROM emp";
+    sql(sql).expand(false).convertsTo("${plan}");
   }
 
   /**
@@ -1480,7 +1492,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
    * <a href="https://issues.apache.org/jira/browse/CALCITE-695">[CALCITE-695]
    * SqlSingleValueAggFunction is created when it may not be needed</a>.
    */
-  @Test public void testSubqueryAggreFunctionFollowedBySimpleOperation() {
+  @Test public void testSubQueryAggregateFunctionFollowedBySimpleOperation() {
     sql("select deptno\n"
         + "from EMP\n"
         + "where deptno > (select min(deptno) * 2 + 10 from EMP)")
@@ -1492,7 +1504,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
    * <a href="https://issues.apache.org/jira/browse/CALCITE-695">[CALCITE-695]
    * SqlSingleValueAggFunction is created when it may not be needed</a>.
    */
-  @Test public void testSubqueryValues() {
+  @Test public void testSubQueryValues() {
     sql("select deptno\n"
         + "from EMP\n"
         + "where deptno > (values 10)")
@@ -1504,7 +1516,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
    * <a href="https://issues.apache.org/jira/browse/CALCITE-695">[CALCITE-695]
    * SqlSingleValueAggFunction is created when it may not be needed</a>.
    */
-  @Test public void testSubqueryLimitOne() {
+  @Test public void testSubQueryLimitOne() {
     sql("select deptno\n"
         + "from EMP\n"
         + "where deptno > (select deptno\n"
@@ -1518,7 +1530,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
    * When look up subqueries, perform the same logic as the way when ones were
    * registered</a>.
    */
-  @Test public void testIdenticalExpressionInSubquery() {
+  @Test public void testIdenticalExpressionInSubQuery() {
     sql("select deptno\n"
         + "from EMP\n"
         + "where deptno in (1, 2) or deptno in (1, 2)")
@@ -1545,7 +1557,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
    * Scan HAVING clause for sub-queries and IN-lists</a>, with a sub-query in
    * the HAVING clause.
    */
-  @Test public void testHavingInSubqueryWithAggrFunction() {
+  @Test public void testHavingInSubQueryWithAggrFunction() {
     sql("select sal\n"
         + "from emp\n"
         + "group by sal\n"
@@ -1639,10 +1651,10 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   /**
    * Test case for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-770">[CALCITE-770]
-   * variant involving join with subquery that contains window function and
+   * variant involving join with subQuery that contains window function and
    * GROUP BY</a>.
    */
-  @Test public void testWindowAggInSubqueryJoin() {
+  @Test public void testWindowAggInSubQueryJoin() {
     sql("select T.x, T.y, T.z, emp.empno from (select min(deptno) as x,\n"
             + "   rank() over (order by empno) as y,\n"
             + "   max(empno) over (partition by deptno) as z\n"
@@ -1653,9 +1665,9 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   }
 
   /**
-   * Test case (correlated scalar aggregate subquery) for
+   * Test case (correlated scalar aggregate subQuery) for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-714">[CALCITE-714]
-   * When de-correlating, push join condition into subquery</a>.
+   * When de-correlating, push join condition into subQuery</a>.
    */
   @Test public void testCorrelationScalarAggAndFilter() {
     final String sql = "SELECT e1.empno\n"
@@ -1676,9 +1688,9 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   }
 
   /**
-   * Test case (correlated EXISTS subquery) for
+   * Test case (correlated EXISTS subQuery) for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-714">[CALCITE-714]
-   * When de-correlating, push join condition into subquery</a>.
+   * When de-correlating, push join condition into subQuery</a>.
    */
   @Test public void testCorrelationExistsAndFilter() {
     final String sql = "SELECT e1.empno\n"
@@ -1699,9 +1711,9 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
   }
 
   /**
-   * Test case (correlated NOT EXISTS subquery) for
+   * Test case (correlated NOT EXISTS subQuery) for
    * <a href="https://issues.apache.org/jira/browse/CALCITE-714">[CALCITE-714]
-   * When de-correlating, push join condition into subquery</a>.
+   * When de-correlating, push join condition into subQuery</a>.
    */
   @Test public void testCorrelationNotExistsAndFilter() {
     tester.withDecorrelation(true).assertConvertsTo(

http://git-wip-us.apache.org/repos/asf/calcite/blob/82b58604/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 84e1afe..0f9c715 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -117,6 +117,25 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)], EXPR$2=[SUM(DISTINCT $1)], EXPR$
             <![CDATA[select deptno, sum(sal), sum(distinct sal), count(*) from emp group by deptno]]>
         </Resource>
     </TestCase>
+    <TestCase name="testCorrelatedSubQueryInAggregate">
+        <Resource name="sql">
+            <![CDATA[SELECT SUM(
+  (select char_length(name) from dept
+   where dept.deptno = emp.empno))
+FROM emp]]>
+        </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalAggregate(group=[{}], EXPR$0=[SUM($0)])
+  LogicalProject($f0=[$SCALAR_QUERY({
+LogicalProject(EXPR$0=[CHAR_LENGTH($1)])
+  LogicalFilter(condition=[=($0, $cor0.EMPNO)])
+    LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+})])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testCorrelatedSubQueryInJoin">
         <Resource name="sql">
             <![CDATA[select *
@@ -156,7 +175,7 @@ LogicalProject(EXPR$0=[$0])
             <![CDATA[select*from unnest(multiset[1,2])]]>
         </Resource>
     </TestCase>
-    <TestCase name="testUnnestSubquery">
+    <TestCase name="testUnnestSubQuery">
         <Resource name="plan">
             <![CDATA[
 LogicalProject(DEPTNO=[$0], NAME=[$1])
@@ -198,7 +217,7 @@ LogicalProject(DEPTNO=[$0], NAME=[$1], ORDINALITY=[$2])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testMultisetSubquery">
+    <TestCase name="testMultisetSubQuery">
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EXPR$0=[$1])
@@ -408,7 +427,7 @@ select 34 from emp
 union all values (30), (45 + 10)]]>
         </Resource>
     </TestCase>
-    <TestCase name="testUnionSubquery">
+    <TestCase name="testUnionSubQuery">
         <Resource name="plan">
             <![CDATA[
 LogicalProject(DEPTNO=[$7])
@@ -631,7 +650,7 @@ LogicalProject(EMPNO=[$0])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testInUncorrelatedSubquery">
+    <TestCase name="testInUncorrelatedSubQuery">
         <Resource name="sql">
             <![CDATA[select empno from emp where deptno in (select deptno from dept)]]>
         </Resource>
@@ -1372,7 +1391,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testWithInsideScalarSubquery">
+    <TestCase name="testWithInsideScalarSubQuery">
         <Resource name="sql">
             <![CDATA[select (
  with dept2 as (select * from dept where deptno > 10) select count(*) from dept2) as c
@@ -1704,7 +1723,7 @@ LogicalProject(EMPNO=[$0], X=[$1])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testInUncorrelatedSubqueryInSelect">
+    <TestCase name="testInUncorrelatedSubQueryInSelect">
         <Resource name="sql">
             <![CDATA[select name, deptno in (
   select case when true then deptno else null end from emp)
@@ -1728,7 +1747,7 @@ LogicalProject(NAME=[$1], EXPR$1=[CASE(=($2, 0), false, IS NOT NULL($6), true, I
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testNotInUncorrelatedSubqueryInSelect">
+    <TestCase name="testNotInUncorrelatedSubQueryInSelect">
         <Resource name="sql">
             <![CDATA[select empno, deptno not in (
   select case when true then deptno else null end from dept)
@@ -1752,7 +1771,7 @@ LogicalProject(EMPNO=[$0], EXPR$1=[NOT(CASE(=($9, 0), false, IS NOT NULL($13), t
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testNotInUncorrelatedSubquery">
+    <TestCase name="testNotInUncorrelatedSubQuery">
         <Resource name="sql">
             <![CDATA[select empno from emp where deptno not in (select deptno from dept)]]>
         </Resource>
@@ -1775,7 +1794,7 @@ LogicalProject(EMPNO=[$0])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testNotInUncorrelatedSubqueryInSelectNotNull">
+    <TestCase name="testNotInUncorrelatedSubQueryInSelectNotNull">
         <Resource name="sql">
             <![CDATA[select empno, deptno not in (
   select deptno from dept)
@@ -2069,7 +2088,7 @@ LogicalProject(DEPTNO=[$0], NAME=[$1], X=[$2])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testGroupByCaseSubquery">
+    <TestCase name="testGroupByCaseSubQuery">
         <Resource name="sql">
             <![CDATA[SELECT CASE WHEN emp.empno IN (3) THEN 0 ELSE 1 END
 FROM emp
@@ -2096,7 +2115,7 @@ LogicalAggregate(group=[{0, 1}], EXPR$2=[COUNT()])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testAggCaseSubquery">
+    <TestCase name="testAggCaseSubQuery">
         <Resource name="sql">
             <![CDATA[SELECT SUM(CASE WHEN empno IN (3) THEN 0 ELSE 1 END) FROM emp]]>
         </Resource>
@@ -2108,14 +2127,24 @@ LogicalAggregate(group=[{}], EXPR$0=[SUM($0)])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testAggCaseInSubquery">
+    <TestCase name="testAggCaseInSubQuery">
         <Resource name="sql">
             <![CDATA[SELECT SUM(
   CASE WHEN deptno IN (SELECT deptno FROM dept) THEN 1 ELSE 0 END)
 FROM emp]]>
         </Resource>
+        <Resource name="plan">
+            <![CDATA[
+LogicalAggregate(group=[{}], EXPR$0=[SUM($0)])
+  LogicalProject($f0=[CASE(IN($7, {
+LogicalProject(DEPTNO=[$0])
+  LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+}), 1, 0)])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
     </TestCase>
-    <TestCase name="testAggScalarSubquery">
+    <TestCase name="testAggScalarSubQuery">
         <Resource name="sql">
             <![CDATA[SELECT SUM(SELECT min(deptno) FROM dept) FROM emp]]>
         </Resource>
@@ -2201,7 +2230,7 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($1) FILTER $2], EXPR$2=[COUNT()])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testSubqueryAggreFunctionFollowedBySimpleOperation">
+    <TestCase name="testSubQueryAggregateFunctionFollowedBySimpleOperation">
         <Resource name="sql">
             <![CDATA[select deptno
 from EMP
@@ -2220,7 +2249,7 @@ LogicalProject(DEPTNO=[$7])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testSubqueryValues">
+    <TestCase name="testSubQueryValues">
         <Resource name="sql">
             <![CDATA[select deptno
 from EMP
@@ -2236,7 +2265,7 @@ LogicalProject(DEPTNO=[$7])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testSubqueryLimitOne">
+    <TestCase name="testSubQueryLimitOne">
         <Resource name="sql">
             <![CDATA[select deptno
 from EMP
@@ -2255,7 +2284,7 @@ LogicalProject(DEPTNO=[$7])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testIdenticalExpressionInSubquery">
+    <TestCase name="testIdenticalExpressionInSubQuery">
         <Resource name="sql">
             <![CDATA[select deptno
 from EMP
@@ -2287,7 +2316,7 @@ LogicalProject(DEPTNO=[$0])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testHavingInSubqueryWithAggrFunction">
+    <TestCase name="testHavingInSubQueryWithAggrFunction">
         <Resource name="sql">
             <![CDATA[select sal
 from emp
@@ -2467,7 +2496,7 @@ LogicalProject(EXPR$0=[$2], EXPR$1=[RANK() OVER (ORDER BY $1 RANGE BETWEEN UNBOU
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testWindowAggInSubqueryJoin">
+    <TestCase name="testWindowAggInSubQueryJoin">
         <Resource name="sql">
             <![CDATA[select T.x, T.y, T.z, emp.empno from (select min(deptno) as x,
    rank() over (order by empno) as y,
@@ -2703,7 +2732,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testWithInsideScalarSubqueryRex">
+    <TestCase name="testWithInsideScalarSubQueryRex">
         <Resource name="sql">
             <![CDATA[select (
  with dept2 as (select * from dept where deptno > 10) select count(*) from dept2) as c
@@ -2742,7 +2771,7 @@ LogicalFilter(condition=[<=($0, $cor1.DEPTNO)])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testInUncorrelatedSubqueryInSelectRex">
+    <TestCase name="testInUncorrelatedSubQueryInSelectRex">
         <Resource name="sql">
             <![CDATA[select name, deptno in (
   select case when true then deptno else null end from emp)
@@ -2758,7 +2787,7 @@ LogicalProject(EXPR$0=[CASE(true, CAST($7):INTEGER, null)])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testNotInUncorrelatedSubqueryInSelectNotNullRex">
+    <TestCase name="testNotInUncorrelatedSubQueryInSelectNotNullRex">
         <Resource name="sql">
             <![CDATA[select empno, deptno not in (
   select deptno from dept)
@@ -2774,7 +2803,7 @@ LogicalProject(DEPTNO=[$0])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testNotInUncorrelatedSubqueryRex">
+    <TestCase name="testNotInUncorrelatedSubQueryRex">
         <Resource name="sql">
             <![CDATA[select empno from emp where deptno not in (select deptno from dept)]]>
         </Resource>
@@ -2789,7 +2818,7 @@ LogicalProject(DEPTNO=[$0])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testNotInUncorrelatedSubqueryInSelectRex">
+    <TestCase name="testNotInUncorrelatedSubQueryInSelectRex">
         <Resource name="sql">
             <![CDATA[select empno, deptno not in (
   select case when true then deptno else null end from dept)
@@ -2805,7 +2834,7 @@ LogicalProject(EXPR$0=[CASE(true, CAST($0):INTEGER, null)])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testInUncorrelatedSubqueryRex">
+    <TestCase name="testInUncorrelatedSubQueryRex">
         <Resource name="sql">
             <![CDATA[select empno from emp where deptno in (select deptno from dept)]]>
         </Resource>
@@ -2840,7 +2869,7 @@ LogicalFilter(condition=[<=($0, $cor1.DEPTNO)])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testCompositeInUncorrelatedSubqueryRex">
+    <TestCase name="testCompositeInUncorrelatedSubQueryRex">
         <Resource name="sql">
             <![CDATA[select empno from emp where (empno, deptno) in (select deptno - 10, deptno from dept)]]>
         </Resource>
@@ -2892,7 +2921,7 @@ LogicalFilter(condition=[>($0, +($cor0.DEPTNO0, 5))])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testInUncorrelatedSubqueryInHavingRex">
+    <TestCase name="testInUncorrelatedSubQueryInHavingRex">
         <Resource name="sql">
             <![CDATA[select sum(sal) as s
 from emp
@@ -2914,7 +2943,7 @@ LogicalProject(EXPR$0=[CASE(true, CAST($7):INTEGER, null)])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testUncorrelatedScalarSubqueryInGroupOrderRex">
+    <TestCase name="testUncorrelatedScalarSubQueryInGroupOrderRex">
         <Resource name="sql">
             <![CDATA[select sum(sal) as s
 from emp
@@ -2936,7 +2965,7 @@ LogicalProject(EXPR$0=[CASE(true, CAST($7):INTEGER, null)])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testUncorrelatedScalarSubqueryInOrderRex">
+    <TestCase name="testUncorrelatedScalarSubQueryInOrderRex">
         <Resource name="sql">
             <![CDATA[select ename
 from emp
@@ -2955,7 +2984,7 @@ LogicalProject(EXPR$0=[CASE(true, CAST($7):INTEGER, null)])
 ]]>
         </Resource>
     </TestCase>
-    <TestCase name="testUncorrelatedScalarSubqueryInAggregateRex">
+    <TestCase name="testUncorrelatedScalarSubQueryInAggregateRex">
         <Resource name="sql">
             <![CDATA[select sum((select min(deptno) from emp)) as s
 from emp

http://git-wip-us.apache.org/repos/asf/calcite/blob/82b58604/core/src/test/resources/sql/agg.iq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/agg.iq b/core/src/test/resources/sql/agg.iq
index 52a15cc..39bd683 100644
--- a/core/src/test/resources/sql/agg.iq
+++ b/core/src/test/resources/sql/agg.iq
@@ -591,6 +591,54 @@ from (values cast(-86.4 as float), cast(-100 as float)) as t(v);
 
 !ok
 
+# [CALCITE-551] Sub-query inside aggregate function
+SELECT SUM(
+  CASE WHEN deptno IN (SELECT deptno FROM "scott".dept) THEN 1
+  ELSE 0 END) as s
+FROM "scott".emp;
++----+
+| S  |
++----+
+| 14 |
++----+
+(1 row)
+
+!ok
+
+SELECT SUM((select min(cast(deptno as integer)) from "scott".dept)) as s
+FROM "scott".emp;
++-----+
+| S   |
++-----+
+| 140 |
++-----+
+(1 row)
+
+!ok
+
+# As above, but with GROUP BY
+SELECT SUM((select min(cast(deptno as integer)) from "scott".dept)) as s, deptno
+FROM "scott".emp
+GROUP BY deptno;
++----+--------+
+| S  | DEPTNO |
++----+--------+
+| 30 |     10 |
+| 50 |     20 |
+| 60 |     30 |
++----+--------+
+(3 rows)
+
+!ok
+
+# As above, but with correlation
+!if (fixed.calcite1045) {
+SELECT SUM(
+  (select char_length(dname) from "scott".dept where dept.deptno = emp.empno)) as s
+FROM "scott".emp;
+!ok
+!}
+
 # COLLECT
 select deptno, collect(empno) as empnos
 from "scott".emp