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 2017/03/31 12:23:22 UTC

[07/12] kylin git commit: KYLIN-2521 upgrade calcite to 1.12

http://git-wip-us.apache.org/repos/asf/kylin/blob/19d5b3de/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 2c308f5..c199c31 100644
--- a/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/atopcalcite/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -1,12 +1,13 @@
 /*
- * 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,
@@ -16,25 +17,6 @@
  */
 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.LinkedHashSet;
-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;
@@ -106,6 +88,7 @@ import org.apache.calcite.schema.ModifiableTable;
 import org.apache.calcite.schema.ModifiableView;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.TranslatableTable;
+import org.apache.calcite.schema.Wrapper;
 import org.apache.calcite.sql.JoinConditionType;
 import org.apache.calcite.sql.JoinType;
 import org.apache.calcite.sql.SemiJoinType;
@@ -125,6 +108,7 @@ import org.apache.calcite.sql.SqlIntervalQualifier;
 import org.apache.calcite.sql.SqlJoin;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlMatchRecognize;
 import org.apache.calcite.sql.SqlMerge;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlNodeList;
@@ -161,6 +145,7 @@ import org.apache.calcite.sql.validate.ListScope;
 import org.apache.calcite.sql.validate.ParameterScope;
 import org.apache.calcite.sql.validate.SelectScope;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
+import org.apache.calcite.sql.validate.SqlNameMatcher;
 import org.apache.calcite.sql.validate.SqlQualified;
 import org.apache.calcite.sql.validate.SqlUserDefinedTableFunction;
 import org.apache.calcite.sql.validate.SqlUserDefinedTableMacro;
@@ -168,6 +153,7 @@ import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorImpl;
 import org.apache.calcite.sql.validate.SqlValidatorNamespace;
 import org.apache.calcite.sql.validate.SqlValidatorScope;
+import org.apache.calcite.sql.validate.SqlValidatorTable;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
@@ -178,7 +164,6 @@ import org.apache.calcite.util.NumberUtil;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.trace.CalciteTrace;
-import org.slf4j.Logger;
 
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
@@ -190,6 +175,28 @@ import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
+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.HashSet;
+import java.util.LinkedHashSet;
+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;
+
 /*
  * The code has synced with calcite. Hope one day, we could remove the hardcode override point.
  * OVERRIDE POINT:
@@ -211,7 +218,7 @@ public class SqlToRelConverter {
     //~ Static fields/initializers ---------------------------------------------
 
     protected static final Logger SQL2REL_LOGGER =
-            CalciteTrace.getSqlToRelTracer();
+        CalciteTrace.getSqlToRelTracer();
 
     private static final BigDecimal TWO = BigDecimal.valueOf(2L);
 
@@ -222,7 +229,7 @@ public class SqlToRelConverter {
 
     @Deprecated // to be removed before 2.0
     public static final int DEFAULT_IN_SUBQUERY_THRESHOLD =
-            DEFAULT_IN_SUB_QUERY_THRESHOLD;
+        DEFAULT_IN_SUB_QUERY_THRESHOLD;
 
     //~ Instance fields --------------------------------------------------------
 
@@ -230,7 +237,6 @@ public class SqlToRelConverter {
     protected final RexBuilder rexBuilder;
     protected final Prepare.CatalogReader catalogReader;
     protected final RelOptCluster cluster;
-    private DefaultValueFactory defaultValueFactory;
     private SubQueryConverter subQueryConverter;
     protected final List<RelNode> leaves = new ArrayList<>();
     private final List<SqlDynamicParam> dynamicParamSqlNodes = new ArrayList<>();
@@ -244,7 +250,7 @@ public class SqlToRelConverter {
      * Fields used in name resolution for correlated sub-queries.
      */
     private final Map<CorrelationId, DeferredLookup> mapCorrelToDeferred =
-            new HashMap<>();
+        new HashMap<>();
 
     /**
      * Stack of names of datasets requested by the <code>
@@ -258,7 +264,7 @@ public class SqlToRelConverter {
      * already been evaluated.
      */
     private final Map<SqlNode, RexNode> mapConvertedNonCorrSubqs =
-            new HashMap<>();
+        new HashMap<>();
 
     public final RelOptTable.ViewExpander viewExpander;
 
