You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by li...@apache.org on 2016/07/23 00:18:40 UTC

[1/2] kylin git commit: KYLIN-1898: Upgrade Calcite to 1.8

Repository: kylin
Updated Branches:
  refs/heads/master 408d06896 -> 67017e3ed


KYLIN-1898: Upgrade Calcite to 1.8

Signed-off-by: Yang Li <li...@apache.org>


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

Branch: refs/heads/master
Commit: 1adc2fdcf6d475c344ff44a35c553053e9782ab3
Parents: 408d068
Author: Yiming Liu <li...@gmail.com>
Authored: Sun Jul 17 00:51:28 2016 +0800
Committer: Yang Li <li...@apache.org>
Committed: Sat Jul 23 06:48:05 2016 +0800

----------------------------------------------------------------------
 atopcalcite/pom.xml                             | 10 ------
 .../calcite/sql2rel/SqlToRelConverter.java      | 13 +++-----
 jdbc/pom.xml                                    |  8 +----
 .../java/org/apache/kylin/jdbc/KylinMeta.java   | 35 ++++++++++++++++++++
 pom.xml                                         | 21 +++++++++---
 query/pom.xml                                   |  2 +-
 6 files changed, 58 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/1adc2fdc/atopcalcite/pom.xml
----------------------------------------------------------------------
diff --git a/atopcalcite/pom.xml b/atopcalcite/pom.xml
index b208ea1..7f4e508 100644
--- a/atopcalcite/pom.xml
+++ b/atopcalcite/pom.xml
@@ -39,16 +39,6 @@
             <groupId>org.apache.calcite</groupId>
             <artifactId>calcite-core</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.apache.calcite</groupId>
-            <artifactId>calcite-avatica</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>com.google.protobuf</groupId>
-                    <artifactId>protobuf-java</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
     </dependencies>
 
 </project>

http://git-wip-us.apache.org/repos/asf/kylin/blob/1adc2fdc/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 849d5d7..c01663a 100644
--- a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -35,8 +35,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 
 import org.apache.calcite.avatica.util.Spaces;
 import org.apache.calcite.linq4j.Ord;