@@ -275,44 +281,43 @@ public class SqlToRelConverter {
      */
     @Deprecated // to be removed before 2.0
     public SqlToRelConverter(
-            RelOptTable.ViewExpander viewExpander,
-            SqlValidator validator,
-            Prepare.CatalogReader catalogReader,
-            RelOptPlanner planner,
-            RexBuilder rexBuilder,
-            SqlRexConvertletTable convertletTable) {
+        RelOptTable.ViewExpander viewExpander,
+        SqlValidator validator,
+        Prepare.CatalogReader catalogReader,
+        RelOptPlanner planner,
+        RexBuilder rexBuilder,
+        SqlRexConvertletTable convertletTable) {
         this(viewExpander, validator, catalogReader,
-                RelOptCluster.create(planner, rexBuilder), convertletTable,
-                Config.DEFAULT);
+            RelOptCluster.create(planner, rexBuilder), convertletTable,
+            Config.DEFAULT);
     }
 
     @Deprecated // to be removed before 2.0
     public SqlToRelConverter(
-            RelOptTable.ViewExpander viewExpander,
-            SqlValidator validator,
-            Prepare.CatalogReader catalogReader,
-            RelOptCluster cluster,
-            SqlRexConvertletTable convertletTable) {
+        RelOptTable.ViewExpander viewExpander,
+        SqlValidator validator,
+        Prepare.CatalogReader catalogReader,
+        RelOptCluster cluster,
+        SqlRexConvertletTable convertletTable) {
         this(viewExpander, validator, catalogReader, cluster, convertletTable,
-                Config.DEFAULT);
+            Config.DEFAULT);
     }
 
     /* Creates a converter. */
     public SqlToRelConverter(
-            RelOptTable.ViewExpander viewExpander,
-            SqlValidator validator,
-            Prepare.CatalogReader catalogReader,
-            RelOptCluster cluster,
-            SqlRexConvertletTable convertletTable,
-            Config config) {
+        RelOptTable.ViewExpander viewExpander,
+        SqlValidator validator,
+        Prepare.CatalogReader catalogReader,
+        RelOptCluster cluster,
+        SqlRexConvertletTable convertletTable,
+        Config config) {
         this.viewExpander = viewExpander;
         this.opTab =
-                (validator
-                        == null) ? SqlStdOperatorTable.instance()
-                        : validator.getOperatorTable();
+            (validator
+                == null) ? SqlStdOperatorTable.instance()
+                : validator.getOperatorTable();
         this.validator = validator;
         this.catalogReader = catalogReader;
-        this.defaultValueFactory = new NullDefaultValueFactory();
         this.subQueryConverter = new NoOpSubQueryConverter();
         this.rexBuilder = cluster.getRexBuilder();
         this.typeFactory = rexBuilder.getTypeFactory();
@@ -393,21 +398,11 @@ public class SqlToRelConverter {
      * @param alreadyConvertedNonCorrSubqs the other map
      */
     public void addConvertedNonCorrSubqs(
-            Map<SqlNode, RexNode> alreadyConvertedNonCorrSubqs) {
+        Map<SqlNode, RexNode> alreadyConvertedNonCorrSubqs) {
         mapConvertedNonCorrSubqs.putAll(alreadyConvertedNonCorrSubqs);
     }
 
     /**
-     * Set a new DefaultValueFactory. To have any effect, this must be called
-     * before any convert method.
-     *
-     * @param factory new DefaultValueFactory
-     */
-    public void setDefaultValueFactory(DefaultValueFactory factory) {
-        defaultValueFactory = factory;
-    }
-
-    /**
      * Sets a new SubQueryConverter. To have any effect, this must be called
      * before any convert method.
      *
@@ -438,36 +433,36 @@ public class SqlToRelConverter {
         // validator type information associated with its result,
         // hence the namespace check above.)
         final List<RelDataTypeField> validatedFields =
-                validator.getValidatedNodeType(query).getFieldList();
+            validator.getValidatedNodeType(query).getFieldList();
         final RelDataType validatedRowType =
-                validator.getTypeFactory().createStructType(
-                        Pair.right(validatedFields),
-                        SqlValidatorUtil.uniquify(Pair.left(validatedFields),
-                                catalogReader.isCaseSensitive()));
+            validator.getTypeFactory().createStructType(
+                Pair.right(validatedFields),
+                SqlValidatorUtil.uniquify(Pair.left(validatedFields),
+                    catalogReader.nameMatcher().isCaseSensitive()));
 
         final List<RelDataTypeField> convertedFields =
-                result.getRowType().getFieldList().subList(0, validatedFields.size());
+            result.getRowType().getFieldList().subList(0, validatedFields.size());
         final RelDataType convertedRowType =
-                validator.getTypeFactory().createStructType(convertedFields);
+            validator.getTypeFactory().createStructType(convertedFields);
 
         if (!RelOptUtil.equal("validated row type", validatedRowType,
-                "converted row type", convertedRowType, Litmus.IGNORE)) {
+            "converted row type", convertedRowType, Litmus.IGNORE)) {
             throw new AssertionError("Conversion to relational algebra failed to "
-                    + "preserve datatypes:\n"
-                    + "validated type:\n"
-                    + validatedRowType.getFullTypeString()
-                    + "\nconverted type:\n"
-                    + convertedRowType.getFullTypeString()
-                    + "\nrel:\n"
-                    + RelOptUtil.toString(result));
+                + "preserve datatypes:\n"
+                + "validated type:\n"
+                + validatedRowType.getFullTypeString()
+                + "\nconverted type:\n"
+                + convertedRowType.getFullTypeString()
+                + "\nrel:\n"
+                + RelOptUtil.toString(result));
         }
     }
 
     public RelNode flattenTypes(
-            RelNode rootRel,
-            boolean restructure) {
+        RelNode rootRel,
+        boolean restructure) {
         RelStructuredTypeFlattener typeFlattener =
-                new RelStructuredTypeFlattener(rexBuilder, createToRelContext(), restructure);
+            new RelStructuredTypeFlattener(rexBuilder, createToRelContext(), restructure);
         return typeFlattener.rewrite(rootRel);
     }
 
@@ -514,20 +509,20 @@ public class SqlToRelConverter {
         if (isTrimUnusedFields()) {
             final RelFieldTrimmer trimmer = newFieldTrimmer();
             final List<RelCollation> collations =
-                    rootRel.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
+                rootRel.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
             rootRel = trimmer.trim(rootRel);
             if (!ordered
-                    && collations != null
-                    && !collations.isEmpty()
-                    && !collations.equals(ImmutableList.of(RelCollations.EMPTY))) {
+                && collations != null
+                && !collations.isEmpty()
+                && !collations.equals(ImmutableList.of(RelCollations.EMPTY))) {
                 final RelTraitSet traitSet = rootRel.getTraitSet()
-                        .replace(RelCollationTraitDef.INSTANCE, collations);
+                    .replace(RelCollationTraitDef.INSTANCE, collations);
                 rootRel = rootRel.copy(traitSet, rootRel.getInputs());
             }
             if (SQL2REL_LOGGER.isDebugEnabled()) {
                 SQL2REL_LOGGER.debug(
-                        RelOptUtil.dumpPlan("Plan after trimming unused fields", rootRel,
-                                SqlExplainFormat.TEXT, SqlExplainLevel.EXPPLAN_ATTRIBUTES));
+                    RelOptUtil.dumpPlan("Plan after trimming unused fields", rootRel,
+                        SqlExplainFormat.TEXT, SqlExplainLevel.EXPPLAN_ATTRIBUTES));
             }
         }
         return rootRel;
@@ -540,7 +535,7 @@ public class SqlToRelConverter {
      */
     protected RelFieldTrimmer newFieldTrimmer() {
         final RelBuilder relBuilder =
-                RelFactories.LOGICAL_BUILDER.create(cluster, null);
+            RelFactories.LOGICAL_BUILDER.create(cluster, null);
         return new RelFieldTrimmer(validator, relBuilder);
     }
 
@@ -556,17 +551,18 @@ public class SqlToRelConverter {
      *                        the query will be part of a view.
      */
     public RelRoot convertQuery(
-            SqlNode query,
-            final boolean needsValidation,
-            final boolean top) {
-        SqlNode origQuery = query; /* OVERRIDE POINT */
+        SqlNode query,
+        final boolean needsValidation,
+        final boolean top) {
 
+        SqlNode origQuery = query; /* OVERRIDE POINT */
+        
         if (needsValidation) {
             query = validator.validate(query);
         }
 
         RelMetadataQuery.THREAD_PROVIDERS.set(
-                JaninoRelMetadataProvider.of(cluster.getMetadataProvider()));
+            JaninoRelMetadataProvider.of(cluster.getMetadataProvider()));
         RelNode result = convertQueryRecursive(query, top, null).rel;
         if (top) {
             if (isStream(query)) {
@@ -583,27 +579,28 @@ public class SqlToRelConverter {
 
         if (SQL2REL_LOGGER.isDebugEnabled()) {
             SQL2REL_LOGGER.debug(
-                    RelOptUtil.dumpPlan("Plan after converting SqlNode to RelNode",
-                            result, SqlExplainFormat.TEXT,
-                            SqlExplainLevel.EXPPLAN_ATTRIBUTES));
+                RelOptUtil.dumpPlan("Plan after converting SqlNode to RelNode",
+                    result, SqlExplainFormat.TEXT,
+                    SqlExplainLevel.EXPPLAN_ATTRIBUTES));
         }
 
         final RelDataType validatedRowType = validator.getValidatedNodeType(query);
-        RelRoot origResult =  RelRoot.of(result, validatedRowType, query.getKind())
-                .withCollation(collation);
+        RelRoot origResult = RelRoot.of(result, validatedRowType, query.getKind())
+            .withCollation(collation);
         return hackSelectStar(origQuery, origResult);
     }
 
+
     /* OVERRIDE POINT */
     private RelRoot hackSelectStar(SqlNode query, RelRoot root) {
-//        /*
-//         * Rel tree is like:
-//         *
-//         *   LogicalSort (optional)
-//         *    |- LogicalProject
-//         *        |- LogicalFilter (optional)
-//         *            |- OLAPTableScan or LogicalJoin
-//         */
+        //        /*
+        //         * Rel tree is like:
+        //         *
+        //         *   LogicalSort (optional)
+        //         *    |- LogicalProject
+        //         *        |- LogicalFilter (optional)
+        //         *            |- OLAPTableScan or LogicalJoin
+        //         */
         LogicalProject rootPrj = null;
         LogicalSort rootSort = null;
         if (root.rel instanceof LogicalProject) {
@@ -614,16 +611,16 @@ public class SqlToRelConverter {
         } else {
             return root;
         }
-//
+        //
         RelNode input = rootPrj.getInput();
-//        if (!(//
-//                isAmong(input, "OLAPTableScan", "LogicalJoin")//
-//                || (isAmong(input, "LogicalFilter") && isAmong(input.getInput(0), "OLAPTableScan", "LogicalJoin"))//
-//             ))
-//            return root;
-//
-//        if (rootPrj.getRowType().getFieldCount() < input.getRowType().getFieldCount())
-//            return root;
+        //        if (!(//
+        //                isAmong(input, "OLAPTableScan", "LogicalJoin")//
+        //                || (isAmong(input, "LogicalFilter") && isAmong(input.getInput(0), "OLAPTableScan", "LogicalJoin"))//
+        //             ))
+        //            return root;
+        //
+        //        if (rootPrj.getRowType().getFieldCount() < input.getRowType().getFieldCount())
+        //            return root;
 
         RelDataType inType = rootPrj.getRowType();
         List<String> inFields = inType.getFieldNames();
@@ -654,25 +651,17 @@ public class SqlToRelConverter {
         return root;
     }
 
-    private boolean isAmong(RelNode rel, String... names) {
-        String simpleName = rel.getClass().getSimpleName();
-        for (String n : names) {
-            if (simpleName.equals(n))
-                return true;
-        }
-        return false;
-    }
 
     private static boolean isStream(SqlNode query) {
         return query instanceof SqlSelect
-                && ((SqlSelect) query).isKeywordPresent(SqlSelectKeyword.STREAM);
+            && ((SqlSelect) query).isKeywordPresent(SqlSelectKeyword.STREAM);
     }
 
     public static boolean isOrdered(SqlNode query) {
         switch (query.getKind()) {
             case SELECT:
                 return ((SqlSelect) query).getOrderList() != null
-                        && ((SqlSelect) query).getOrderList().size() > 0;
+                    && ((SqlSelect) query).getOrderList().size() > 0;
             case WITH:
                 return isOrdered(((SqlWith) query).body);
             case ORDER_BY:
@@ -709,7 +698,7 @@ public class SqlToRelConverter {
      * Factory method for creating translation workspace.
      */
     protected Blackboard createBlackboard(SqlValidatorScope scope,
-                                          Map<String, RexNode> nameToNodeMap, boolean top) {
+        Map<String, RexNode> nameToNodeMap, boolean top) {
         return new Blackboard(scope, nameToNodeMap, top);
     }
 
@@ -718,44 +707,44 @@ public class SqlToRelConverter {
      * derived class may override.
      */
     protected void convertSelectImpl(
-            final Blackboard bb,
-            SqlSelect select) {
+        final Blackboard bb,
+        SqlSelect select) {
         convertFrom(
-                bb,
-                select.getFrom());
+            bb,
+            select.getFrom());
         convertWhere(
-                bb,
-                select.getWhere());
+            bb,
+            select.getWhere());
 
         final List<SqlNode> orderExprList = new ArrayList<>();
         final List<RelFieldCollation> collationList = new ArrayList<>();
         gatherOrderExprs(
-                bb,
-                select,
-                select.getOrderList(),
-                orderExprList,
-                collationList);
+            bb,
+            select,
+            select.getOrderList(),
+            orderExprList,
+            collationList);
         final RelCollation collation =
-                cluster.traitSet().canonize(RelCollations.of(collationList));
+            cluster.traitSet().canonize(RelCollations.of(collationList));
 
         if (validator.isAggregate(select)) {
             convertAgg(
-                    bb,
-                    select,
-                    orderExprList);
+                bb,
+                select,
+                orderExprList);
         } else {
             convertSelectList(
-                    bb,
-                    select,
-                    orderExprList);
+                bb,
+                select,
+                orderExprList);
         }
 
         if (select.isDistinct()) {
             distinctify(bb, true);
         }
         convertOrder(
-                select, bb, collation, orderExprList, select.getOffset(),
-                select.getFetch());
+            select, bb, collation, orderExprList, select.getOffset(),
+            select.getFetch());
         bb.setRoot(bb.root, true);
     }
 
@@ -772,8 +761,8 @@ public class SqlToRelConverter {
      * @param checkForDupExprs Check for duplicate expressions
      */
     private void distinctify(
-            Blackboard bb,
-            boolean checkForDupExprs) {
+        Blackboard bb,
+        boolean checkForDupExprs) {
         // Look for duplicate expressions in the project.
         // Say we have 'select x, y, x, z'.
         // Then dups will be {[2, 0]}
@@ -808,8 +797,8 @@ public class SqlToRelConverter {
                 }
             }
             rel =
-                    LogicalProject.create(rel, Pair.left(newProjects),
-                            Pair.right(newProjects));
+                LogicalProject.create(rel, Pair.left(newProjects),
+                    Pair.right(newProjects));
             bb.root = rel;
             distinctify(bb, false);
             rel = bb.root;
@@ -821,18 +810,18 @@ public class SqlToRelConverter {
                 final int origin = origins.get(i);
                 RelDataTypeField field = fields.get(i);
                 undoProjects.add(
-                        Pair.of(
-                                (RexNode) new RexInputRef(
-                                        squished.get(origin), field.getType()),
-                                field.getName()));
+                    Pair.of(
+                        (RexNode) new RexInputRef(
+                            squished.get(origin), field.getType()),
+                        field.getName()));
             }
 
             rel =
-                    LogicalProject.create(rel, Pair.left(undoProjects),
-                            Pair.right(undoProjects));
+                LogicalProject.create(rel, Pair.left(undoProjects),
+                    Pair.right(undoProjects));
             bb.setRoot(
-                    rel,
-                    false);
+                rel,
+                false);
 
             return;
         }
@@ -840,14 +829,14 @@ public class SqlToRelConverter {
         // Usual case: all of the expressions in the SELECT clause are
         // different.
         final ImmutableBitSet groupSet =
-                ImmutableBitSet.range(rel.getRowType().getFieldCount());
+            ImmutableBitSet.range(rel.getRowType().getFieldCount());
         rel =
-                createAggregate(bb, false, groupSet, ImmutableList.of(groupSet),
-                        ImmutableList.<AggregateCall>of());
+            createAggregate(bb, false, groupSet, ImmutableList.of(groupSet),
+                ImmutableList.<AggregateCall>of());
 
         bb.setRoot(
-                rel,
-                false);
+            rel,
+            false);
     }
 
     private int findExpr(RexNode seek, List<RexNode> exprs, int count) {
@@ -873,28 +862,28 @@ public class SqlToRelConverter {
      * @param fetch         Expression for number of rows to fetch
      */
     protected void convertOrder(
-            SqlSelect select,
-            Blackboard bb,
-            RelCollation collation,
-            List<SqlNode> orderExprList,
-            SqlNode offset,
-            SqlNode fetch) {
+        SqlSelect select,
+        Blackboard bb,
+        RelCollation collation,
+        List<SqlNode> orderExprList,
+        SqlNode offset,
+        SqlNode fetch) {
         if (select.getOrderList() == null
-                || select.getOrderList().getList().isEmpty()) {
+            || select.getOrderList().getList().isEmpty()) {
             assert collation.getFieldCollations().isEmpty();
             if ((offset == null
-                    || ((SqlLiteral) offset).bigDecimalValue().equals(BigDecimal.ZERO))
-                    && fetch == null) {
+                || ((SqlLiteral) offset).bigDecimalValue().equals(BigDecimal.ZERO))
+                && fetch == null) {
                 return;
             }
         }
 
         // Create a sorter using the previously constructed collations.
         bb.setRoot(
-                LogicalSort.create(bb.root, collation,
-                        offset == null ? null : convertExpression(offset),
-                        fetch == null ? null : convertExpression(fetch)),
-                false);
+            LogicalSort.create(bb.root, collation,
+                offset == null ? null : convertExpression(offset),
+                fetch == null ? null : convertExpression(fetch)),
+            false);
 
         // If extra expressions were added to the project list for sorting,
         // add another project to remove them. But make the collation empty, because
@@ -905,14 +894,14 @@ public class SqlToRelConverter {
             final List<RexNode> exprs = new ArrayList<>();
             final RelDataType rowType = bb.root.getRowType();
             final int fieldCount =
-                    rowType.getFieldCount() - orderExprList.size();
+                rowType.getFieldCount() - orderExprList.size();
             for (int i = 0; i < fieldCount; i++) {
                 exprs.add(rexBuilder.makeInputRef(bb.root, i));
             }
             bb.setRoot(
-                    LogicalProject.create(bb.root, exprs,
-                            rowType.getFieldNames().subList(0, fieldCount)),
-                    false);
+                LogicalProject.create(bb.root, exprs,
+                    rowType.getFieldNames().subList(0, fieldCount)),
+                false);
         }
     }
 