@@ -187,6 +185,7 @@ import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import org.slf4j.Logger;
 
 /*
  * OVERRIDE POINT:
@@ -500,9 +499,8 @@ public class SqlToRelConverter {
                 final RelTraitSet traitSet = rootRel.getTraitSet().replace(RelCollationTraitDef.INSTANCE, collations);
                 rootRel = rootRel.copy(traitSet, rootRel.getInputs());
             }
-            boolean dumpPlan = SQL2REL_LOGGER.isLoggable(Level.FINE);
-            if (dumpPlan) {
-                SQL2REL_LOGGER.fine(RelOptUtil.dumpPlan("Plan after trimming unused fields", rootRel, false, SqlExplainLevel.EXPPLAN_ATTRIBUTES));
+            if (SQL2REL_LOGGER.isDebugEnabled()) {
+                SQL2REL_LOGGER.debug(RelOptUtil.dumpPlan("Plan after trimming unused fields", rootRel, false, SqlExplainLevel.EXPPLAN_ATTRIBUTES));
             }
         }
         return rootRel;
@@ -548,9 +546,8 @@ public class SqlToRelConverter {
         }
         checkConvertedType(query, result);
 
-        boolean dumpPlan = SQL2REL_LOGGER.isLoggable(Level.FINE);
-        if (dumpPlan) {
-            SQL2REL_LOGGER.fine(RelOptUtil.dumpPlan("Plan after converting SqlNode to RelNode", result, false, SqlExplainLevel.EXPPLAN_ATTRIBUTES));
+        if (SQL2REL_LOGGER.isDebugEnabled()) {
+            SQL2REL_LOGGER.debug(RelOptUtil.dumpPlan("Plan after converting SqlNode to RelNode", result, false, SqlExplainLevel.EXPPLAN_ATTRIBUTES));
         }
 
         final RelDataType validatedRowType = validator.getValidatedNodeType(query);

http://git-wip-us.apache.org/repos/asf/kylin/blob/1adc2fdc/jdbc/pom.xml
----------------------------------------------------------------------
diff --git a/jdbc/pom.xml b/jdbc/pom.xml
index 890a4c0..7797145 100644
--- a/jdbc/pom.xml
+++ b/jdbc/pom.xml
@@ -40,13 +40,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.calcite</groupId>
-            <artifactId>calcite-avatica</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>com.google.protobuf</groupId>
-                    <artifactId>protobuf-java</artifactId>
-                </exclusion>
-            </exclusions>
+            <artifactId>calcite-core</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>

http://git-wip-us.apache.org/repos/asf/kylin/blob/1adc2fdc/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java
index 8059dd0..002e5bd 100644
--- a/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java
+++ b/jdbc/src/main/java/org/apache/kylin/jdbc/KylinMeta.java
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
 
 import org.apache.calcite.avatica.AvaticaUtils;
 import org.apache.calcite.avatica.ColumnMetaData;
+import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.MetaImpl;
 import org.apache.calcite.avatica.MissingResultsException;
 import org.apache.calcite.avatica.NoSuchStatementException;
@@ -58,15 +59,33 @@ public class KylinMeta extends MetaImpl {
         return result;
     }
 
+    @Override
+    public ExecuteBatchResult prepareAndExecuteBatch(StatementHandle sh, List<String> sqlCommands) throws NoSuchStatementException {
+        return new ExecuteBatchResult(new long[]{});
+    }
+
+    @Override
+    public ExecuteBatchResult executeBatch(StatementHandle sh, List<List<TypedValue>> parameterValues) throws NoSuchStatementException {
+        return new ExecuteBatchResult(new long[]{});
+    }
+
     // real execution happens in KylinResultSet.execute()
     @Override
+    @Deprecated
     public ExecuteResult execute(StatementHandle sh, List<TypedValue> parameterValues, long maxRowCount) throws NoSuchStatementException {
         final MetaResultSet metaResultSet = MetaResultSet.create(sh.connectionId, sh.id, false, sh.signature, null);
         return new ExecuteResult(Collections.singletonList(metaResultSet));
     }
 
+    @Override
+    public ExecuteResult execute(StatementHandle sh, List<TypedValue> parameterValues, int maxRowsInFirstFrame) throws NoSuchStatementException {
+        final MetaResultSet metaResultSet = MetaResultSet.create(sh.connectionId, sh.id, false, sh.signature, null);
+        return new ExecuteResult(Collections.singletonList(metaResultSet));
+    }
+
     // mimic from CalciteMetaImpl, real execution happens via callback in KylinResultSet.execute()
     @Override
+    @Deprecated
     public ExecuteResult prepareAndExecute(StatementHandle sh, String sql, long maxRowCount, PrepareCallback callback) {
         try {
             synchronized (callback.getMonitor()) {
@@ -83,6 +102,22 @@ public class KylinMeta extends MetaImpl {
     }
 
     @Override
+    public ExecuteResult prepareAndExecute(StatementHandle sh, String sql, long maxRowCount, int maxRowsInFirstFrame, PrepareCallback callback) throws NoSuchStatementException {
+        try {
+            synchronized (callback.getMonitor()) {
+                callback.clear();
+                sh.signature = connection().mockPreparedSignature(sql);
+                callback.assign(sh.signature, null, -1);
+            }
+            callback.execute();
+            final MetaResultSet metaResultSet = MetaResultSet.create(sh.connectionId, sh.id, false, sh.signature, null);
+            return new ExecuteResult(Collections.singletonList(metaResultSet));
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
     public void closeStatement(StatementHandle h) {
         // nothing to do
     }

http://git-wip-us.apache.org/repos/asf/kylin/blob/1adc2fdc/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 1d09a90..a1d140d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -100,7 +100,7 @@
         <spring.boot.version>1.2.7.RELEASE</spring.boot.version>
 
         <!-- Calcite Version -->
-        <calcite.version>1.6.0</calcite.version>
+        <calcite.version>1.8.0</calcite.version>
 
         <!-- Curator.version Version -->
         <curator.version>2.6.0</curator.version>
@@ -279,15 +279,26 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.calcite</groupId>
-                <artifactId>calcite-avatica</artifactId>
+                <artifactId>calcite-linq4j</artifactId>
                 <version>${calcite.version}</version>
             </dependency>
             <dependency>
-                <groupId>org.apache.calcite</groupId>
-                <artifactId>calcite-linq4j</artifactId>
+                <groupId>org.apache.calcite.avatica</groupId>
+                <artifactId>avatica</artifactId>
                 <version>${calcite.version}</version>
             </dependency>
-
+            <!-- Workaround for hive 0.14 avatica dependency -->
+            <dependency>
+                <groupId>org.apache.calcite</groupId>
+                <artifactId>calcite-avatica</artifactId>
+                <version>1.6.0</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>com.google.protobuf</groupId>
+                        <artifactId>protobuf-java</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
             <!-- Spark dependency -->
             <dependency>
                 <groupId>org.apache.spark</groupId>

http://git-wip-us.apache.org/repos/asf/kylin/blob/1adc2fdc/query/pom.xml
----------------------------------------------------------------------
diff --git a/query/pom.xml b/query/pom.xml
index 0dff0c3..f4c7e50 100644
--- a/query/pom.xml
+++ b/query/pom.xml
@@ -50,7 +50,7 @@
         </dependency>
         <dependency>
             <groupId>org.apache.calcite</groupId>
-            <artifactId>calcite-linq4j</artifactId>
+            <artifactId>calcite-core</artifactId>
         </dependency>
         <dependency>
             <groupId>log4j</groupId>


[2/2] kylin git commit: KYLIN-1898 update SqlToRelConverter

Posted by li...@apache.org.
KYLIN-1898 update SqlToRelConverter


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

Branch: refs/heads/master
Commit: 67017e3eda9854d9640e7290a0ff039469f149c7
Parents: 1adc2fd
Author: Yang Li <li...@apache.org>
Authored: Sat Jul 23 08:18:34 2016 +0800
Committer: Yang Li <li...@apache.org>
Committed: Sat Jul 23 08:18:34 2016 +0800

----------------------------------------------------------------------
 .../calcite/sql2rel/SqlToRelConverter.java      | 191 ++++++++++++-------
 1 file changed, 126 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/67017e3e/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index c01663a..d223cdf 100644
--- a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -1,13 +1,12 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,27 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.calcite.sql2rel;
 
-import static org.apache.calcite.sql.SqlUtil.stripAs;
-import static org.apache.calcite.util.Static.RESOURCE;
-
-import java.lang.reflect.Type;
-import java.math.BigDecimal;
-import java.util.AbstractList;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
 import org.apache.calcite.avatica.util.Spaces;
 import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.plan.Convention;
@@ -80,7 +60,9 @@ import org.apache.calcite.rel.logical.LogicalTableModify;
 import org.apache.calcite.rel.logical.LogicalTableScan;
 import org.apache.calcite.rel.logical.LogicalUnion;
 import org.apache.calcite.rel.logical.LogicalValues;
+import org.apache.calcite.rel.metadata.JaninoRelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelColumnMapping;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.stream.Delta;
 import org.apache.calcite.rel.stream.LogicalDelta;
 import org.apache.calcite.rel.type.RelDataType;
@@ -180,13 +162,33 @@ 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;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+
 import org.slf4j.Logger;
 
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.util.AbstractList;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import static org.apache.calcite.sql.SqlUtil.stripAs;
+import static org.apache.calcite.util.Static.RESOURCE;
+
 /*
  * OVERRIDE POINT:
  * - getInSubqueryThreshold(), was `20`, now `Integer.MAX_VALUE`
@@ -202,7 +204,6 @@ import org.slf4j.Logger;
  * <p>The public entry points are: {@link #convertQuery},
  * {@link #convertExpression(SqlNode)}.
  */
-@SuppressWarnings("incomplete-switch")
 public class SqlToRelConverter {
     //~ Static fields/initializers ---------------------------------------------
 
@@ -532,6 +533,7 @@ public class SqlToRelConverter {
             query = validator.validate(query);
         }
 
+        RelMetadataQuery.THREAD_PROVIDERS.set(JaninoRelMetadataProvider.of(cluster.getMetadataProvider()));
         RelNode result = convertQueryRecursive(query, top, null).rel;
         if (top) {
             if (isStream(query)) {
@@ -1530,8 +1532,9 @@ public class SqlToRelConverter {
         SqlCall aggCall = call.operand(0);
         SqlNode windowOrRef = call.operand(1);
         final SqlWindow window = validator.resolveWindow(windowOrRef, bb.scope, true);
+
         // ROW_NUMBER() expects specific kind of framing.
-        if (aggCall.getOperator() == SqlStdOperatorTable.ROW_NUMBER) {
+        if (aggCall.getKind() == SqlKind.ROW_NUMBER) {
             window.setLowerBound(SqlWindow.createUnboundedPreceding(SqlParserPos.ZERO));
             window.setUpperBound(SqlWindow.createCurrentRow(SqlParserPos.ZERO));
             window.setRows(SqlLiteral.createBoolean(true, SqlParserPos.ZERO));
@@ -1594,6 +1597,11 @@ public class SqlToRelConverter {
      *             </ul>
      */
     protected void convertFrom(Blackboard bb, SqlNode from) {
+        if (from == null) {
+            bb.setRoot(LogicalValues.createOneRow(cluster), false);
+            return;
+        }
+
         final SqlCall call;
         final SqlNode[] operands;
         switch (from.getKind()) {
@@ -1695,12 +1703,20 @@ public class SqlToRelConverter {
 
         case UNNEST:
             call = (SqlCall) from;
-            final SqlNode node = call.operand(0);
+            final List<SqlNode> nodes = call.getOperandList();
             final SqlUnnestOperator operator = (SqlUnnestOperator) call.getOperator();
-            replaceSubqueries(bb, node, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
-            final RelNode childRel = RelOptUtil.createProject((null != bb.root) ? bb.root : LogicalValues.createOneRow(cluster), Collections.singletonList(bb.convertExpression(node)), Collections.singletonList(validator.deriveAlias(node, 0)), true);
+            for (SqlNode node : nodes) {
+                replaceSubqueries(bb, node, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
+            }
+            final List<RexNode> exprs = new ArrayList<>();
+            final List<String> fieldNames = new ArrayList<>();
+            for (Ord<SqlNode> node : Ord.zip(nodes)) {
+                exprs.add(bb.convertExpression(node.e));
+                fieldNames.add(validator.deriveAlias(node.e, node.i));
+            }
+            final RelNode input = RelOptUtil.createProject((null != bb.root) ? bb.root : LogicalValues.createOneRow(cluster), exprs, fieldNames, true);
 
-            Uncollect uncollect = new Uncollect(cluster, cluster.traitSetOf(Convention.NONE), childRel, operator.withOrdinality);
+            Uncollect uncollect = new Uncollect(cluster, cluster.traitSetOf(Convention.NONE), input, operator.withOrdinality);
             bb.setRoot(uncollect, true);
             return;
 
@@ -1721,7 +1737,7 @@ public class SqlToRelConverter {
     protected void convertCollectionTable(Blackboard bb, SqlCall call) {
         final SqlOperator operator = call.getOperator();
         if (operator == SqlStdOperatorTable.TABLESAMPLE) {
-            final String sampleName = SqlLiteral.stringValue(call.operand(0));
+            final String sampleName = (String) SqlLiteral.value(call.operand(0));
             datasetStack.push(sampleName);
             SqlCall cursorCall = call.operand(1);
             SqlNode query = cursorCall.operand(0);
@@ -1849,7 +1865,7 @@ 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() == lookup.getFieldAccess(correlName).getField().getType();
@@ -2075,11 +2091,15 @@ public class SqlToRelConverter {
             // agg converter knows which aggregations are required
 
             selectList.accept(aggConverter);
+            // Assert we don't have dangling items left in the stack
+            assert !aggConverter.inOver;
             for (SqlNode expr : orderExprList) {
                 expr.accept(aggConverter);
+                assert !aggConverter.inOver;
             }
             if (having != null) {
                 having.accept(aggConverter);
+                assert !aggConverter.inOver;
             }
 
             // compute inputs to the aggregator
@@ -2284,14 +2304,14 @@ public class SqlToRelConverter {
         int ordinal = -1;
         for (SqlNode selectItem : selectScope.getExpandedSelectList()) {
             ++ordinal;
-            if (converted.equalsDeep(stripAs(selectItem), false)) {
+            if (converted.equalsDeep(stripAs(selectItem), Litmus.IGNORE)) {
                 return new RelFieldCollation(ordinal, direction, nullDirection);
             }
         }
 
         for (SqlNode extraExpr : extraExprs) {
             ++ordinal;
-            if (converted.equalsDeep(extraExpr, false)) {
+            if (converted.equalsDeep(extraExpr, Litmus.IGNORE)) {
                 return new RelFieldCollation(ordinal, direction, nullDirection);
             }
         }
@@ -2719,20 +2739,25 @@ 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, (RexFieldAccess) e);
+            final RexNode prev = bb.mapCorrelateToRex.put(((RexCorrelVariable) e0.left).id, (RexFieldAccess) e);
             assert prev == null;
         }
         return e;
@@ -2903,7 +2928,6 @@ public class SqlToRelConverter {
 
         fieldNames = SqlValidatorUtil.uniquify(fieldNames);
 
-        RelNode inputRel = bb.root;
         bb.setRoot(RelOptUtil.createProject(bb.root, exprs, fieldNames), false);
 
         assert bb.columnMonotonicities.isEmpty();
@@ -3210,13 +3234,13 @@ 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 };
@@ -3233,18 +3257,41 @@ public class SqlToRelConverter {
             if ((inputs != null) && !isParent) {
                 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,
                 // e.g. "select from emp as emp join emp.getDepts() as dept".
                 // Create a temporary expression.
-                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());
+                }
             }
         }
 
@@ -3290,7 +3337,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;
                 }
             }
@@ -3299,7 +3346,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;
                 }
             }
@@ -3672,6 +3719,9 @@ public class SqlToRelConverter {
         private final Map<SqlNode, RexNode> aggMapping = Maps.newHashMap();
         private final Map<AggregateCall, RexNode> aggCallMapping = Maps.newHashMap();
 
+        /** Are we directly inside a windowed aggregate? */
+        private boolean inOver = false;
+
         /**
          * Creates an AggConverter.
          *
@@ -3736,12 +3786,10 @@ public class SqlToRelConverter {
             convertedInputExprNames.add(name);
         }
 
-        // implement SqlVisitor
         public Void visit(SqlIdentifier id) {
             return null;
         }
 
-        // implement SqlVisitor
         public Void visit(SqlNodeList nodeList) {
             for (int i = 0; i < nodeList.size(); i++) {
                 nodeList.get(i).accept(this);
@@ -3749,22 +3797,18 @@ public class SqlToRelConverter {
             return null;
         }
 
-        // implement SqlVisitor
         public Void visit(SqlLiteral lit) {
             return null;
         }
 
-        // implement SqlVisitor
         public Void visit(SqlDataTypeSpec type) {
             return null;
         }
 
-        // implement SqlVisitor
         public Void visit(SqlDynamicParam param) {
             return null;
         }
 
-        // implement SqlVisitor
         public Void visit(SqlIntervalQualifier intervalQualifier) {
             return null;
         }
@@ -3779,13 +3823,28 @@ public class SqlToRelConverter {
                 // for now do not detect aggregates in subqueries.
                 return null;
             }
-            // ignore window aggregates and ranking functions (associated with OVER operator)
+            final boolean prevInOver = inOver;
+            // Ignore window aggregates and ranking functions (associated with OVER
+            // operator). However, do not ignore nested window aggregates.
             if (call.getOperator().getKind() == SqlKind.OVER) {
-                return null;
+                if (call.operand(0).getKind() == SqlKind.RANK) {
+                    return null;
+                }
+                // Track aggregate nesting levels only within an OVER operator.
+                inOver = true;
             }
+
+            // Do not translate the top level window aggregate. Only do so for
+            // nested aggregates, if present
             if (call.getOperator().isAggregator()) {
-                translateAgg(call, null, call);
-                return null;
+                if (inOver) {
+                    // Add the parent aggregate level before visiting its children
+                    inOver = false;
+                } else {
+                    // We're beyond the one ignored level
+                    translateAgg(call, null, call);
+                    return null;
+                }
             }
             for (SqlNode operand : call.getOperandList()) {
                 // Operands are occasionally null, e.g. switched CASE arg 0.
@@ -3793,6 +3852,8 @@ public class SqlToRelConverter {
                     operand.accept(this);
                 }
             }
+            // Remove the parent aggregate level after visiting its children
+            inOver = prevInOver;
             return null;
         }
 
@@ -3883,7 +3944,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;
                 }
             }