@@ -922,17 +911,17 @@ public class SqlToRelConverter {
      * @param node a RexNode tree
      */
     private static boolean containsInOperator(
-            SqlNode node) {
+        SqlNode node) {
         try {
             SqlVisitor<Void> visitor =
-                    new SqlBasicVisitor<Void>() {
-                        public Void visit(SqlCall call) {
-                            if (call.getOperator() instanceof SqlInOperator) {
-                                throw new Util.FoundOne(call);
-                            }
-                            return super.visit(call);
+                new SqlBasicVisitor<Void>() {
+                    public Void visit(SqlCall call) {
+                        if (call.getOperator() instanceof SqlInOperator) {
+                            throw new Util.FoundOne(call);
                         }
-                    };
+                        return super.visit(call);
+                    }
+                };
             node.accept(visitor);
             return false;
         } catch (Util.FoundOne e) {
@@ -949,11 +938,11 @@ public class SqlToRelConverter {
      * @return the transformed SqlNode representation with NOT pushed down.
      */
     private static SqlNode pushDownNotForIn(SqlValidatorScope scope,
-                                            SqlNode sqlNode) {
+        SqlNode sqlNode) {
         if ((sqlNode instanceof SqlCall) && containsInOperator(sqlNode)) {
             SqlCall sqlCall = (SqlCall) sqlNode;
             if ((sqlCall.getOperator() == SqlStdOperatorTable.AND)
-                    || (sqlCall.getOperator() == SqlStdOperatorTable.OR)) {
+                || (sqlCall.getOperator() == SqlStdOperatorTable.OR)) {
                 SqlNode[] sqlOperands = ((SqlBasicCall) sqlCall).operands;
                 for (int i = 0; i < sqlOperands.length; i++) {
                     sqlOperands[i] = pushDownNotForIn(scope, sqlOperands[i]);
@@ -967,22 +956,30 @@ public class SqlToRelConverter {
                     SqlNode[] andOperands = childSqlCall.getOperands();
                     SqlNode[] orOperands = new SqlNode[andOperands.length];
                     for (int i = 0; i < orOperands.length; i++) {
-                        orOperands[i] = reg(scope, SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO, andOperands[i]));
+                        orOperands[i] = reg(scope,
+                            SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO,
+                                andOperands[i]));
                     }
                     for (int i = 0; i < orOperands.length; i++) {
                         orOperands[i] = pushDownNotForIn(scope, orOperands[i]);
                     }
-                    return reg(scope, SqlStdOperatorTable.OR.createCall(SqlParserPos.ZERO, orOperands[0], orOperands[1]));
+                    return reg(scope,
+                        SqlStdOperatorTable.OR.createCall(SqlParserPos.ZERO,
+                            orOperands[0], orOperands[1]));
                 } else if (childSqlCall.getOperator() == SqlStdOperatorTable.OR) {
                     SqlNode[] orOperands = childSqlCall.getOperands();
                     SqlNode[] andOperands = new SqlNode[orOperands.length];
                     for (int i = 0; i < andOperands.length; i++) {
-                        andOperands[i] = reg(scope, SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO, orOperands[i]));
+                        andOperands[i] = reg(scope,
+                            SqlStdOperatorTable.NOT.createCall(SqlParserPos.ZERO,
+                                orOperands[i]));
                     }
                     for (int i = 0; i < andOperands.length; i++) {
                         andOperands[i] = pushDownNotForIn(scope, andOperands[i]);
                     }
-                    return reg(scope, SqlStdOperatorTable.AND.createCall(SqlParserPos.ZERO, andOperands[0], andOperands[1]));
+                    return reg(scope,
+                        SqlStdOperatorTable.AND.createCall(SqlParserPos.ZERO,
+                            andOperands[0], andOperands[1]));
                 } else if (childSqlCall.getOperator() == SqlStdOperatorTable.NOT) {
                     SqlNode[] notOperands = childSqlCall.getOperands();
                     assert notOperands.length == 1;
@@ -990,11 +987,15 @@ public class SqlToRelConverter {
                 } else if (childSqlCall.getOperator() instanceof SqlInOperator) {
                     SqlNode[] inOperands = childSqlCall.getOperands();
                     SqlInOperator inOp =
-                            (SqlInOperator) childSqlCall.getOperator();
+                        (SqlInOperator) childSqlCall.getOperator();
                     if (inOp.isNotIn()) {
-                        return reg(scope, SqlStdOperatorTable.IN.createCall(SqlParserPos.ZERO, inOperands[0], inOperands[1]));
+                        return reg(scope,
+                            SqlStdOperatorTable.IN.createCall(SqlParserPos.ZERO,
+                                inOperands[0], inOperands[1]));
                     } else {
-                        return reg(scope, SqlStdOperatorTable.NOT_IN.createCall(SqlParserPos.ZERO, inOperands[0], inOperands[1]));
+                        return reg(scope,
+                            SqlStdOperatorTable.NOT_IN.createCall(SqlParserPos.ZERO,
+                                inOperands[0], inOperands[1]));
                     }
                 } else {
                     // childSqlCall is "leaf" node in a logical expression tree
@@ -1013,7 +1014,7 @@ public class SqlToRelConverter {
     }
 
     /** Registers with the validator a {@link SqlNode} that has been created
-      * during the Sql-to-Rel process. */
+     * during the Sql-to-Rel process. */
     private static SqlNode reg(SqlValidatorScope scope, SqlNode e) {
         scope.getValidator().deriveType(scope, e);
         return e;
@@ -1026,8 +1027,8 @@ public class SqlToRelConverter {
      * @param where WHERE clause, may be null
      */
     private void convertWhere(
-            final Blackboard bb,
-            final SqlNode where) {
+        final Blackboard bb,
+        final SqlNode where) {
         if (where == null) {
             return;
         }
@@ -1041,7 +1042,7 @@ public class SqlToRelConverter {
         }
 
         final RelFactories.FilterFactory factory =
-                RelFactories.DEFAULT_FILTER_FACTORY;
+            RelFactories.DEFAULT_FILTER_FACTORY;
         final RelNode filter = factory.createFilter(bb.root, convertedWhere);
         final RelNode r;
         final CorrelationUse p = getCorrelationUse(bb, filter);
@@ -1049,7 +1050,7 @@ public class SqlToRelConverter {
             assert p.r instanceof Filter;
             Filter f = (Filter) p.r;
             r = LogicalFilter.create(f.getInput(), f.getCondition(),
-                    ImmutableSet.of(p.id));
+                ImmutableSet.of(p.id));
         } else {
             r = filter;
         }
@@ -1058,9 +1059,9 @@ public class SqlToRelConverter {
     }
 
     private void replaceSubQueries(
-            final Blackboard bb,
-            final SqlNode expr,
-            RelOptUtil.Logic logic) {
+        final Blackboard bb,
+        final SqlNode expr,
+        RelOptUtil.Logic logic) {
         findSubQueries(bb, expr, logic, false);
         for (SubQuery node : bb.subQueryList) {
             substituteSubQuery(bb, node);
@@ -1114,14 +1115,14 @@ public class SqlToRelConverter {
                 if (query instanceof SqlNodeList) {
                     SqlNodeList valueList = (SqlNodeList) query;
                     if (!containsNullLiteral(valueList)
-                            && valueList.size() < config.getInSubQueryThreshold()) {
+                        && valueList.size() < config.getInSubQueryThreshold()) {
                         // We're under the threshold, so convert to OR.
                         subQuery.expr =
-                                convertInToOr(
-                                        bb,
-                                        leftKeys,
-                                        valueList,
-                                        notIn);
+                            convertInToOr(
+                                bb,
+                                leftKeys,
+                                valueList,
+                                notIn);
                         return;
                     }
 
@@ -1153,36 +1154,36 @@ public class SqlToRelConverter {
                 //         and q.indicator <> TRUE"
                 //
                 final RelDataType targetRowType =
-                        SqlTypeUtil.promoteToRowType(typeFactory,
-                                validator.getValidatedNodeType(leftKeyNode), null);
+                    SqlTypeUtil.promoteToRowType(typeFactory,
+                        validator.getValidatedNodeType(leftKeyNode), null);
                 converted =
-                        convertExists(query, RelOptUtil.SubQueryType.IN, subQuery.logic,
-                                notIn, targetRowType);
+                    convertExists(query, RelOptUtil.SubQueryType.IN, subQuery.logic,
+                        notIn, targetRowType);
                 if (converted.indicator) {
                     // Generate
                     //    emp CROSS JOIN (SELECT COUNT(*) AS c,
                     //                       COUNT(deptno) AS ck FROM dept)
                     final RelDataType longType =
-                            typeFactory.createSqlType(SqlTypeName.BIGINT);
+                        typeFactory.createSqlType(SqlTypeName.BIGINT);
                     final RelNode seek = converted.r.getInput(0); // fragile
                     final int keyCount = leftKeys.size();
                     final List<Integer> args = ImmutableIntList.range(0, keyCount);
                     LogicalAggregate aggregate =
-                            LogicalAggregate.create(seek, false, ImmutableBitSet.of(), null,
-                                    ImmutableList.of(
-                                            AggregateCall.create(SqlStdOperatorTable.COUNT, false,
-                                                    ImmutableList.<Integer>of(), -1, longType, null),
-                                            AggregateCall.create(SqlStdOperatorTable.COUNT, false,
-                                                    args, -1, longType, null)));
+                        LogicalAggregate.create(seek, false, ImmutableBitSet.of(), null,
+                            ImmutableList.of(
+                                AggregateCall.create(SqlStdOperatorTable.COUNT, false,
+                                    ImmutableList.<Integer>of(), -1, longType, null),
+                                AggregateCall.create(SqlStdOperatorTable.COUNT, false,
+                                    args, -1, longType, null)));
                     LogicalJoin join =
-                            LogicalJoin.create(bb.root, aggregate, rexBuilder.makeLiteral(true),
-                                    ImmutableSet.<CorrelationId>of(), JoinRelType.INNER);
+                        LogicalJoin.create(bb.root, aggregate, rexBuilder.makeLiteral(true),
+                            ImmutableSet.<CorrelationId>of(), JoinRelType.INNER);
                     bb.setRoot(join, false);
                 }
                 final RexNode rex =
-                        bb.register(converted.r,
-                                converted.outerJoin ? JoinRelType.LEFT : JoinRelType.INNER,
-                                leftKeys);
+                    bb.register(converted.r,
+                        converted.outerJoin ? JoinRelType.LEFT : JoinRelType.INNER,
+                        leftKeys);
 
                 RelOptUtil.Logic logic = subQuery.logic;
                 switch (logic) {
@@ -1195,7 +1196,7 @@ public class SqlToRelConverter {
                 subQuery.expr = translateIn(logic, bb.root, rex);
                 if (notIn) {
                     subQuery.expr =
-                            rexBuilder.makeCall(SqlStdOperatorTable.NOT, subQuery.expr);
+                        rexBuilder.makeCall(SqlStdOperatorTable.NOT, subQuery.expr);
                 }
                 return;
 
@@ -1215,7 +1216,7 @@ public class SqlToRelConverter {
                     return;
                 }
                 converted = convertExists(query, RelOptUtil.SubQueryType.EXISTS,
-                        subQuery.logic, true, null);
+                    subQuery.logic, true, null);
                 assert !converted.indicator;
                 if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, true)) {
                     return;
@@ -1232,7 +1233,7 @@ public class SqlToRelConverter {
                 call = (SqlBasicCall) subQuery.node;
                 query = call.operand(0);
                 converted = convertExists(query, RelOptUtil.SubQueryType.SCALAR,
-                        subQuery.logic, true, null);
+                    subQuery.logic, true, null);
                 assert !converted.indicator;
                 if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, false)) {
                     return;
@@ -1247,18 +1248,19 @@ public class SqlToRelConverter {
                 // select * from unnest(select multiset[deptno] from emps);
                 //
                 converted = convertExists(subQuery.node, RelOptUtil.SubQueryType.SCALAR,
-                        subQuery.logic, true, null);
+                    subQuery.logic, true, null);
                 assert !converted.indicator;
                 subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
                 return;
 
             default:
-                throw Util.newInternal("unexpected kind of sub-query :" + subQuery.node);
+                throw new AssertionError("unexpected kind of sub-query: "
+                    + subQuery.node);
         }
     }
 
     private RexNode translateIn(RelOptUtil.Logic logic, RelNode root,
-                                final RexNode rex) {
+        final RexNode rex) {
         switch (logic) {
             case TRUE:
                 return rexBuilder.makeLiteral(true);
@@ -1281,12 +1283,12 @@ public class SqlToRelConverter {
                 final int k = (fieldCount - 1) / 2;
                 for (int i = 0; i < k; i++) {
                     rexNode =
+                        rexBuilder.makeCall(
+                            SqlStdOperatorTable.AND,
+                            rexNode,
                             rexBuilder.makeCall(
-                                    SqlStdOperatorTable.AND,
-                                    rexNode,
-                                    rexBuilder.makeCall(
-                                            SqlStdOperatorTable.IS_NOT_NULL,
-                                            rexBuilder.makeFieldAccess(rex, i)));
+                                SqlStdOperatorTable.IS_NOT_NULL,
+                                rexBuilder.makeFieldAccess(rex, i)));
                 }
                 return rexNode;
 
@@ -1309,33 +1311,33 @@ public class SqlToRelConverter {
                 final RelNode leftLeft = ((Join) left.getInput()).getLeft();
                 final int leftLeftCount = leftLeft.getRowType().getFieldCount();
                 final RelDataType longType =
-                        typeFactory.createSqlType(SqlTypeName.BIGINT);
+                    typeFactory.createSqlType(SqlTypeName.BIGINT);
                 final RexNode cRef = rexBuilder.makeInputRef(root, leftLeftCount);
                 final RexNode ckRef = rexBuilder.makeInputRef(root, leftLeftCount + 1);
                 final RexNode iRef =
-                        rexBuilder.makeInputRef(root, root.getRowType().getFieldCount() - 1);
+                    rexBuilder.makeInputRef(root, root.getRowType().getFieldCount() - 1);
 
                 final RexLiteral zero =
-                        rexBuilder.makeExactLiteral(BigDecimal.ZERO, longType);
+                    rexBuilder.makeExactLiteral(BigDecimal.ZERO, longType);
                 final RexLiteral trueLiteral = rexBuilder.makeLiteral(true);
                 final RexLiteral falseLiteral = rexBuilder.makeLiteral(false);
                 final RexNode unknownLiteral =
-                        rexBuilder.makeNullLiteral(SqlTypeName.BOOLEAN);
+                    rexBuilder.makeNullLiteral(trueLiteral.getType());
 
                 final ImmutableList.Builder<RexNode> args = ImmutableList.builder();
                 args.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, cRef, zero),
-                        falseLiteral,
-                        rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, iRef),
-                        trueLiteral);
+                    falseLiteral,
+                    rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, iRef),
+                    trueLiteral);
                 final JoinInfo joinInfo = join.analyzeCondition();
                 for (int leftKey : joinInfo.leftKeys) {
                     final RexNode kRef = rexBuilder.makeInputRef(root, leftKey);
                     args.add(rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, kRef),
-                            unknownLiteral);
+                        unknownLiteral);
                 }
                 args.add(rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, ckRef, cRef),
-                        unknownLiteral,
-                        falseLiteral);
+                    unknownLiteral,
+                    falseLiteral);
 
                 return rexBuilder.makeCall(SqlStdOperatorTable.CASE, args.build());
 
@@ -1367,24 +1369,24 @@ public class SqlToRelConverter {
      * @return Whether the sub-query can be converted to a constant
      */
     private boolean convertNonCorrelatedSubQuery(
-            SubQuery subQuery,
-            Blackboard bb,
-            RelNode converted,
-            boolean isExists) {
+        SubQuery subQuery,
+        Blackboard bb,
+        RelNode converted,
+        boolean isExists) {
         SqlCall call = (SqlBasicCall) subQuery.node;
         if (subQueryConverter.canConvertSubQuery()
-                && isSubQueryNonCorrelated(converted, bb)) {
+            && isSubQueryNonCorrelated(converted, bb)) {
             // First check if the sub-query has already been converted
             // because it's a nested sub-query.  If so, don't re-evaluate
             // it again.
             RexNode constExpr = mapConvertedNonCorrSubqs.get(call);
             if (constExpr == null) {
                 constExpr =
-                        subQueryConverter.convertSubQuery(
-                                call,
-                                this,
-                                isExists,
-                                config.isExplain());
+                    subQueryConverter.convertSubQuery(
+                        call,
+                        this,
+                        isExists,
+                        config.isExplain());
             }
             if (constExpr != null) {
                 subQuery.expr = constExpr;
@@ -1404,8 +1406,8 @@ public class SqlToRelConverter {
      * @return the converted RelNode tree
      */
     public RelNode convertToSingleValueSubq(
-            SqlNode query,
-            RelNode plan) {
+        SqlNode query,
+        RelNode plan) {
         // Check whether query is guaranteed to produce a single value.
         if (query instanceof SqlSelect) {
             SqlSelect select = (SqlSelect) query;
@@ -1413,7 +1415,7 @@ public class SqlToRelConverter {
             SqlNodeList groupList = select.getGroup();
 
             if ((selectList.size() == 1)
-                    && ((groupList == null) || (groupList.size() == 0))) {
+                && ((groupList == null) || (groupList.size() == 0))) {
                 SqlNode selectExpr = selectList.get(0);
                 if (selectExpr instanceof SqlCall) {
                     SqlCall selectExprCall = (SqlCall) selectExpr;
@@ -1425,7 +1427,7 @@ public class SqlToRelConverter {
                 // If there is a limit with 0 or 1,
                 // it is ensured to produce a single value
                 if (select.getFetch() != null
-                        && select.getFetch() instanceof SqlNumericLiteral) {
+                    && select.getFetch() instanceof SqlNumericLiteral) {
                     SqlNumericLiteral limitNum = (SqlNumericLiteral) select.getFetch();
                     if (((BigDecimal) limitNum.getValue()).intValue() < 2) {
                         return plan;
@@ -1438,16 +1440,16 @@ public class SqlToRelConverter {
             // whether SingleValueAgg is necessary
             SqlCall exprCall = (SqlCall) query;
             if (exprCall.getOperator()
-                    instanceof SqlValuesOperator
-                    && Util.isSingleValue(exprCall)) {
+                instanceof SqlValuesOperator
+                && Util.isSingleValue(exprCall)) {
                 return plan;
             }
         }
 
         // If not, project SingleValueAgg
         return RelOptUtil.createSingleValueAggRel(
-                cluster,
-                plan);
+            cluster,
+            plan);
     }
 
     /**
@@ -1459,51 +1461,51 @@ public class SqlToRelConverter {
      * @return converted expression
      */
     private RexNode convertInToOr(
-            final Blackboard bb,
-            final List<RexNode> leftKeys,
-            SqlNodeList valuesList,
-            boolean isNotIn) {
+        final Blackboard bb,
+        final List<RexNode> leftKeys,
+        SqlNodeList valuesList,
+        boolean isNotIn) {
         final List<RexNode> comparisons = new ArrayList<>();
         for (SqlNode rightVals : valuesList) {
             RexNode rexComparison;
             if (leftKeys.size() == 1) {
                 rexComparison =
-                        rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
-                                leftKeys.get(0),
-                                ensureSqlType(leftKeys.get(0).getType(),
-                                        bb.convertExpression(rightVals)));
+                    rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+                        leftKeys.get(0),
+                        ensureSqlType(leftKeys.get(0).getType(),
+                            bb.convertExpression(rightVals)));
             } else {
                 assert rightVals instanceof SqlCall;
                 final SqlBasicCall call = (SqlBasicCall) rightVals;
                 assert (call.getOperator() instanceof SqlRowOperator)
-                        && call.operandCount() == leftKeys.size();
+                    && call.operandCount() == leftKeys.size();
                 rexComparison =
-                        RexUtil.composeConjunction(
-                                rexBuilder,
-                                Iterables.transform(
-                                        Pair.zip(leftKeys, call.getOperandList()),
-                                        new Function<Pair<RexNode, SqlNode>, RexNode>() {
-                                            public RexNode apply(Pair<RexNode, SqlNode> pair) {
-                                                return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
-                                                        pair.left,
-                                                        ensureSqlType(pair.left.getType(),
-                                                                bb.convertExpression(pair.right)));
-                                            }
-                                        }),
-                                false);
+                    RexUtil.composeConjunction(
+                        rexBuilder,
+                        Iterables.transform(
+                            Pair.zip(leftKeys, call.getOperandList()),
+                            new Function<Pair<RexNode, SqlNode>, RexNode>() {
+                                public RexNode apply(Pair<RexNode, SqlNode> pair) {
+                                    return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+                                        pair.left,
+                                        ensureSqlType(pair.left.getType(),
+                                            bb.convertExpression(pair.right)));
+                                }
+                            }),
+                        false);
             }
             comparisons.add(rexComparison);
         }
 
         RexNode result =
-                RexUtil.composeDisjunction(rexBuilder, comparisons, true);
+            RexUtil.composeDisjunction(rexBuilder, comparisons, true);
         assert result != null;
 
         if (isNotIn) {
             result =
-                    rexBuilder.makeCall(
-                            SqlStdOperatorTable.NOT,
-                            result);
+                rexBuilder.makeCall(
+                    SqlStdOperatorTable.NOT,
+                    result);
         }
 
         return result;
@@ -1514,8 +1516,8 @@ public class SqlToRelConverter {
      * returns the expression unchanged. */
     private RexNode ensureSqlType(RelDataType type, RexNode node) {
         if (type.getSqlTypeName() == node.getType().getSqlTypeName()
-                || (type.getSqlTypeName() == SqlTypeName.VARCHAR
-                && node.getType().getSqlTypeName() == SqlTypeName.CHAR)) {
+            || (type.getSqlTypeName() == SqlTypeName.VARCHAR
+            && node.getType().getSqlTypeName() == SqlTypeName.CHAR)) {
             return node;
         }
         return rexBuilder.ensureType(type, node, true);
@@ -1551,18 +1553,17 @@ public class SqlToRelConverter {
      *     approximation (say representing UNKNOWN as FALSE)
      * @param notIn Whether the operation is NOT IN
      * @return join expression
-     * @pre extraExpr == null || extraName != null
      */
     private RelOptUtil.Exists convertExists(
-            SqlNode seek,
-            RelOptUtil.SubQueryType subQueryType,
-            RelOptUtil.Logic logic,
-            boolean notIn,
-            RelDataType targetDataType) {
+        SqlNode seek,
+        RelOptUtil.SubQueryType subQueryType,
+        RelOptUtil.Logic logic,
+        boolean notIn,
+        RelDataType targetDataType) {
         final SqlValidatorScope seekScope =
-                (seek instanceof SqlSelect)
-                        ? validator.getSelectScope((SqlSelect) seek)
-                        : null;
+            (seek instanceof SqlSelect)
+                ? validator.getSelectScope((SqlSelect) seek)
+                : null;
         final Blackboard seekBb = createBlackboard(seekScope, null, false);
         RelNode seekRel = convertQueryOrInList(seekBb, seek, targetDataType);
 
@@ -1570,9 +1571,9 @@ public class SqlToRelConverter {
     }
 
     private RelNode convertQueryOrInList(
-            Blackboard bb,
-            SqlNode seek,
-            RelDataType targetRowType) {
+        Blackboard bb,
+        SqlNode seek,
+        RelDataType targetRowType) {
         // NOTE: Once we start accepting single-row queries as row constructors,
         // there will be an ambiguity here for a case like X IN ((SELECT Y FROM
         // Z)).  The SQL standard resolves the ambiguity by saying that a lone
@@ -1581,22 +1582,22 @@ public class SqlToRelConverter {
         // return multiple rows.
         if (seek instanceof SqlNodeList) {
             return convertRowValues(
-                    bb,
-                    seek,
-                    ((SqlNodeList) seek).getList(),
-                    false,
-                    targetRowType);
+                bb,
+                seek,
+                ((SqlNodeList) seek).getList(),
+                false,
+                targetRowType);
         } else {
             return convertQueryRecursive(seek, false, null).project();
         }
     }
 
     private RelNode convertRowValues(
-            Blackboard bb,
-            SqlNode rowList,
-            Collection<SqlNode> rows,
-            boolean allowLiteralsOnly,
-            RelDataType targetRowType) {
+        Blackboard bb,
+        SqlNode rowList,
+        Collection<SqlNode> rows,
+        boolean allowLiteralsOnly,
+        RelDataType targetRowType) {
         // NOTE jvs 30-Apr-2006: We combine all rows consisting entirely of
         // literals into a single LogicalValues; this gives the optimizer a smaller
         // input tree.  For everything else (computed expressions, row
@@ -1604,16 +1605,16 @@ public class SqlToRelConverter {
         // LogicalOneRow.
 
         final ImmutableList.Builder<ImmutableList<RexLiteral>> tupleList =
-                ImmutableList.builder();
+            ImmutableList.builder();
         final RelDataType rowType;
         if (targetRowType != null) {
             rowType = targetRowType;
         } else {
             rowType =
-                    SqlTypeUtil.promoteToRowType(
-                            typeFactory,
-                            validator.getValidatedNodeType(rowList),
-                            null);
+                SqlTypeUtil.promoteToRowType(
+                    typeFactory,
+                    validator.getValidatedNodeType(rowList),
+                    null);
         }
 
         final List<RelNode> unionInputs = new ArrayList<>();
@@ -1624,11 +1625,11 @@ public class SqlToRelConverter {
                 ImmutableList.Builder<RexLiteral> tuple = ImmutableList.builder();
                 for (Ord<SqlNode> operand : Ord.zip(call.operands)) {
                     RexLiteral rexLiteral =
-                            convertLiteralInValuesList(
-                                    operand.e,
-                                    bb,
-                                    rowType,
-                                    operand.i);
+                        convertLiteralInValuesList(
+                            operand.e,
+                            bb,
+                            rowType,
+                            operand.i);
                     if ((rexLiteral == null) && allowLiteralsOnly) {
                         return null;
                     }
@@ -1645,11 +1646,11 @@ public class SqlToRelConverter {
                 }
             } else {
                 RexLiteral rexLiteral =
-                        convertLiteralInValuesList(
-                                node,
-                                bb,
-                                rowType,
-                                0);
+                    convertLiteralInValuesList(
+                        node,
+                        bb,
+                        rowType,
+                        0);
                 if ((rexLiteral != null) && config.isCreateValuesRel()) {
                     tupleList.add(ImmutableList.of(rexLiteral));
                     continue;
@@ -1661,14 +1662,14 @@ public class SqlToRelConverter {
 
                 // convert "1" to "row(1)"
                 call =
-                        (SqlBasicCall) SqlStdOperatorTable.ROW.createCall(
-                                SqlParserPos.ZERO,
-                                node);
+                    (SqlBasicCall) SqlStdOperatorTable.ROW.createCall(
+                        SqlParserPos.ZERO,
+                        node);
             }
             unionInputs.add(convertRowConstructor(bb, call));
         }
         LogicalValues values =
-                LogicalValues.create(cluster, rowType, tupleList.build());
+            LogicalValues.create(cluster, rowType, tupleList.build());
         RelNode resultRel;
         if (unionInputs.isEmpty()) {
             resultRel = values;
@@ -1683,10 +1684,10 @@ public class SqlToRelConverter {
     }
 
     private RexLiteral convertLiteralInValuesList(
-            SqlNode sqlNode,
-            Blackboard bb,
-            RelDataType rowType,
-            int iField) {
+        SqlNode sqlNode,
+        Blackboard bb,
+        RelDataType rowType,
+        int iField) {
         if (!(sqlNode instanceof SqlLiteral)) {
             return null;
         }
@@ -1700,9 +1701,9 @@ public class SqlToRelConverter {
         }
 
         RexNode literalExpr =
-                exprConverter.convertLiteral(
-                        bb,
-                        (SqlLiteral) sqlNode);
+            exprConverter.convertLiteral(
+                bb,
+                (SqlLiteral) sqlNode);
 
         if (!(literalExpr instanceof RexLiteral)) {
             assert literalExpr.isA(SqlKind.CAST);
@@ -1720,23 +1721,23 @@ public class SqlToRelConverter {
 
         if (SqlTypeUtil.isExactNumeric(type) && SqlTypeUtil.hasScale(type)) {
             BigDecimal roundedValue =
-                    NumberUtil.rescaleBigDecimal(
-                            (BigDecimal) value,
-                            type.getScale());
+                NumberUtil.rescaleBigDecimal(
+                    (BigDecimal) value,
+                    type.getScale());
             return rexBuilder.makeExactLiteral(
-                    roundedValue,
-                    type);
+                roundedValue,
+                type);
         }
 
         if ((value instanceof NlsString)
-                && (type.getSqlTypeName() == SqlTypeName.CHAR)) {
+            && (type.getSqlTypeName() == SqlTypeName.CHAR)) {
             // pad fixed character type
             NlsString unpadded = (NlsString) value;
             return rexBuilder.makeCharLiteral(
-                    new NlsString(
-                            Spaces.padRight(unpadded.getValue(), type.getPrecision()),
-                            unpadded.getCharsetName(),
-                            unpadded.getCollation()));
+                new NlsString(
+                    Spaces.padRight(unpadded.getValue(), type.getPrecision()),
+                    unpadded.getCharsetName(),
+                    unpadded.getCollation()));
         }
         return literal;
     }
@@ -1764,10 +1765,10 @@ public class SqlToRelConverter {
      *                                     sub-query
      */
     private void findSubQueries(
-            Blackboard bb,
-            SqlNode node,
-            RelOptUtil.Logic logic,
-            boolean registerOnlyScalarSubQueries) {
+        Blackboard bb,
+        SqlNode node,
+        RelOptUtil.Logic logic,
+        boolean registerOnlyScalarSubQueries) {
         final SqlKind kind = node.getKind();
         switch (kind) {
             case EXISTS:
@@ -1778,7 +1779,7 @@ public class SqlToRelConverter {
             case CURSOR:
             case SCALAR_QUERY:
                 if (!registerOnlyScalarSubQueries
-                        || (kind == SqlKind.SCALAR_QUERY)) {
+                    || (kind == SqlKind.SCALAR_QUERY)) {
                     bb.registerSubQuery(node, RelOptUtil.Logic.TRUE_FALSE);
                 }
                 return;
@@ -1797,19 +1798,19 @@ public class SqlToRelConverter {
                     // In the case of an IN expression, locate scalar
                     // sub-queries so we can convert them to constants
                     findSubQueries(
-                            bb,
-                            operand,
-                            logic,
-                            kind == SqlKind.IN || registerOnlyScalarSubQueries);
+                        bb,
+                        operand,
+                        logic,
+                        kind == SqlKind.IN || registerOnlyScalarSubQueries);
                 }
             }
         } else if (node instanceof SqlNodeList) {
             for (SqlNode child : (SqlNodeList) node) {
                 findSubQueries(
-                        bb,
-                        child,
-                        logic,
-                        kind == SqlKind.IN || registerOnlyScalarSubQueries);
+                    bb,
+                    child,
+                    logic,
+                    kind == SqlKind.IN || registerOnlyScalarSubQueries);
             }
         }
 
@@ -1840,10 +1841,10 @@ public class SqlToRelConverter {
      * @return Converted expression
      */
     public RexNode convertExpression(
-            SqlNode node) {
+        SqlNode node) {
         Map<String, RelDataType> nameToTypeMap = Collections.emptyMap();
         final ParameterScope scope =
-                new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
+            new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
         final Blackboard bb = createBlackboard(scope, null, false);
         return bb.convertExpression(node);
     }
@@ -1860,14 +1861,14 @@ public class SqlToRelConverter {
      * @return Converted expression
      */
     public RexNode convertExpression(
-            SqlNode node,
-            Map<String, RexNode> nameToNodeMap) {
+        SqlNode node,
+        Map<String, RexNode> nameToNodeMap) {
         final Map<String, RelDataType> nameToTypeMap = new HashMap<>();
         for (Map.Entry<String, RexNode> entry : nameToNodeMap.entrySet()) {
             nameToTypeMap.put(entry.getKey(), entry.getValue().getType());
         }
         final ParameterScope scope =
-                new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
+            new ParameterScope((SqlValidatorImpl) validator, nameToTypeMap);
         final Blackboard bb = createBlackboard(scope, nameToNodeMap, false);
         return bb.convertExpression(node);
     }
@@ -1884,8 +1885,8 @@ public class SqlToRelConverter {
      * @return null to proceed with the usual expression translation process
      */
     protected RexNode convertExtendedExpression(
-            SqlNode node,
-            Blackboard bb) {
+        SqlNode node,
+        Blackboard bb) {
         return null;
     }
 
@@ -1894,7 +1895,7 @@ public class SqlToRelConverter {
         SqlCall aggCall = call.operand(0);
         SqlNode windowOrRef = call.operand(1);
         final SqlWindow window =
-                validator.resolveWindow(windowOrRef, bb.scope, true);
+            validator.resolveWindow(windowOrRef, bb.scope, true);
 
         // ROW_NUMBER() expects specific kind of framing.
         if (aggCall.getKind() == SqlKind.ROW_NUMBER) {
@@ -1904,7 +1905,7 @@ public class SqlToRelConverter {
         }
         final SqlNodeList partitionList = window.getPartitionList();
         final ImmutableList.Builder<RexNode> partitionKeys =
-                ImmutableList.builder();
+            ImmutableList.builder();
         for (SqlNode partition : partitionList) {
             partitionKeys.add(bb.convertExpression(partition));
         }
@@ -1918,11 +1919,11 @@ public class SqlToRelConverter {
             orderList = bb.scope.getOrderList();
             if (orderList == null) {
                 throw new AssertionError(
-                        "Relation should have sort key for implicit ORDER BY");
+                    "Relation should have sort key for implicit ORDER BY");
             }
         }
         final ImmutableList.Builder<RexFieldCollation> orderKeys =
-                ImmutableList.builder();
+            ImmutableList.builder();
         final Set<SqlKind> flags = EnumSet.noneOf(SqlKind.class);
         for (SqlNode order : orderList) {
             flags.clear();
@@ -1930,22 +1931,23 @@ public class SqlToRelConverter {
             orderKeys.add(new RexFieldCollation(e, flags));
         }
         try {
-            Util.permAssert(bb.window == null, "already in window agg mode");
+            Preconditions.checkArgument(bb.window == null,
+                "already in window agg mode");
             bb.window = window;
             RexNode rexAgg = exprConverter.convertCall(bb, aggCall);
             rexAgg =
-                    rexBuilder.ensureType(
-                            validator.getValidatedNodeType(call), rexAgg, false);
+                rexBuilder.ensureType(
+                    validator.getValidatedNodeType(call), rexAgg, false);
 
             // Walk over the tree and apply 'over' to all agg functions. This is
             // necessary because the returned expression is not necessarily a call
             // to an agg function. For example, AVG(x) becomes SUM(x) / COUNT(x).
             final RexShuttle visitor =
-                    new HistogramShuttle(
-                            partitionKeys.build(), orderKeys.build(),
-                            RexWindowBound.create(window.getLowerBound(), lowerBound),
-                            RexWindowBound.create(window.getUpperBound(), upperBound),
-                            window);
+                new HistogramShuttle(
+                    partitionKeys.build(), orderKeys.build(),
+                    RexWindowBound.create(window.getLowerBound(), lowerBound),
+                    RexWindowBound.create(window.getUpperBound(), upperBound),
+                    window);
             return rexAgg.accept(visitor);
         } finally {
             bb.window = null;
@@ -1970,8 +1972,8 @@ public class SqlToRelConverter {
      *             </ul>
      */
     protected void convertFrom(
-            Blackboard bb,
-            SqlNode from) {
+        Blackboard bb,
+        SqlNode from) {
         if (from == null) {
             bb.setRoot(LogicalValues.createOneRow(cluster), false);
             return;
@@ -1980,6 +1982,10 @@ public class SqlToRelConverter {
         final SqlCall call;
         final SqlNode[] operands;
         switch (from.getKind()) {
+            case MATCH_RECOGNIZE:
+                convertMatchRecognize(bb, (SqlCall) from);
+                return;
+
             case AS:
                 convertFrom(bb, ((SqlCall) from).operand(0));
                 return;
@@ -1997,54 +2003,36 @@ public class SqlToRelConverter {
                 SqlSampleSpec sampleSpec = SqlLiteral.sampleValue(operands[1]);
                 if (sampleSpec instanceof SqlSampleSpec.SqlSubstitutionSampleSpec) {
                     String sampleName =
-                            ((SqlSampleSpec.SqlSubstitutionSampleSpec) sampleSpec)
-                                    .getName();
+                        ((SqlSampleSpec.SqlSubstitutionSampleSpec) sampleSpec)
+                            .getName();
                     datasetStack.push(sampleName);
                     convertFrom(bb, operands[0]);
                     datasetStack.pop();
                 } else if (sampleSpec instanceof SqlSampleSpec.SqlTableSampleSpec) {
                     SqlSampleSpec.SqlTableSampleSpec tableSampleSpec =
-                            (SqlSampleSpec.SqlTableSampleSpec) sampleSpec;
+                        (SqlSampleSpec.SqlTableSampleSpec) sampleSpec;
                     convertFrom(bb, operands[0]);
                     RelOptSamplingParameters params =
-                            new RelOptSamplingParameters(
-                                    tableSampleSpec.isBernoulli(),
-                                    tableSampleSpec.getSamplePercentage(),
-                                    tableSampleSpec.isRepeatable(),
-                                    tableSampleSpec.getRepeatableSeed());
+                        new RelOptSamplingParameters(
+                            tableSampleSpec.isBernoulli(),
+                            tableSampleSpec.getSamplePercentage(),
+                            tableSampleSpec.isRepeatable(),
+                            tableSampleSpec.getRepeatableSeed());
                     bb.setRoot(new Sample(cluster, bb.root, params), false);
                 } else {
-                    throw Util.newInternal(
-                            "unknown TABLESAMPLE type: " + sampleSpec);
+                    throw new AssertionError("unknown TABLESAMPLE type: " + sampleSpec);
                 }
                 return;
 
             case IDENTIFIER:
-                final SqlValidatorNamespace fromNamespace =
-                        validator.getNamespace(from).resolve();
-                if (fromNamespace.getNode() != null) {
-                    convertFrom(bb, fromNamespace.getNode());
-                    return;
-                }
-                final String datasetName =
-                        datasetStack.isEmpty() ? null : datasetStack.peek();
-                boolean[] usedDataset = {false};
-                RelOptTable table =
-                        SqlValidatorUtil.getRelOptTable(
-                                fromNamespace,
-                                catalogReader,
-                                datasetName,
-                                usedDataset);
-                final RelNode tableRel;
-                if (config.isConvertTableAccess()) {
-                    tableRel = toRel(table);
-                } else {
-                    tableRel = LogicalTableScan.create(cluster, table);
-                }
-                bb.setRoot(tableRel, true);
-                if (usedDataset[0]) {
-                    bb.setDataset(datasetName);
-                }
+                convertIdentifier(bb, (SqlIdentifier) from, null);
+                return;
+
+            case EXTEND:
+                call = (SqlCall) from;
+                SqlIdentifier id = (SqlIdentifier) call.getOperandList().get(0);
+                SqlNodeList extendedColumns = (SqlNodeList) call.getOperandList().get(1);
+                convertIdentifier(bb, id, extendedColumns);
                 return;
 
             case JOIN:
@@ -2056,15 +2044,15 @@ public class SqlToRelConverter {
                 final boolean isNatural = join.isNatural();
                 final JoinType joinType = join.getJoinType();
                 final SqlValidatorScope leftScope =
-                        Util.first(validator.getJoinScope(left),
-                                ((DelegatingScope) bb.scope).getParent());
+                    Util.first(validator.getJoinScope(left),
+                        ((DelegatingScope) bb.scope).getParent());
                 final Blackboard leftBlackboard =
-                        createBlackboard(leftScope, null, false);
+                    createBlackboard(leftScope, null, false);
                 final SqlValidatorScope rightScope =
-                        Util.first(validator.getJoinScope(right),
-                                ((DelegatingScope) bb.scope).getParent());
+                    Util.first(validator.getJoinScope(right),
+                        ((DelegatingScope) bb.scope).getParent());
                 final Blackboard rightBlackboard =
-                        createBlackboard(rightScope, null, false);
+                    createBlackboard(rightScope, null, false);
                 convertFrom(leftBlackboard, left);
                 RelNode leftRel = leftBlackboard.root;
                 convertFrom(rightBlackboard, right);
@@ -2077,29 +2065,29 @@ public class SqlToRelConverter {
                     final RelDataType leftRowType = leftNamespace.getRowType();
                     final RelDataType rightRowType = rightNamespace.getRowType();
                     final List<String> columnList =
-                            SqlValidatorUtil.deriveNaturalJoinColumnList(leftRowType,
-                                    rightRowType);
+                        SqlValidatorUtil.deriveNaturalJoinColumnList(leftRowType,
+                            rightRowType);
                     conditionExp = convertUsing(leftNamespace, rightNamespace,
-                            columnList);
+                        columnList);
                 } else {
                     conditionExp =
-                            convertJoinCondition(
-                                    fromBlackboard,
-                                    leftNamespace,
-                                    rightNamespace,
-                                    join.getCondition(),
-                                    join.getConditionType(),
-                                    leftRel,
-                                    rightRel);
+                        convertJoinCondition(
+                            fromBlackboard,
+                            leftNamespace,
+                            rightNamespace,
+                            join.getCondition(),
+                            join.getConditionType(),
+                            leftRel,
+                            rightRel);
                 }
 
                 final RelNode joinRel =
-                        createJoin(
-                                fromBlackboard,
-                                leftRel,
-                                rightRel,
-                                conditionExp,
-                                convertedJoinType);
+                    createJoin(
+                        fromBlackboard,
+                        leftRel,
+                        rightRel,
+                        conditionExp,
+                        convertedJoinType);
                 bb.setRoot(joinRel, false);
                 return;
 
@@ -2129,13 +2117,13 @@ public class SqlToRelConverter {
                     fieldNames.add(validator.deriveAlias(node.e, node.i));
                 }
                 final RelNode input =
-                        RelOptUtil.createProject(
-                                (null != bb.root) ? bb.root : LogicalValues.createOneRow(cluster),
-                                exprs, fieldNames, true);
+                    RelOptUtil.createProject(
+                        (null != bb.root) ? bb.root : LogicalValues.createOneRow(cluster),
+                        exprs, fieldNames, true);
 
                 Uncollect uncollect =
-                        new Uncollect(cluster, cluster.traitSetOf(Convention.NONE),
-                                input, operator.withOrdinality);
+                    new Uncollect(cluster, cluster.traitSetOf(Convention.NONE),
+                        input, operator.withOrdinality);
                 bb.setRoot(uncollect, true);
                 return;
 
@@ -2149,13 +2137,116 @@ public class SqlToRelConverter {
                 return;
 
             default:
-                throw Util.newInternal("not a join operator " + from);
+                throw new AssertionError("not a join operator " + from);
+        }
+    }
+
+    protected void convertMatchRecognize(Blackboard bb, SqlCall call) {
+        final SqlMatchRecognize matchRecognize = (SqlMatchRecognize) call;
+        final SqlValidatorNamespace ns = validator.getNamespace(matchRecognize);
+        final SqlValidatorScope scope = validator.getMatchRecognizeScope(matchRecognize);
+
+        final Blackboard mrBlackBoard = createBlackboard(scope, null, false);
+        final RelDataType rowType = ns.getRowType();
+        // convert inner query, could be a table name or a derived table
+        SqlNode expr = matchRecognize.getTableRef();
+        convertFrom(mrBlackBoard, expr);
+        final RelNode input = mrBlackBoard.root;
+
+        // convert pattern
+        final Set<String> patternVarsSet = new HashSet<>();
+        SqlNode pattern = matchRecognize.getPattern();
+        final SqlBasicVisitor<RexNode> patternVarVisitor =
+            new SqlBasicVisitor<RexNode>() {
+                @Override public RexNode visit(SqlCall call) {
+                    List<SqlNode> operands = call.getOperandList();
+                    List<RexNode> newOperands = Lists.newArrayList();
+                    for (SqlNode node : operands) {
+                        newOperands.add(node.accept(this));
+                    }
+                    return rexBuilder.makeCall(
+                        validator.getUnknownType(), call.getOperator(), newOperands);
+                }
+
+                @Override public RexNode visit(SqlIdentifier id) {
+                    assert id.isSimple();
+                    patternVarsSet.add(id.getSimple());
+                    return rexBuilder.makeLiteral(id.getSimple());
+                }
+
+                @Override public RexNode visit(SqlLiteral literal) {
+                    if (literal instanceof SqlNumericLiteral) {
+                        return rexBuilder.makeExactLiteral(BigDecimal.valueOf(literal.intValue(true)));
+                    } else {
+                        return rexBuilder.makeLiteral(literal.booleanValue());
+                    }
+                }
+            };
+        final RexNode patternNode = pattern.accept(patternVarVisitor);
+
+        mrBlackBoard.setPatternVarRef(true);
+
+        // convert definitions
+        final ImmutableMap.Builder<String, RexNode> definitionNodes =
+            ImmutableMap.builder();
+        for (SqlNode def : matchRecognize.getPatternDefList()) {
+            List<SqlNode> operands = ((SqlCall) def).getOperandList();
+            String alias = ((SqlIdentifier) operands.get(1)).getSimple();
+            RexNode rex = mrBlackBoard.convertExpression(operands.get(0));
+            definitionNodes.put(alias, rex);
+        }
+
+        mrBlackBoard.setPatternVarRef(false);
+
+        final RelFactories.MatchFactory factory =
+            RelFactories.DEFAULT_MATCH_FACTORY;
+        final RelNode rel =
+            factory.createMatchRecognize(input, patternNode,
+                matchRecognize.getStrictStart().booleanValue(),
+                matchRecognize.getStrictEnd().booleanValue(),
+                definitionNodes.build(),
+                rowType);
+        bb.setRoot(rel, false);
+    }
+
+    private void convertIdentifier(Blackboard bb, SqlIdentifier id,
+        SqlNodeList extendedColumns) {
+        final SqlValidatorNamespace fromNamespace =
+            validator.getNamespace(id).resolve();
+        if (fromNamespace.getNode() != null) {
+            convertFrom(bb, fromNamespace.getNode());
+            return;
+        }
+        final String datasetName =
+            datasetStack.isEmpty() ? null : datasetStack.peek();
+        final boolean[] usedDataset = {false};
+        RelOptTable table =
+            SqlValidatorUtil.getRelOptTable(fromNamespace, catalogReader,
+                datasetName, usedDataset);
+        if (extendedColumns != null && extendedColumns.size() > 0) {
+            assert table != null;
+            final SqlValidatorTable validatorTable =
+                table.unwrap(SqlValidatorTable.class);
+            final List<RelDataTypeField> extendedFields =
+                SqlValidatorUtil.getExtendedColumns(validator, validatorTable,
+                    extendedColumns);
+            table = table.extend(extendedFields);
+        }
+        final RelNode tableRel;
+        if (config.isConvertTableAccess()) {
+            tableRel = toRel(table);
+        } else {
+            tableRel = LogicalTableScan.create(cluster, table);
+        }
+        bb.setRoot(tableRel, true);
+        if (usedDataset[0]) {
+            bb.setDataset(datasetName);
         }
     }
 
     protected void convertCollectionTable(
-            Blackboard bb,
-            SqlCall call) {
+        Blackboard bb,
+        SqlCall call) {
         final SqlOperator operator = call.getOperator();
         if (operator == SqlStdOperatorTable.TABLESAMPLE) {
             final String sampleName = (String) SqlLiteral.value(call.operand(0));
@@ -2172,15 +2263,15 @@ public class SqlToRelConverter {
         // Expand table macro if possible. It's more efficient than
         // LogicalTableFunctionScan.
         final SqlCallBinding callBinding =
-                new SqlCallBinding(bb.scope.getValidator(), bb.scope, call);
+            new SqlCallBinding(bb.scope.getValidator(), bb.scope, call);
         if (operator instanceof SqlUserDefinedTableMacro) {
             final SqlUserDefinedTableMacro udf =
-                    (SqlUserDefinedTableMacro) operator;
+                (SqlUserDefinedTableMacro) operator;
             final TranslatableTable table =
-                    udf.getTable(typeFactory, callBinding.operands());
+                udf.getTable(typeFactory, callBinding.operands());
             final RelDataType rowType = table.getRowType(typeFactory);
             RelOptTable relOptTable = RelOptTableImpl.create(null, rowType, table,
-                    udf.getNameAsId().names);
+                udf.getNameAsId().names);
             RelNode converted = toRel(relOptTable);
             bb.setRoot(converted, true);
             return;
@@ -2197,23 +2288,23 @@ public class SqlToRelConverter {
         RexNode rexCall = bb.convertExpression(call);
         final List<RelNode> inputs = bb.retrieveCursors();
         Set<RelColumnMapping> columnMappings =
-                getColumnMappings(operator);
+            getColumnMappings(operator);
         LogicalTableFunctionScan callRel =
-                LogicalTableFunctionScan.create(
-                        cluster,
-                        inputs,
-                        rexCall,
-                        elementType,
-                        validator.getValidatedNodeType(call),
-                        columnMappings);
+            LogicalTableFunctionScan.create(
+                cluster,
+                inputs,
+                rexCall,
+                elementType,
+                validator.getValidatedNodeType(call),
+                columnMappings);
         bb.setRoot(callRel, true);
         afterTableFunction(bb, call, callRel);
     }
 
     protected void afterTableFunction(
-            SqlToRelConverter.Blackboard bb,
-            SqlCall call,
-            LogicalTableFunctionScan callRel) {
+        SqlToRelConverter.Blackboard bb,
+        SqlCall call,
+        LogicalTableFunctionScan callRel) {
     }
 
     private Set<RelColumnMapping> getColumnMappings(SqlOperator op) {
@@ -2223,7 +2314,7 @@ public class SqlToRelConverter {
         }
         if (rti instanceof TableFunctionReturnTypeInference) {
             TableFunctionReturnTypeInference tfrti =
-                    (TableFunctionReturnTypeInference) rti;
+                (TableFunctionReturnTypeInference) rti;
             return tfrti.getColumnMappings();
         } else {
             return null;
@@ -2231,35 +2322,35 @@ public class SqlToRelConverter {
     }
 
     protected RelNode createJoin(
-            Blackboard bb,
-            RelNode leftRel,
-            RelNode rightRel,
-            RexNode joinCond,
-            JoinRelType joinType) {
+        Blackboard bb,
+        RelNode leftRel,
+        RelNode rightRel,
+        RexNode joinCond,
+        JoinRelType joinType) {
         assert joinCond != null;
 
         final CorrelationUse p = getCorrelationUse(bb, rightRel);
         if (p != null) {
             LogicalCorrelate corr = LogicalCorrelate.create(leftRel, p.r,
-                    p.id, p.requiredColumns, SemiJoinType.of(joinType));
+                p.id, p.requiredColumns, SemiJoinType.of(joinType));
             if (!joinCond.isAlwaysTrue()) {
                 final RelFactories.FilterFactory factory =
-                        RelFactories.DEFAULT_FILTER_FACTORY;
+                    RelFactories.DEFAULT_FILTER_FACTORY;
                 return factory.createFilter(corr, joinCond);
             }
             return corr;
         }
 
         final Join originalJoin =
-                (Join) RelFactories.DEFAULT_JOIN_FACTORY.createJoin(leftRel, rightRel,
-                        joinCond, ImmutableSet.<CorrelationId>of(), joinType, false);
+            (Join) RelFactories.DEFAULT_JOIN_FACTORY.createJoin(leftRel, rightRel,
+                joinCond, ImmutableSet.<CorrelationId>of(), joinType, false);
 
         return RelOptUtil.pushDownJoinConditions(originalJoin);
     }
 
     private CorrelationUse getCorrelationUse(Blackboard bb, final RelNode r0) {
         final Set<CorrelationId> correlatedVariables =
-                RelOptUtil.getVariablesUsed(r0);
+            RelOptUtil.getVariablesUsed(r0);
         if (correlatedVariables.isEmpty()) {
             return null;
         }
@@ -2274,18 +2365,21 @@ public class SqlToRelConverter {
 
         for (CorrelationId correlName : correlatedVariables) {
             DeferredLookup lookup =
-                    mapCorrelToDeferred.get(correlName);
+                mapCorrelToDeferred.get(correlName);
             RexFieldAccess fieldAccess = lookup.getFieldAccess(correlName);
             String originalRelName = lookup.getOriginalRelName();
             String originalFieldName = fieldAccess.getField().getName();
 
-            SqlValidatorScope.ResolvedImpl resolved =
-                    new SqlValidatorScope.ResolvedImpl();
-            lookup.bb.scope.resolve(ImmutableList.of(originalRelName), false,
-                    resolved);
+            final SqlNameMatcher nameMatcher =
+                lookup.bb.scope.getValidator().getCatalogReader().nameMatcher();
+            final SqlValidatorScope.ResolvedImpl resolved =
+                new SqlValidatorScope.ResolvedImpl();
+            lookup.bb.scope.resolve(ImmutableList.of(originalRelName),
+                nameMatcher, false, resolved);
             assert resolved.count() == 1;
             final SqlValidatorScope.Resolve resolve = resolved.only();
             final SqlValidatorNamespace foundNs = resolve.namespace;
+       

<TRUNCATED>