You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by vl...@apache.org on 2018/08/02 09:12:55 UTC

[1/3] calcite git commit: [CALCITE-2435] tests: refactor SqlTestFactory

Repository: calcite
Updated Branches:
  refs/heads/master c11376590 -> 96b28f7ba


http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/catalog/CompoundNameColumnResolver.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/catalog/CompoundNameColumnResolver.java b/core/src/test/java/org/apache/calcite/test/catalog/CompoundNameColumnResolver.java
new file mode 100644
index 0000000..6b0fa97
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/catalog/CompoundNameColumnResolver.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.test.catalog;
+
+import org.apache.calcite.linq4j.Ord;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
+import org.apache.calcite.rel.type.StructKind;
+import org.apache.calcite.util.Pair;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** ColumnResolver implementation that resolves CompoundNameColumn by simulating
+ *  Phoenix behaviors. */
+final class CompoundNameColumnResolver implements MockCatalogReader.ColumnResolver {
+  private final Map<String, Integer> nameMap = new HashMap<>();
+  private final Map<String, Map<String, Integer>> groupMap = new HashMap<>();
+  private final String defaultColumnGroup;
+
+  CompoundNameColumnResolver(
+      List<CompoundNameColumn> columns, String defaultColumnGroup) {
+    this.defaultColumnGroup = defaultColumnGroup;
+    for (Ord<CompoundNameColumn> column : Ord.zip(columns)) {
+      nameMap.put(column.e.getName(), column.i);
+      Map<String, Integer> subMap =
+          groupMap.computeIfAbsent(column.e.first, k -> new HashMap<>());
+      subMap.put(column.e.second, column.i);
+    }
+  }
+
+  @Override public List<Pair<RelDataTypeField, List<String>>> resolveColumn(
+      RelDataType rowType, RelDataTypeFactory typeFactory, List<String> names) {
+    List<Pair<RelDataTypeField, List<String>>> ret = new ArrayList<>();
+    if (names.size() >= 2) {
+      Map<String, Integer> subMap = groupMap.get(names.get(0));
+      if (subMap != null) {
+        Integer index = subMap.get(names.get(1));
+        if (index != null) {
+          ret.add(
+              new Pair<RelDataTypeField, List<String>>(
+                  rowType.getFieldList().get(index),
+                  names.subList(2, names.size())));
+        }
+      }
+    }
+
+    final String columnName = names.get(0);
+    final List<String> remainder = names.subList(1, names.size());
+    Integer index = nameMap.get(columnName);
+    if (index != null) {
+      ret.add(
+          new Pair<RelDataTypeField, List<String>>(
+              rowType.getFieldList().get(index), remainder));
+      return ret;
+    }
+
+    final List<String> priorityGroups = Arrays.asList("", defaultColumnGroup);
+    for (String group : priorityGroups) {
+      Map<String, Integer> subMap = groupMap.get(group);
+      if (subMap != null) {
+        index = subMap.get(columnName);
+        if (index != null) {
+          ret.add(
+              new Pair<RelDataTypeField, List<String>>(
+                  rowType.getFieldList().get(index), remainder));
+          return ret;
+        }
+      }
+    }
+    for (Map.Entry<String, Map<String, Integer>> entry : groupMap.entrySet()) {
+      if (priorityGroups.contains(entry.getKey())) {
+        continue;
+      }
+      index = entry.getValue().get(columnName);
+      if (index != null) {
+        ret.add(
+            new Pair<RelDataTypeField, List<String>>(
+                rowType.getFieldList().get(index), remainder));
+      }
+    }
+
+    if (ret.isEmpty() && names.size() == 1) {
+      Map<String, Integer> subMap = groupMap.get(columnName);
+      if (subMap != null) {
+        List<Map.Entry<String, Integer>> entries =
+            new ArrayList<>(subMap.entrySet());
+        entries.sort((o1, o2) -> o1.getValue() - o2.getValue());
+        ret.add(
+            new Pair<RelDataTypeField, List<String>>(
+                new RelDataTypeFieldImpl(
+                    columnName, -1,
+                    createStructType(
+                        rowType,
+                        typeFactory,
+                        entries)),
+                remainder));
+      }
+    }
+
+    return ret;
+  }
+
+  private static RelDataType createStructType(
+      final RelDataType rowType,
+      RelDataTypeFactory typeFactory,
+      final List<Map.Entry<String, Integer>> entries) {
+    return typeFactory.createStructType(
+        StructKind.PEEK_FIELDS,
+        new AbstractList<RelDataType>() {
+          @Override public RelDataType get(int index) {
+            final int i = entries.get(index).getValue();
+            return rowType.getFieldList().get(i).getType();
+          }
+          @Override public int size() {
+            return entries.size();
+          }
+        },
+        new AbstractList<String>() {
+          @Override public String get(int index) {
+            return entries.get(index).getKey();
+          }
+          @Override public int size() {
+            return entries.size();
+          }
+        });
+  }
+}
+
+// End CompoundNameColumnResolver.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/catalog/CountingFactory.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/catalog/CountingFactory.java b/core/src/test/java/org/apache/calcite/test/catalog/CountingFactory.java
new file mode 100644
index 0000000..badbb7d
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/catalog/CountingFactory.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.test.catalog;
+
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.ColumnStrategy;
+import org.apache.calcite.sql.SqlFunction;
+import org.apache.calcite.sql2rel.InitializerContext;
+import org.apache.calcite.sql2rel.InitializerExpressionFactory;
+import org.apache.calcite.sql2rel.NullInitializerExpressionFactory;
+
+import com.google.common.collect.ImmutableList;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/** To check whether
+ * {@link InitializerExpressionFactory#newColumnDefaultValue} is called.
+ *
+ * <p>If a column is in {@code defaultColumns}, returns 1 as the default
+ * value. */
+public class CountingFactory extends NullInitializerExpressionFactory {
+  public static final ThreadLocal<AtomicInteger> THREAD_CALL_COUNT =
+      ThreadLocal.withInitial(AtomicInteger::new);
+
+  private final List<String> defaultColumns;
+
+  CountingFactory(List<String> defaultColumns) {
+    this.defaultColumns = ImmutableList.copyOf(defaultColumns);
+  }
+
+  @Override public ColumnStrategy generationStrategy(RelOptTable table,
+      int iColumn) {
+    final RelDataTypeField field =
+        table.getRowType().getFieldList().get(iColumn);
+    if (defaultColumns.contains(field.getName())) {
+      return ColumnStrategy.DEFAULT;
+    }
+    return super.generationStrategy(table, iColumn);
+  }
+
+  @Override public RexNode newColumnDefaultValue(RelOptTable table,
+      int iColumn, InitializerContext context) {
+    THREAD_CALL_COUNT.get().incrementAndGet();
+    final RelDataTypeField field =
+        table.getRowType().getFieldList().get(iColumn);
+    if (defaultColumns.contains(field.getName())) {
+      final RexBuilder rexBuilder = context.getRexBuilder();
+      return rexBuilder.makeExactLiteral(BigDecimal.ONE);
+    }
+    return super.newColumnDefaultValue(table, iColumn, context);
+  }
+
+  @Override public RexNode newAttributeInitializer(RelDataType type,
+      SqlFunction constructor, int iAttribute,
+      List<RexNode> constructorArgs, InitializerContext context) {
+    THREAD_CALL_COUNT.get().incrementAndGet();
+    return super.newAttributeInitializer(type, constructor, iAttribute,
+       constructorArgs, context);
+  }
+}
+
+// End CountingFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/catalog/EmpInitializerExpressionFactory.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/catalog/EmpInitializerExpressionFactory.java b/core/src/test/java/org/apache/calcite/test/catalog/EmpInitializerExpressionFactory.java
new file mode 100644
index 0000000..4d26cba
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/catalog/EmpInitializerExpressionFactory.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.test.catalog;
+
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.ColumnStrategy;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql2rel.InitializerContext;
+import org.apache.calcite.sql2rel.NullInitializerExpressionFactory;
+
+import java.math.BigDecimal;
+
+/** Default values for the "EMPDEFAULTS" table. */
+class EmpInitializerExpressionFactory
+    extends NullInitializerExpressionFactory {
+  @Override public ColumnStrategy generationStrategy(RelOptTable table,
+      int iColumn) {
+    switch (iColumn) {
+    case 0:
+    case 1:
+    case 5:
+      return ColumnStrategy.DEFAULT;
+    default:
+      return super.generationStrategy(table, iColumn);
+    }
+  }
+
+  @Override public RexNode newColumnDefaultValue(RelOptTable table,
+      int iColumn, InitializerContext context) {
+    final RexBuilder rexBuilder = context.getRexBuilder();
+    final RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
+    switch (iColumn) {
+    case 0:
+      return rexBuilder.makeExactLiteral(new BigDecimal(123),
+          typeFactory.createSqlType(SqlTypeName.INTEGER));
+    case 1:
+      return rexBuilder.makeLiteral("Bob");
+    case 5:
+      return rexBuilder.makeExactLiteral(new BigDecimal(555),
+          typeFactory.createSqlType(SqlTypeName.INTEGER));
+    default:
+      return rexBuilder.constantNull();
+    }
+  }
+}
+
+// End EmpInitializerExpressionFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/catalog/Fixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/catalog/Fixture.java b/core/src/test/java/org/apache/calcite/test/catalog/Fixture.java
new file mode 100644
index 0000000..90e7e2d
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/catalog/Fixture.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.test.catalog;
+
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeComparability;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
+import org.apache.calcite.rel.type.StructKind;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.type.ObjectSqlType;
+import org.apache.calcite.sql.type.SqlTypeName;
+
+import java.util.Arrays;
+
+/** Types used during initialization. */
+final class Fixture {
+  final RelDataType intType;
+  final RelDataType intTypeNull;
+  final RelDataType varchar10Type;
+  final RelDataType varchar10TypeNull;
+  final RelDataType varchar20Type;
+  final RelDataType varchar20TypeNull;
+  final RelDataType timestampType;
+  final RelDataType timestampTypeNull;
+  final RelDataType dateType;
+  final RelDataType booleanType;
+  final RelDataType booleanTypeNull;
+  final RelDataType rectilinearCoordType;
+  final RelDataType rectilinearPeekCoordType;
+  final RelDataType rectilinearPeekNoExpandCoordType;
+  final RelDataType abRecordType;
+  final RelDataType skillRecordType;
+  final RelDataType empRecordType;
+  final RelDataType empListType;
+  final ObjectSqlType addressType;
+
+  Fixture(RelDataTypeFactory typeFactory) {
+    intType = typeFactory.createSqlType(SqlTypeName.INTEGER);
+    intTypeNull = typeFactory.createTypeWithNullability(intType, true);
+    varchar10Type = typeFactory.createSqlType(SqlTypeName.VARCHAR, 10);
+    varchar10TypeNull = typeFactory.createTypeWithNullability(varchar10Type, true);
+    varchar20Type = typeFactory.createSqlType(SqlTypeName.VARCHAR, 20);
+    varchar20TypeNull = typeFactory.createTypeWithNullability(varchar20Type, true);
+    timestampType = typeFactory.createSqlType(SqlTypeName.TIMESTAMP);
+    timestampTypeNull =
+        typeFactory.createTypeWithNullability(timestampType, true);
+    dateType =
+        typeFactory.createSqlType(SqlTypeName.DATE);
+    booleanType =
+        typeFactory.createSqlType(SqlTypeName.BOOLEAN);
+    booleanTypeNull =
+        typeFactory.createTypeWithNullability(booleanType, true);
+    rectilinearCoordType =
+        typeFactory.builder()
+            .add("X", intType)
+            .add("Y", intType)
+            .build();
+    rectilinearPeekCoordType =
+        typeFactory.builder()
+            .add("X", intType)
+            .add("Y", intType)
+            .kind(StructKind.PEEK_FIELDS)
+            .build();
+    rectilinearPeekNoExpandCoordType =
+        typeFactory.builder()
+            .add("M", intType)
+            .add("SUB",
+                typeFactory.builder()
+                    .add("A", intType)
+                    .add("B", intType)
+                    .kind(StructKind.PEEK_FIELDS_NO_EXPAND)
+                    .build())
+            .kind(StructKind.PEEK_FIELDS_NO_EXPAND)
+            .build();
+    abRecordType =
+        typeFactory.builder()
+            .add("A", varchar10Type)
+            .add("B", varchar10Type)
+            .build();
+    skillRecordType =
+        typeFactory.builder()
+            .add("TYPE", varchar10Type)
+            .add("DESC", varchar20Type)
+            .add("OTHERS", abRecordType)
+            .build();
+    empRecordType =
+        typeFactory.builder()
+            .add("EMPNO", intType)
+            .add("ENAME", varchar10Type)
+            .add("DETAIL",
+                typeFactory.builder().add("SKILLS",
+                    typeFactory.createArrayType(skillRecordType, -1)).build())
+            .build();
+    empListType =
+        typeFactory.createArrayType(empRecordType, -1);
+    addressType =
+        new ObjectSqlType(SqlTypeName.STRUCTURED,
+            new SqlIdentifier("ADDRESS", SqlParserPos.ZERO),
+            false,
+            Arrays.asList(
+                new RelDataTypeFieldImpl("STREET", 0, varchar20Type),
+                new RelDataTypeFieldImpl("CITY", 1, varchar20Type),
+                new RelDataTypeFieldImpl("ZIP", 2, intType),
+                new RelDataTypeFieldImpl("STATE", 3, varchar20Type)),
+            RelDataTypeComparability.NONE);
+  }
+}
+
+// End Fixture.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReader.java b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReader.java
new file mode 100644
index 0000000..a31833d
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReader.java
@@ -0,0 +1,1006 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.test.catalog;
+
+import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.config.CalciteConnectionConfig;
+import org.apache.calcite.jdbc.CalcitePrepare;
+import org.apache.calcite.jdbc.CalciteSchema;
+import org.apache.calcite.linq4j.QueryProvider;
+import org.apache.calcite.linq4j.Queryable;
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.plan.RelOptSchema;
+import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.prepare.CalciteCatalogReader;
+import org.apache.calcite.prepare.Prepare;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollations;
+import org.apache.calcite.rel.RelDistribution;
+import org.apache.calcite.rel.RelDistributions;
+import org.apache.calcite.rel.RelFieldCollation;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.RelReferentialConstraint;
+import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.logical.LogicalTableScan;
+import org.apache.calcite.rel.type.DynamicRecordTypeImpl;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeComparability;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeFamily;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rel.type.RelDataTypeImpl;
+import org.apache.calcite.rel.type.RelDataTypePrecedenceList;
+import org.apache.calcite.rel.type.RelProtoDataType;
+import org.apache.calcite.rel.type.RelRecordType;
+import org.apache.calcite.rel.type.StructKind;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.schema.CustomColumnResolvingTable;
+import org.apache.calcite.schema.ExtensibleTable;
+import org.apache.calcite.schema.Path;
+import org.apache.calcite.schema.Schema;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.Schemas;
+import org.apache.calcite.schema.Statistic;
+import org.apache.calcite.schema.StreamableTable;
+import org.apache.calcite.schema.Table;
+import org.apache.calcite.schema.Wrapper;
+import org.apache.calcite.schema.impl.AbstractSchema;
+import org.apache.calcite.schema.impl.ModifiableViewTable;
+import org.apache.calcite.schema.impl.ViewTableMacro;
+import org.apache.calcite.sql.SqlAccessType;
+import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlCollation;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlIntervalQualifier;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql.validate.SqlModality;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
+import org.apache.calcite.sql.validate.SqlNameMatcher;
+import org.apache.calcite.sql.validate.SqlNameMatchers;
+import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
+import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.sql2rel.InitializerExpressionFactory;
+import org.apache.calcite.sql2rel.NullInitializerExpressionFactory;
+import org.apache.calcite.test.JdbcTest;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.Pair;
+import org.apache.calcite.util.Util;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Mock implementation of {@link SqlValidatorCatalogReader} which returns tables
+ * "EMP", "DEPT", "BONUS", "SALGRADE" (same as Oracle's SCOTT schema).
+ * Also two streams "ORDERS", "SHIPMENTS";
+ * and a view "EMP_20".
+ */
+public abstract class MockCatalogReader extends CalciteCatalogReader {
+  //~ Static fields/initializers ---------------------------------------------
+
+  static final String DEFAULT_CATALOG = "CATALOG";
+  static final String DEFAULT_SCHEMA = "SALES";
+  static final List<String> PREFIX = ImmutableList.of(DEFAULT_SCHEMA);
+
+  //~ Instance fields --------------------------------------------------------
+
+  //~ Constructors -----------------------------------------------------------
+
+  /**
+   * Creates a MockCatalogReader.
+   *
+   * <p>Caller must then call {@link #init} to populate with data.</p>
+   *
+   * @param typeFactory Type factory
+   */
+  public MockCatalogReader(RelDataTypeFactory typeFactory,
+      boolean caseSensitive) {
+    super(CalciteSchema.createRootSchema(false, true, DEFAULT_CATALOG),
+        SqlNameMatchers.withCaseSensitive(caseSensitive),
+        ImmutableList.of(PREFIX, ImmutableList.of()),
+        typeFactory, null);
+  }
+
+  @Override public boolean isCaseSensitive() {
+    return nameMatcher.isCaseSensitive();
+  }
+
+  public SqlNameMatcher nameMatcher() {
+    return nameMatcher;
+  }
+
+  /**
+   * Initializes this catalog reader.
+   */
+  public abstract MockCatalogReader init();
+
+  protected void registerTablesWithRollUp(MockSchema schema, Fixture f) {
+    // Register "EMP_R" table. Contains a rolled up column.
+    final MockTable empRolledTable =
+            MockTable.create(this, schema, "EMP_R", false, 14);
+    empRolledTable.addColumn("EMPNO", f.intType, true);
+    empRolledTable.addColumn("DEPTNO", f.intType);
+    empRolledTable.addColumn("SLACKER", f.booleanType);
+    empRolledTable.addColumn("SLACKINGMIN", f.intType);
+    empRolledTable.registerRolledUpColumn("SLACKINGMIN");
+    registerTable(empRolledTable);
+
+    // Register the "DEPT_R" table. Doesn't contain a rolled up column,
+    // but is useful for testing join
+    MockTable deptSlackingTable = MockTable.create(this, schema, "DEPT_R", false, 4);
+    deptSlackingTable.addColumn("DEPTNO", f.intType, true);
+    deptSlackingTable.addColumn("SLACKINGMIN", f.intType);
+    registerTable(deptSlackingTable);
+
+    // Register nested schema NEST that contains table with a rolled up column.
+    MockSchema nestedSchema = new MockSchema("NEST");
+    registerNestedSchema(schema, nestedSchema);
+
+    // Register "EMP_R" table which contains a rolled up column in NEST schema.
+    ImmutableList<String> tablePath =
+        ImmutableList.of(schema.getCatalogName(), schema.name, nestedSchema.name, "EMP_R");
+    final MockTable nestedEmpRolledTable = MockTable.create(this, tablePath, false, 14);
+    nestedEmpRolledTable.addColumn("EMPNO", f.intType, true);
+    nestedEmpRolledTable.addColumn("DEPTNO", f.intType);
+    nestedEmpRolledTable.addColumn("SLACKER", f.booleanType);
+    nestedEmpRolledTable.addColumn("SLACKINGMIN", f.intType);
+    nestedEmpRolledTable.registerRolledUpColumn("SLACKINGMIN");
+    registerTable(nestedEmpRolledTable);
+  }
+
+  //~ Methods ----------------------------------------------------------------
+
+  protected void registerType(final List<String> names, final RelProtoDataType relProtoDataType) {
+    assert names.get(0).equals(DEFAULT_CATALOG);
+    final List<String> schemaPath = Util.skipLast(names);
+    final CalciteSchema schema = SqlValidatorUtil.getSchema(rootSchema,
+        schemaPath, SqlNameMatchers.withCaseSensitive(true));
+    schema.add(Util.last(names), relProtoDataType);
+  }
+
+  protected void registerTable(final MockTable table) {
+    table.onRegister(typeFactory);
+    final WrapperTable wrapperTable = new WrapperTable(table);
+    if (table.stream) {
+      registerTable(table.names,
+          new StreamableWrapperTable(table) {
+            public Table stream() {
+              return wrapperTable;
+            }
+          });
+    } else {
+      registerTable(table.names, wrapperTable);
+    }
+  }
+
+  private void registerTable(final List<String> names, final Table table) {
+    assert names.get(0).equals(DEFAULT_CATALOG);
+    final List<String> schemaPath = Util.skipLast(names);
+    final String tableName = Util.last(names);
+    final CalciteSchema schema = SqlValidatorUtil.getSchema(rootSchema,
+        schemaPath, SqlNameMatchers.withCaseSensitive(true));
+    schema.add(tableName, table);
+  }
+
+  protected void registerSchema(MockSchema schema) {
+    rootSchema.add(schema.name, new AbstractSchema());
+  }
+
+  private void registerNestedSchema(MockSchema parentSchema, MockSchema schema) {
+    rootSchema.getSubSchema(parentSchema.getName(), true)
+        .add(schema.name, new AbstractSchema());
+  }
+
+  private static List<RelCollation> deduceMonotonicity(
+      Prepare.PreparingTable table) {
+    final List<RelCollation> collationList = new ArrayList<>();
+
+    // Deduce which fields the table is sorted on.
+    int i = -1;
+    for (RelDataTypeField field : table.getRowType().getFieldList()) {
+      ++i;
+      final SqlMonotonicity monotonicity =
+          table.getMonotonicity(field.getName());
+      if (monotonicity != SqlMonotonicity.NOT_MONOTONIC) {
+        final RelFieldCollation.Direction direction =
+            monotonicity.isDecreasing()
+                ? RelFieldCollation.Direction.DESCENDING
+                : RelFieldCollation.Direction.ASCENDING;
+        collationList.add(
+            RelCollations.of(
+                new RelFieldCollation(i, direction)));
+      }
+    }
+    return collationList;
+  }
+
+  //~ Inner Classes ----------------------------------------------------------
+
+  /** Column resolver*/
+  public interface ColumnResolver {
+    List<Pair<RelDataTypeField, List<String>>> resolveColumn(
+        RelDataType rowType, RelDataTypeFactory typeFactory, List<String> names);
+  }
+
+  /** Mock schema. */
+  public static class MockSchema {
+    private final List<String> tableNames = new ArrayList<>();
+    private String name;
+
+    public MockSchema(String name) {
+      this.name = name;
+    }
+
+    public void addTable(String name) {
+      tableNames.add(name);
+    }
+
+    public String getCatalogName() {
+      return DEFAULT_CATALOG;
+    }
+
+    public String getName() {
+      return name;
+    }
+  }
+
+  /**
+   * Mock implementation of
+   * {@link org.apache.calcite.prepare.Prepare.PreparingTable}.
+   */
+  public static class MockTable extends Prepare.AbstractPreparingTable {
+    protected final MockCatalogReader catalogReader;
+    protected final boolean stream;
+    protected final double rowCount;
+    protected final List<Map.Entry<String, RelDataType>> columnList =
+        new ArrayList<>();
+    protected final List<Integer> keyList = new ArrayList<>();
+    protected final List<RelReferentialConstraint> referentialConstraints =
+        new ArrayList<>();
+    protected RelDataType rowType;
+    protected List<RelCollation> collationList;
+    protected final List<String> names;
+    protected final Set<String> monotonicColumnSet = new HashSet<>();
+    protected StructKind kind = StructKind.FULLY_QUALIFIED;
+    protected final ColumnResolver resolver;
+    protected final InitializerExpressionFactory initializerFactory;
+    protected final Set<String> rolledUpColumns = new HashSet<>();
+
+    public MockTable(MockCatalogReader catalogReader, String catalogName,
+        String schemaName, String name, boolean stream, double rowCount,
+        ColumnResolver resolver,
+        InitializerExpressionFactory initializerFactory) {
+      this(catalogReader, ImmutableList.of(catalogName, schemaName, name), stream, rowCount,
+          resolver, initializerFactory);
+    }
+
+    public void registerRolledUpColumn(String columnName) {
+      rolledUpColumns.add(columnName);
+    }
+
+    private MockTable(MockCatalogReader catalogReader, List<String> names, boolean stream,
+        double rowCount, ColumnResolver resolver, InitializerExpressionFactory initializerFactory) {
+      this.catalogReader = catalogReader;
+      this.stream = stream;
+      this.rowCount = rowCount;
+      this.names = names;
+      this.resolver = resolver;
+      this.initializerFactory = initializerFactory;
+    }
+
+    /**
+     * Copy constructor.
+     */
+    protected MockTable(MockCatalogReader catalogReader, boolean stream, double rowCount,
+        List<Map.Entry<String, RelDataType>> columnList, List<Integer> keyList,
+        RelDataType rowType, List<RelCollation> collationList, List<String> names,
+        Set<String> monotonicColumnSet, StructKind kind, ColumnResolver resolver,
+        InitializerExpressionFactory initializerFactory) {
+      this.catalogReader = catalogReader;
+      this.stream = stream;
+      this.rowCount = rowCount;
+      this.rowType = rowType;
+      this.collationList = collationList;
+      this.names = names;
+      this.kind = kind;
+      this.resolver = resolver;
+      this.initializerFactory = initializerFactory;
+      for (String name : monotonicColumnSet) {
+        addMonotonic(name);
+      }
+    }
+
+    /** Implementation of AbstractModifiableTable. */
+    private class ModifiableTable extends JdbcTest.AbstractModifiableTable
+        implements ExtensibleTable, Wrapper {
+      protected ModifiableTable(String tableName) {
+        super(tableName);
+      }
+
+      @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+        return typeFactory.createStructType(MockTable.this.getRowType().getFieldList());
+      }
+
+      @Override public Collection getModifiableCollection() {
+        return null;
+      }
+
+      @Override public <E> Queryable<E>
+      asQueryable(QueryProvider queryProvider, SchemaPlus schema,
+          String tableName) {
+        return null;
+      }
+
+      @Override public Type getElementType() {
+        return null;
+      }
+
+      @Override public Expression getExpression(SchemaPlus schema,
+          String tableName, Class clazz) {
+        return null;
+      }
+
+      @Override public <C> C unwrap(Class<C> aClass) {
+        if (aClass.isInstance(initializerFactory)) {
+          return aClass.cast(initializerFactory);
+        } else if (aClass.isInstance(MockTable.this)) {
+          return aClass.cast(MockTable.this);
+        }
+        return super.unwrap(aClass);
+      }
+
+      @Override public Table extend(final List<RelDataTypeField> fields) {
+        return new ModifiableTable(Util.last(names)) {
+          @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+            ImmutableList<RelDataTypeField> allFields = ImmutableList.copyOf(
+                Iterables.concat(
+                    ModifiableTable.this.getRowType(typeFactory).getFieldList(),
+                    fields));
+            return typeFactory.createStructType(allFields);
+          }
+        };
+      }
+
+      @Override public int getExtendedColumnOffset() {
+        return rowType.getFieldCount();
+      }
+    }
+
+    @Override protected RelOptTable extend(final Table extendedTable) {
+      return new MockTable(catalogReader, names, stream, rowCount, resolver, initializerFactory) {
+        @Override public RelDataType getRowType() {
+          return extendedTable.getRowType(catalogReader.typeFactory);
+        }
+      };
+    }
+
+    public static MockTable create(MockCatalogReader catalogReader,
+        MockSchema schema, String name, boolean stream, double rowCount) {
+      return create(catalogReader, schema, name, stream, rowCount, null);
+    }
+
+    public static MockTable create(MockCatalogReader catalogReader,
+        List<String> names, boolean stream, double rowCount) {
+      return new MockTable(catalogReader, names, stream, rowCount, null,
+          NullInitializerExpressionFactory.INSTANCE);
+    }
+
+    public static MockTable create(MockCatalogReader catalogReader,
+        MockSchema schema, String name, boolean stream, double rowCount,
+        ColumnResolver resolver) {
+      return create(catalogReader, schema, name, stream, rowCount, resolver,
+          NullInitializerExpressionFactory.INSTANCE);
+    }
+
+    public static MockTable create(MockCatalogReader catalogReader,
+        MockSchema schema, String name, boolean stream, double rowCount,
+        ColumnResolver resolver,
+        InitializerExpressionFactory initializerExpressionFactory) {
+      MockTable table =
+          new MockTable(catalogReader, schema.getCatalogName(), schema.name,
+              name, stream, rowCount, resolver, initializerExpressionFactory);
+      schema.addTable(name);
+      return table;
+    }
+
+    public <T> T unwrap(Class<T> clazz) {
+      if (clazz.isInstance(this)) {
+        return clazz.cast(this);
+      }
+      if (clazz.isInstance(initializerFactory)) {
+        return clazz.cast(initializerFactory);
+      }
+      if (clazz.isAssignableFrom(Table.class)) {
+        final Table table = resolver == null
+            ? new ModifiableTable(Util.last(names))
+                : new ModifiableTableWithCustomColumnResolving(Util.last(names));
+        return clazz.cast(table);
+      }
+      return null;
+    }
+
+    public double getRowCount() {
+      return rowCount;
+    }
+
+    public RelOptSchema getRelOptSchema() {
+      return catalogReader;
+    }
+
+    public RelNode toRel(ToRelContext context) {
+      return LogicalTableScan.create(context.getCluster(), this);
+    }
+
+    public List<RelCollation> getCollationList() {
+      return collationList;
+    }
+
+    public RelDistribution getDistribution() {
+      return RelDistributions.BROADCAST_DISTRIBUTED;
+    }
+
+    public boolean isKey(ImmutableBitSet columns) {
+      return !keyList.isEmpty()
+          && columns.contains(ImmutableBitSet.of(keyList));
+    }
+
+    public List<RelReferentialConstraint> getReferentialConstraints() {
+      return referentialConstraints;
+    }
+
+    public RelDataType getRowType() {
+      return rowType;
+    }
+
+    public boolean supportsModality(SqlModality modality) {
+      return modality == (stream ? SqlModality.STREAM : SqlModality.RELATION);
+    }
+
+    public void onRegister(RelDataTypeFactory typeFactory) {
+      rowType = typeFactory.createStructType(kind, Pair.right(columnList),
+          Pair.left(columnList));
+      collationList = deduceMonotonicity(this);
+    }
+
+    public List<String> getQualifiedName() {
+      return names;
+    }
+
+    public SqlMonotonicity getMonotonicity(String columnName) {
+      return monotonicColumnSet.contains(columnName)
+          ? SqlMonotonicity.INCREASING
+          : SqlMonotonicity.NOT_MONOTONIC;
+    }
+
+    public SqlAccessType getAllowedAccess() {
+      return SqlAccessType.ALL;
+    }
+
+    public Expression getExpression(Class clazz) {
+      throw new UnsupportedOperationException();
+    }
+
+    public void addColumn(String name, RelDataType type) {
+      addColumn(name, type, false);
+    }
+
+    public void addColumn(String name, RelDataType type, boolean isKey) {
+      if (isKey) {
+        keyList.add(columnList.size());
+      }
+      columnList.add(Pair.of(name, type));
+    }
+
+    public void addMonotonic(String name) {
+      monotonicColumnSet.add(name);
+      assert Pair.left(columnList).contains(name);
+    }
+
+    public void setKind(StructKind kind) {
+      this.kind = kind;
+    }
+
+    public StructKind getKind() {
+      return kind;
+    }
+
+    /**
+     * Subclass of {@link ModifiableTable} that also implements
+     * {@link CustomColumnResolvingTable}.
+     */
+    private class ModifiableTableWithCustomColumnResolving
+        extends ModifiableTable implements CustomColumnResolvingTable, Wrapper {
+
+      ModifiableTableWithCustomColumnResolving(String tableName) {
+        super(tableName);
+      }
+
+      @Override public List<Pair<RelDataTypeField, List<String>>> resolveColumn(
+          RelDataType rowType, RelDataTypeFactory typeFactory,
+          List<String> names) {
+        return resolver.resolveColumn(rowType, typeFactory, names);
+      }
+    }
+  }
+
+  /**
+   * Alternative to MockViewTable that exercises code paths in ModifiableViewTable
+   * and ModifiableViewTableInitializerExpressionFactory.
+   */
+  public static class MockModifiableViewRelOptTable extends MockTable {
+    private final MockModifiableViewTable modifiableViewTable;
+
+    private MockModifiableViewRelOptTable(MockModifiableViewTable modifiableViewTable,
+        MockCatalogReader catalogReader, String catalogName, String schemaName, String name,
+        boolean stream, double rowCount, ColumnResolver resolver,
+        InitializerExpressionFactory initializerExpressionFactory) {
+      super(catalogReader, ImmutableList.of(catalogName, schemaName, name), stream, rowCount,
+          resolver, initializerExpressionFactory);
+      this.modifiableViewTable = modifiableViewTable;
+    }
+
+    /**
+     * Copy constructor.
+     */
+    private MockModifiableViewRelOptTable(MockModifiableViewTable modifiableViewTable,
+        MockCatalogReader catalogReader, boolean stream, double rowCount,
+        List<Map.Entry<String, RelDataType>> columnList, List<Integer> keyList,
+        RelDataType rowType, List<RelCollation> collationList, List<String> names,
+        Set<String> monotonicColumnSet, StructKind kind, ColumnResolver resolver,
+        InitializerExpressionFactory initializerFactory) {
+      super(catalogReader, stream, rowCount, columnList, keyList, rowType, collationList, names,
+          monotonicColumnSet, kind, resolver, initializerFactory);
+      this.modifiableViewTable = modifiableViewTable;
+    }
+
+    public static MockModifiableViewRelOptTable create(MockModifiableViewTable modifiableViewTable,
+        MockCatalogReader catalogReader, String catalogName, String schemaName, String name,
+        boolean stream, double rowCount, ColumnResolver resolver) {
+      final Table underlying = modifiableViewTable.unwrap(Table.class);
+      final InitializerExpressionFactory initializerExpressionFactory =
+          underlying != null && underlying instanceof Wrapper
+              ? ((Wrapper) underlying).unwrap(InitializerExpressionFactory.class)
+              : NullInitializerExpressionFactory.INSTANCE;
+      return new MockModifiableViewRelOptTable(modifiableViewTable,
+          catalogReader, catalogName, schemaName, name, stream, rowCount,
+          resolver, Util.first(initializerExpressionFactory,
+          NullInitializerExpressionFactory.INSTANCE));
+    }
+
+    public static MockViewTableMacro viewMacro(CalciteSchema schema, String viewSql,
+        List<String> schemaPath, List<String> viewPath, Boolean modifiable) {
+      return new MockViewTableMacro(schema, viewSql, schemaPath, viewPath, modifiable);
+    }
+
+    @Override public RelDataType getRowType() {
+      return modifiableViewTable.getRowType(catalogReader.typeFactory);
+    }
+
+    @Override protected RelOptTable extend(Table extendedTable) {
+      return new MockModifiableViewRelOptTable((MockModifiableViewTable) extendedTable,
+          catalogReader, stream, rowCount, columnList, keyList, rowType, collationList, names,
+          monotonicColumnSet, kind, resolver, initializerFactory);
+    }
+
+    @Override public <T> T unwrap(Class<T> clazz) {
+      if (clazz.isInstance(modifiableViewTable)) {
+        return clazz.cast(modifiableViewTable);
+      }
+      return super.unwrap(clazz);
+    }
+
+    /**
+     * A TableMacro that creates mock ModifiableViewTable.
+     */
+    public static class MockViewTableMacro extends ViewTableMacro {
+      MockViewTableMacro(CalciteSchema schema, String viewSql, List<String> schemaPath,
+          List<String> viewPath, Boolean modifiable) {
+        super(schema, viewSql, schemaPath, viewPath, modifiable);
+      }
+
+      @Override protected ModifiableViewTable modifiableViewTable(
+          CalcitePrepare.AnalyzeViewResult parsed, String viewSql,
+          List<String> schemaPath, List<String> viewPath, CalciteSchema schema) {
+        final JavaTypeFactory typeFactory = (JavaTypeFactory) parsed.typeFactory;
+        final Type elementType = typeFactory.getJavaClass(parsed.rowType);
+        return new MockModifiableViewTable(elementType,
+            RelDataTypeImpl.proto(parsed.rowType), viewSql, schemaPath, viewPath,
+            parsed.table, Schemas.path(schema.root(), parsed.tablePath),
+            parsed.constraint, parsed.columnMapping);
+      }
+    }
+
+    /**
+     * A mock of ModifiableViewTable that can unwrap a mock RelOptTable.
+     */
+    public static class MockModifiableViewTable extends ModifiableViewTable {
+      private final RexNode constraint;
+
+      MockModifiableViewTable(Type elementType, RelProtoDataType rowType,
+          String viewSql, List<String> schemaPath, List<String> viewPath,
+          Table table, Path tablePath, RexNode constraint,
+          ImmutableIntList columnMapping) {
+        super(elementType, rowType, viewSql, schemaPath, viewPath, table,
+            tablePath, constraint, columnMapping);
+        this.constraint = constraint;
+      }
+
+      @Override public ModifiableViewTable extend(Table extendedTable,
+          RelProtoDataType protoRowType, ImmutableIntList newColumnMapping) {
+        return new MockModifiableViewTable(getElementType(), protoRowType,
+            getViewSql(), getSchemaPath(), getViewPath(), extendedTable,
+            getTablePath(), constraint, newColumnMapping);
+      }
+    }
+  }
+
+  /**
+   * Mock implementation of
+   * {@link org.apache.calcite.prepare.Prepare.PreparingTable} for views.
+   */
+  public abstract static class MockViewTable extends MockTable {
+    private final MockTable fromTable;
+    private final Table table;
+    private final ImmutableIntList mapping;
+
+    MockViewTable(MockCatalogReader catalogReader, String catalogName,
+        String schemaName, String name, boolean stream, double rowCount,
+        MockTable fromTable, ImmutableIntList mapping, ColumnResolver resolver,
+        InitializerExpressionFactory initializerFactory) {
+      super(catalogReader, catalogName, schemaName, name, stream, rowCount,
+          resolver, initializerFactory);
+      this.fromTable = fromTable;
+      this.table = fromTable.unwrap(Table.class);
+      this.mapping = mapping;
+    }
+
+    /** Implementation of AbstractModifiableView. */
+    private class ModifiableView extends JdbcTest.AbstractModifiableView
+        implements Wrapper {
+      @Override public Table getTable() {
+        return fromTable.unwrap(Table.class);
+      }
+
+      @Override public Path getTablePath() {
+        final ImmutableList.Builder<Pair<String, Schema>> builder =
+            ImmutableList.builder();
+        for (String name : fromTable.names) {
+          builder.add(Pair.of(name, null));
+        }
+        return Schemas.path(builder.build());
+      }
+
+      @Override public ImmutableIntList getColumnMapping() {
+        return mapping;
+      }
+
+      @Override public RexNode getConstraint(RexBuilder rexBuilder,
+          RelDataType tableRowType) {
+        return MockViewTable.this.getConstraint(rexBuilder, tableRowType);
+      }
+
+      @Override public RelDataType
+      getRowType(final RelDataTypeFactory typeFactory) {
+        return typeFactory.createStructType(
+            new AbstractList<Map.Entry<String, RelDataType>>() {
+              @Override public Map.Entry<String, RelDataType>
+              get(int index) {
+                return table.getRowType(typeFactory).getFieldList()
+                    .get(mapping.get(index));
+              }
+
+              @Override public int size() {
+                return mapping.size();
+              }
+            });
+      }
+
+      @Override public <C> C unwrap(Class<C> aClass) {
+        if (table instanceof Wrapper) {
+          final C c = ((Wrapper) table).unwrap(aClass);
+          if (c != null) {
+            return c;
+          }
+        }
+        return super.unwrap(aClass);
+      }
+    }
+
+    /**
+     * Subclass of ModifiableView that also implements
+     * CustomColumnResolvingTable.
+     */
+    private class ModifiableViewWithCustomColumnResolving
+        extends ModifiableView implements CustomColumnResolvingTable, Wrapper {
+
+      @Override public List<Pair<RelDataTypeField, List<String>>> resolveColumn(
+          RelDataType rowType, RelDataTypeFactory typeFactory, List<String> names) {
+        return resolver.resolveColumn(rowType, typeFactory, names);
+      }
+
+      @Override public <C> C unwrap(Class<C> aClass) {
+        if (table instanceof Wrapper) {
+          final C c = ((Wrapper) table).unwrap(aClass);
+          if (c != null) {
+            return c;
+          }
+        }
+        return super.unwrap(aClass);
+      }
+    }
+
+    protected abstract RexNode getConstraint(RexBuilder rexBuilder,
+        RelDataType tableRowType);
+
+    @Override public void onRegister(RelDataTypeFactory typeFactory) {
+      super.onRegister(typeFactory);
+      // To simulate getRowType() behavior in ViewTable.
+      final RelProtoDataType protoRowType = RelDataTypeImpl.proto(rowType);
+      rowType = protoRowType.apply(typeFactory);
+    }
+
+    @Override public RelNode toRel(ToRelContext context) {
+      RelNode rel = LogicalTableScan.create(context.getCluster(), fromTable);
+      final RexBuilder rexBuilder = context.getCluster().getRexBuilder();
+      rel = LogicalFilter.create(
+          rel, getConstraint(rexBuilder, rel.getRowType()));
+      final List<RelDataTypeField> fieldList =
+          rel.getRowType().getFieldList();
+      final List<Pair<RexNode, String>> projects =
+          new AbstractList<Pair<RexNode, String>>() {
+            @Override public Pair<RexNode, String> get(int index) {
+              return RexInputRef.of2(mapping.get(index), fieldList);
+            }
+
+            @Override public int size() {
+              return mapping.size();
+            }
+          };
+      return LogicalProject.create(rel, Pair.left(projects),
+          Pair.right(projects));
+    }
+
+    @Override public <T> T unwrap(Class<T> clazz) {
+      if (clazz.isAssignableFrom(ModifiableView.class)) {
+        ModifiableView view = resolver == null
+            ? new ModifiableView()
+                : new ModifiableViewWithCustomColumnResolving();
+        return clazz.cast(view);
+      }
+      return super.unwrap(clazz);
+    }
+  }
+
+  /**
+   * Mock implementation of
+   * {@link org.apache.calcite.prepare.Prepare.PreparingTable} with dynamic record type.
+   */
+  public static class MockDynamicTable extends MockTable {
+    public MockDynamicTable(MockCatalogReader catalogReader, String catalogName,
+        String schemaName, String name, boolean stream, double rowCount) {
+      super(catalogReader, catalogName, schemaName, name, stream, rowCount,
+          null, NullInitializerExpressionFactory.INSTANCE);
+    }
+
+    public void onRegister(RelDataTypeFactory typeFactory) {
+      rowType = new DynamicRecordTypeImpl(typeFactory);
+    }
+
+    /**
+     * Recreates an immutable rowType, if the table has Dynamic Record Type,
+     * when converts table to Rel.
+     */
+    public RelNode toRel(ToRelContext context) {
+      if (rowType.isDynamicStruct()) {
+        rowType = new RelRecordType(rowType.getFieldList());
+      }
+      return super.toRel(context);
+    }
+  }
+
+  /** Struct type based on another struct type. */
+  private static class DelegateStructType implements RelDataType {
+    private RelDataType delegate;
+    private StructKind structKind;
+
+    DelegateStructType(RelDataType delegate, StructKind structKind) {
+      assert delegate.isStruct();
+      this.delegate = delegate;
+      this.structKind = structKind;
+    }
+
+    public boolean isStruct() {
+      return delegate.isStruct();
+    }
+
+    public boolean isDynamicStruct() {
+      return delegate.isDynamicStruct();
+    }
+
+    public List<RelDataTypeField> getFieldList() {
+      return delegate.getFieldList();
+    }
+
+    public List<String> getFieldNames() {
+      return delegate.getFieldNames();
+    }
+
+    public int getFieldCount() {
+      return delegate.getFieldCount();
+    }
+
+    public StructKind getStructKind() {
+      return structKind;
+    }
+
+    public RelDataTypeField getField(String fieldName, boolean caseSensitive,
+        boolean elideRecord) {
+      return delegate.getField(fieldName, caseSensitive, elideRecord);
+    }
+
+    public boolean isNullable() {
+      return delegate.isNullable();
+    }
+
+    public RelDataType getComponentType() {
+      return delegate.getComponentType();
+    }
+
+    public RelDataType getKeyType() {
+      return delegate.getKeyType();
+    }
+
+    public RelDataType getValueType() {
+      return delegate.getValueType();
+    }
+
+    public Charset getCharset() {
+      return delegate.getCharset();
+    }
+
+    public SqlCollation getCollation() {
+      return delegate.getCollation();
+    }
+
+    public SqlIntervalQualifier getIntervalQualifier() {
+      return delegate.getIntervalQualifier();
+    }
+
+    public int getPrecision() {
+      return delegate.getPrecision();
+    }
+
+    public int getScale() {
+      return delegate.getScale();
+    }
+
+    public SqlTypeName getSqlTypeName() {
+      return delegate.getSqlTypeName();
+    }
+
+    public SqlIdentifier getSqlIdentifier() {
+      return delegate.getSqlIdentifier();
+    }
+
+    public String getFullTypeString() {
+      return delegate.getFullTypeString();
+    }
+
+    public RelDataTypeFamily getFamily() {
+      return delegate.getFamily();
+    }
+
+    public RelDataTypePrecedenceList getPrecedenceList() {
+      return delegate.getPrecedenceList();
+    }
+
+    public RelDataTypeComparability getComparability() {
+      return delegate.getComparability();
+    }
+  }
+
+  /** Wrapper around a {@link MockTable}, giving it a {@link Table} interface.
+   * You can get the {@code MockTable} by calling {@link #unwrap(Class)}. */
+  private static class WrapperTable implements Table, Wrapper {
+    private final MockTable table;
+
+    WrapperTable(MockTable table) {
+      this.table = table;
+    }
+
+    public <C> C unwrap(Class<C> aClass) {
+      return aClass.isInstance(this) ? aClass.cast(this)
+          : aClass.isInstance(table) ? aClass.cast(table)
+          : null;
+    }
+
+    public RelDataType getRowType(RelDataTypeFactory typeFactory) {
+      return table.getRowType();
+    }
+
+    public Statistic getStatistic() {
+      return new Statistic() {
+        public Double getRowCount() {
+          return table.rowCount;
+        }
+
+        public boolean isKey(ImmutableBitSet columns) {
+          return table.isKey(columns);
+        }
+
+        public List<RelReferentialConstraint> getReferentialConstraints() {
+          return table.getReferentialConstraints();
+        }
+
+        public List<RelCollation> getCollations() {
+          return table.collationList;
+        }
+
+        public RelDistribution getDistribution() {
+          return table.getDistribution();
+        }
+      };
+    }
+
+    @Override public boolean isRolledUp(String column) {
+      return table.rolledUpColumns.contains(column);
+    }
+
+    @Override public boolean rolledUpColumnValidInsideAgg(String column,
+        SqlCall call, SqlNode parent, CalciteConnectionConfig config) {
+      // For testing
+      return call.getKind() != SqlKind.MAX
+              && (parent.getKind() == SqlKind.SELECT || parent.getKind() == SqlKind.FILTER);
+    }
+
+    public Schema.TableType getJdbcTableType() {
+      return table.stream ? Schema.TableType.STREAM : Schema.TableType.TABLE;
+    }
+  }
+
+  /** Wrapper around a {@link MockTable}, giving it a {@link StreamableTable}
+   * interface. */
+  private static class StreamableWrapperTable extends WrapperTable
+      implements StreamableTable {
+    StreamableWrapperTable(MockTable table) {
+      super(table);
+    }
+
+    public Table stream() {
+      return this;
+    }
+  }
+
+}
+
+// End MockCatalogReader.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderExtended.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderExtended.java b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderExtended.java
new file mode 100644
index 0000000..9fdb321
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderExtended.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.test.catalog;
+
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.schema.TableMacro;
+import org.apache.calcite.schema.TranslatableTable;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** Adds some extra tables to the mock catalog. These increase the time and
+ * complexity of initializing the catalog (because they contain views whose
+ * SQL needs to be parsed) and so are not used for all tests. */
+public class MockCatalogReaderExtended extends MockCatalogReaderSimple {
+  /**
+   * Creates a MockCatalogReader.
+   *
+   * <p>Caller must then call {@link #init} to populate with data.</p>
+   *
+   * @param typeFactory   Type factory
+   * @param caseSensitive case sensitivity
+   */
+  public MockCatalogReaderExtended(RelDataTypeFactory typeFactory,
+      boolean caseSensitive) {
+    super(typeFactory, caseSensitive);
+  }
+
+  @Override public MockCatalogReader init() {
+    super.init();
+
+    MockSchema salesSchema = new MockSchema("SALES");
+    // Same as "EMP_20" except it uses ModifiableViewTable which populates
+    // constrained columns with default values on INSERT and has a single constraint on DEPTNO.
+    List<String> empModifiableViewNames = ImmutableList.of(
+        salesSchema.getCatalogName(), salesSchema.getName(), "EMP_MODIFIABLEVIEW");
+    TableMacro empModifiableViewMacro = MockModifiableViewRelOptTable.viewMacro(rootSchema,
+        "select EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, SLACKER from EMPDEFAULTS"
+            + " where DEPTNO = 20", empModifiableViewNames.subList(0, 2),
+        ImmutableList.of(empModifiableViewNames.get(2)), true);
+    TranslatableTable empModifiableView = empModifiableViewMacro.apply(ImmutableList.of());
+    MockModifiableViewRelOptTable mockEmpViewTable = MockModifiableViewRelOptTable.create(
+        (MockModifiableViewRelOptTable.MockModifiableViewTable) empModifiableView, this,
+        empModifiableViewNames.get(0), empModifiableViewNames.get(1),
+        empModifiableViewNames.get(2), false, 20, null);
+    registerTable(mockEmpViewTable);
+
+    // Same as "EMP_MODIFIABLEVIEW" except that all columns are in the view, columns are reordered,
+    // and there is an `extra` extended column.
+    List<String> empModifiableViewNames2 = ImmutableList.of(
+        salesSchema.getCatalogName(), salesSchema.getName(), "EMP_MODIFIABLEVIEW2");
+    TableMacro empModifiableViewMacro2 = MockModifiableViewRelOptTable.viewMacro(rootSchema,
+        "select ENAME, EMPNO, JOB, DEPTNO, SLACKER, SAL, EXTRA, HIREDATE, MGR, COMM"
+            + " from EMPDEFAULTS extend (EXTRA boolean)"
+            + " where DEPTNO = 20", empModifiableViewNames2.subList(0, 2),
+        ImmutableList.of(empModifiableViewNames.get(2)), true);
+    TranslatableTable empModifiableView2 = empModifiableViewMacro2.apply(ImmutableList.of());
+    MockModifiableViewRelOptTable mockEmpViewTable2 = MockModifiableViewRelOptTable.create(
+        (MockModifiableViewRelOptTable.MockModifiableViewTable) empModifiableView2, this,
+        empModifiableViewNames2.get(0), empModifiableViewNames2.get(1),
+        empModifiableViewNames2.get(2), false, 20, null);
+    registerTable(mockEmpViewTable2);
+
+    // Same as "EMP_MODIFIABLEVIEW" except that comm is not in the view.
+    List<String> empModifiableViewNames3 = ImmutableList.of(
+        salesSchema.getCatalogName(), salesSchema.getName(), "EMP_MODIFIABLEVIEW3");
+    TableMacro empModifiableViewMacro3 = MockModifiableViewRelOptTable.viewMacro(rootSchema,
+        "select EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, SLACKER from EMPDEFAULTS"
+            + " where DEPTNO = 20", empModifiableViewNames3.subList(0, 2),
+        ImmutableList.of(empModifiableViewNames3.get(2)), true);
+    TranslatableTable empModifiableView3 = empModifiableViewMacro3.apply(ImmutableList.of());
+    MockModifiableViewRelOptTable mockEmpViewTable3 = MockModifiableViewRelOptTable.create(
+        (MockModifiableViewRelOptTable.MockModifiableViewTable) empModifiableView3, this,
+        empModifiableViewNames3.get(0), empModifiableViewNames3.get(1),
+        empModifiableViewNames3.get(2), false, 20, null);
+    registerTable(mockEmpViewTable3);
+
+    MockSchema structTypeSchema = new MockSchema("STRUCT");
+    registerSchema(structTypeSchema);
+    final Fixture f = new Fixture(typeFactory);
+    final List<CompoundNameColumn> columnsExtended = Arrays.asList(
+        new CompoundNameColumn("", "K0", f.varchar20TypeNull),
+        new CompoundNameColumn("", "C1", f.varchar20TypeNull),
+        new CompoundNameColumn("F0", "C0", f.intType),
+        new CompoundNameColumn("F1", "C1", f.intTypeNull));
+    final List<CompoundNameColumn> extendedColumns =
+        new ArrayList<CompoundNameColumn>(columnsExtended);
+    extendedColumns.add(new CompoundNameColumn("F2", "C2", f.varchar20Type));
+    final CompoundNameColumnResolver structExtendedTableResolver =
+        new CompoundNameColumnResolver(extendedColumns, "F0");
+    final MockTable structExtendedTypeTable =
+        MockTable.create(this, structTypeSchema, "T_EXTEND", false, 100,
+            structExtendedTableResolver);
+    for (CompoundNameColumn column : columnsExtended) {
+      structExtendedTypeTable.addColumn(column.getName(), column.type);
+    }
+    registerTable(structExtendedTypeTable);
+
+    return this;
+  }
+}
+
+// End MockCatalogReaderExtended.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderSimple.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderSimple.java b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderSimple.java
new file mode 100644
index 0000000..c9130d0
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReaderSimple.java
@@ -0,0 +1,422 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.test.catalog;
+
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.ObjectSqlType;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.sql2rel.InitializerExpressionFactory;
+import org.apache.calcite.sql2rel.NullInitializerExpressionFactory;
+import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.Litmus;
+import org.apache.calcite.util.Util;
+
+import com.google.common.collect.ImmutableList;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Simple catalog reader for testing.
+ */
+public class MockCatalogReaderSimple extends MockCatalogReader {
+  private final Fixture fixture;
+
+  /**
+   * Creates a MockCatalogReader.
+   *
+   * <p>Caller must then call {@link #init} to populate with data.</p>
+   *
+   * @param typeFactory   Type factory
+   * @param caseSensitive case sensitivity
+   */
+  public MockCatalogReaderSimple(RelDataTypeFactory typeFactory,
+      boolean caseSensitive) {
+    super(typeFactory, caseSensitive);
+    fixture = new Fixture(typeFactory);
+  }
+
+  @Override public RelDataType getNamedType(SqlIdentifier typeName) {
+    if (typeName.equalsDeep(fixture.addressType.getSqlIdentifier(), Litmus.IGNORE)) {
+      return fixture.addressType;
+    } else {
+      return super.getNamedType(typeName);
+    }
+  }
+
+  @Override public MockCatalogReader init() {
+    ObjectSqlType addressType = fixture.addressType;
+
+    // Register "SALES" schema.
+    MockSchema salesSchema = new MockSchema("SALES");
+    registerSchema(salesSchema);
+
+    // Register "EMP" table with customer InitializerExpressionFactory
+    // to check whether newDefaultValue method called or not.
+    final InitializerExpressionFactory countingInitializerExpressionFactory =
+        new CountingFactory(ImmutableList.of("DEPTNO"));
+
+    registerType(
+        ImmutableList.of(salesSchema.getCatalogName(), salesSchema.getName(),
+            "customBigInt"),
+        typeFactory -> typeFactory.createSqlType(SqlTypeName.BIGINT));
+
+    // Register "EMP" table.
+    final MockTable empTable =
+        MockTable.create(this, salesSchema, "EMP", false, 14, null,
+            countingInitializerExpressionFactory);
+    empTable.addColumn("EMPNO", fixture.intType, true);
+    empTable.addColumn("ENAME", fixture.varchar20Type);
+    empTable.addColumn("JOB", fixture.varchar10Type);
+    empTable.addColumn("MGR", fixture.intTypeNull);
+    empTable.addColumn("HIREDATE", fixture.timestampType);
+    empTable.addColumn("SAL", fixture.intType);
+    empTable.addColumn("COMM", fixture.intType);
+    empTable.addColumn("DEPTNO", fixture.intType);
+    empTable.addColumn("SLACKER", fixture.booleanType);
+    registerTable(empTable);
+
+    // Register "EMPNULLABLES" table with nullable columns.
+    final MockTable empNullablesTable =
+        MockTable.create(this, salesSchema, "EMPNULLABLES", false, 14);
+    empNullablesTable.addColumn("EMPNO", fixture.intType, true);
+    empNullablesTable.addColumn("ENAME", fixture.varchar20Type);
+    empNullablesTable.addColumn("JOB", fixture.varchar10TypeNull);
+    empNullablesTable.addColumn("MGR", fixture.intTypeNull);
+    empNullablesTable.addColumn("HIREDATE", fixture.timestampTypeNull);
+    empNullablesTable.addColumn("SAL", fixture.intTypeNull);
+    empNullablesTable.addColumn("COMM", fixture.intTypeNull);
+    empNullablesTable.addColumn("DEPTNO", fixture.intTypeNull);
+    empNullablesTable.addColumn("SLACKER", fixture.booleanTypeNull);
+    registerTable(empNullablesTable);
+
+    // Register "EMPDEFAULTS" table with default values for some columns.
+    final MockTable empDefaultsTable =
+        MockTable.create(this, salesSchema, "EMPDEFAULTS", false, 14, null,
+            new EmpInitializerExpressionFactory());
+    empDefaultsTable.addColumn("EMPNO", fixture.intType, true);
+    empDefaultsTable.addColumn("ENAME", fixture.varchar20Type);
+    empDefaultsTable.addColumn("JOB", fixture.varchar10TypeNull);
+    empDefaultsTable.addColumn("MGR", fixture.intTypeNull);
+    empDefaultsTable.addColumn("HIREDATE", fixture.timestampTypeNull);
+    empDefaultsTable.addColumn("SAL", fixture.intTypeNull);
+    empDefaultsTable.addColumn("COMM", fixture.intTypeNull);
+    empDefaultsTable.addColumn("DEPTNO", fixture.intTypeNull);
+    empDefaultsTable.addColumn("SLACKER", fixture.booleanTypeNull);
+    registerTable(empDefaultsTable);
+
+    // Register "EMP_B" table. As "EMP", birth with a "BIRTHDATE" column.
+    final MockTable empBTable =
+        MockTable.create(this, salesSchema, "EMP_B", false, 14);
+    empBTable.addColumn("EMPNO", fixture.intType, true);
+    empBTable.addColumn("ENAME", fixture.varchar20Type);
+    empBTable.addColumn("JOB", fixture.varchar10Type);
+    empBTable.addColumn("MGR", fixture.intTypeNull);
+    empBTable.addColumn("HIREDATE", fixture.timestampType);
+    empBTable.addColumn("SAL", fixture.intType);
+    empBTable.addColumn("COMM", fixture.intType);
+    empBTable.addColumn("DEPTNO", fixture.intType);
+    empBTable.addColumn("SLACKER", fixture.booleanType);
+    empBTable.addColumn("BIRTHDATE", fixture.dateType);
+    registerTable(empBTable);
+
+    // Register "DEPT" table.
+    MockTable deptTable = MockTable.create(this, salesSchema, "DEPT", false, 4);
+    deptTable.addColumn("DEPTNO", fixture.intType, true);
+    deptTable.addColumn("NAME", fixture.varchar10Type);
+    registerTable(deptTable);
+
+    // Register "DEPT_NESTED" table.
+    MockTable deptNestedTable =
+        MockTable.create(this, salesSchema, "DEPT_NESTED", false, 4);
+    deptNestedTable.addColumn("DEPTNO", fixture.intType, true);
+    deptNestedTable.addColumn("NAME", fixture.varchar10Type);
+    deptNestedTable.addColumn("SKILL", fixture.skillRecordType);
+    deptNestedTable.addColumn("EMPLOYEES", fixture.empListType);
+    registerTable(deptNestedTable);
+
+    // Register "BONUS" table.
+    MockTable bonusTable =
+        MockTable.create(this, salesSchema, "BONUS", false, 0);
+    bonusTable.addColumn("ENAME", fixture.varchar20Type);
+    bonusTable.addColumn("JOB", fixture.varchar10Type);
+    bonusTable.addColumn("SAL", fixture.intType);
+    bonusTable.addColumn("COMM", fixture.intType);
+    registerTable(bonusTable);
+
+    // Register "SALGRADE" table.
+    MockTable salgradeTable =
+        MockTable.create(this, salesSchema, "SALGRADE", false, 5);
+    salgradeTable.addColumn("GRADE", fixture.intType, true);
+    salgradeTable.addColumn("LOSAL", fixture.intType);
+    salgradeTable.addColumn("HISAL", fixture.intType);
+    registerTable(salgradeTable);
+
+    // Register "EMP_ADDRESS" table
+    MockTable contactAddressTable =
+        MockTable.create(this, salesSchema, "EMP_ADDRESS", false, 26);
+    contactAddressTable.addColumn("EMPNO", fixture.intType, true);
+    contactAddressTable.addColumn("HOME_ADDRESS", addressType);
+    contactAddressTable.addColumn("MAILING_ADDRESS", addressType);
+    registerTable(contactAddressTable);
+
+    // Register "DYNAMIC" schema.
+    MockSchema dynamicSchema = new MockSchema("DYNAMIC");
+    registerSchema(dynamicSchema);
+
+    MockTable nationTable =
+        new MockDynamicTable(this, dynamicSchema.getCatalogName(),
+            dynamicSchema.getName(), "NATION", false, 100);
+    registerTable(nationTable);
+
+    MockTable customerTable =
+        new MockDynamicTable(this, dynamicSchema.getCatalogName(),
+            dynamicSchema.getName(), "CUSTOMER", false, 100);
+    registerTable(customerTable);
+
+    // Register "CUSTOMER" schema.
+    MockSchema customerSchema = new MockSchema("CUSTOMER");
+    registerSchema(customerSchema);
+
+    // Register "CONTACT" table.
+    MockTable contactTable = MockTable.create(this, customerSchema, "CONTACT",
+        false, 1000);
+    contactTable.addColumn("CONTACTNO", fixture.intType);
+    contactTable.addColumn("FNAME", fixture.varchar10Type);
+    contactTable.addColumn("LNAME", fixture.varchar10Type);
+    contactTable.addColumn("EMAIL", fixture.varchar20Type);
+    contactTable.addColumn("COORD", fixture.rectilinearCoordType);
+    registerTable(contactTable);
+
+    // Register "CONTACT_PEEK" table. The
+    MockTable contactPeekTable =
+        MockTable.create(this, customerSchema, "CONTACT_PEEK", false, 1000);
+    contactPeekTable.addColumn("CONTACTNO", fixture.intType);
+    contactPeekTable.addColumn("FNAME", fixture.varchar10Type);
+    contactPeekTable.addColumn("LNAME", fixture.varchar10Type);
+    contactPeekTable.addColumn("EMAIL", fixture.varchar20Type);
+    contactPeekTable.addColumn("COORD", fixture.rectilinearPeekCoordType);
+    contactPeekTable.addColumn("COORD_NE", fixture.rectilinearPeekNoExpandCoordType);
+    registerTable(contactPeekTable);
+
+    // Register "ACCOUNT" table.
+    MockTable accountTable = MockTable.create(this, customerSchema, "ACCOUNT",
+        false, 457);
+    accountTable.addColumn("ACCTNO", fixture.intType);
+    accountTable.addColumn("TYPE", fixture.varchar20Type);
+    accountTable.addColumn("BALANCE", fixture.intType);
+    registerTable(accountTable);
+
+    // Register "ORDERS" stream.
+    MockTable ordersStream = MockTable.create(this, salesSchema, "ORDERS",
+        true, Double.POSITIVE_INFINITY);
+    ordersStream.addColumn("ROWTIME", fixture.timestampType);
+    ordersStream.addMonotonic("ROWTIME");
+    ordersStream.addColumn("PRODUCTID", fixture.intType);
+    ordersStream.addColumn("ORDERID", fixture.intType);
+    registerTable(ordersStream);
+
+    // Register "SHIPMENTS" stream.
+    // "ROWTIME" is not column 0, just to mix things up.
+    MockTable shipmentsStream = MockTable.create(this, salesSchema, "SHIPMENTS",
+        true, Double.POSITIVE_INFINITY);
+    shipmentsStream.addColumn("ORDERID", fixture.intType);
+    shipmentsStream.addColumn("ROWTIME", fixture.timestampType);
+    shipmentsStream.addMonotonic("ROWTIME");
+    registerTable(shipmentsStream);
+
+    // Register "PRODUCTS" table.
+    MockTable productsTable = MockTable.create(this, salesSchema, "PRODUCTS",
+        false, 200D);
+    productsTable.addColumn("PRODUCTID", fixture.intType);
+    productsTable.addColumn("NAME", fixture.varchar20Type);
+    productsTable.addColumn("SUPPLIERID", fixture.intType);
+    registerTable(productsTable);
+
+    // Register "SUPPLIERS" table.
+    MockTable suppliersTable = MockTable.create(this, salesSchema, "SUPPLIERS",
+        false, 10D);
+    suppliersTable.addColumn("SUPPLIERID", fixture.intType);
+    suppliersTable.addColumn("NAME", fixture.varchar20Type);
+    suppliersTable.addColumn("CITY", fixture.intType);
+    registerTable(suppliersTable);
+
+    // Register "EMP_20" and "EMPNULLABLES_20 views.
+    // Same columns as "EMP" amd "EMPNULLABLES",
+    // but "DEPTNO" not visible and set to 20 by default
+    // and "SAL" is visible but must be greater than 1000,
+    // which is the equivalent of:
+    //   SELECT EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, SLACKER
+    //   FROM EMP
+    //   WHERE DEPTNO = 20 AND SAL > 1000
+    final ImmutableIntList m0 = ImmutableIntList.of(0, 1, 2, 3, 4, 5, 6, 8);
+    MockTable emp20View =
+        new MockViewTable(this, salesSchema.getCatalogName(), salesSchema.getName(),
+            "EMP_20", false, 600, empTable, m0, null,
+            NullInitializerExpressionFactory.INSTANCE) {
+          public RexNode getConstraint(RexBuilder rexBuilder,
+              RelDataType tableRowType) {
+            final RelDataTypeField deptnoField =
+                tableRowType.getFieldList().get(7);
+            final RelDataTypeField salField =
+                tableRowType.getFieldList().get(5);
+            final List<RexNode> nodes = Arrays.asList(
+                rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+                    rexBuilder.makeInputRef(deptnoField.getType(),
+                        deptnoField.getIndex()),
+                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(20L),
+                        deptnoField.getType())),
+                rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN,
+                    rexBuilder.makeInputRef(salField.getType(),
+                        salField.getIndex()),
+                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(1000L),
+                        salField.getType())));
+            return RexUtil.composeConjunction(rexBuilder, nodes, false);
+          }
+        };
+    salesSchema.addTable(Util.last(emp20View.getQualifiedName()));
+    emp20View.addColumn("EMPNO", fixture.intType);
+    emp20View.addColumn("ENAME", fixture.varchar20Type);
+    emp20View.addColumn("JOB", fixture.varchar10Type);
+    emp20View.addColumn("MGR", fixture.intTypeNull);
+    emp20View.addColumn("HIREDATE", fixture.timestampType);
+    emp20View.addColumn("SAL", fixture.intType);
+    emp20View.addColumn("COMM", fixture.intType);
+    emp20View.addColumn("SLACKER", fixture.booleanType);
+    registerTable(emp20View);
+
+    MockTable empNullables20View =
+        new MockViewTable(this, salesSchema.getCatalogName(), salesSchema.getName(),
+            "EMPNULLABLES_20", false, 600, empNullablesTable, m0, null,
+            NullInitializerExpressionFactory.INSTANCE) {
+          public RexNode getConstraint(RexBuilder rexBuilder,
+              RelDataType tableRowType) {
+            final RelDataTypeField deptnoField =
+                tableRowType.getFieldList().get(7);
+            final RelDataTypeField salField =
+                tableRowType.getFieldList().get(5);
+            final List<RexNode> nodes = Arrays.asList(
+                rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+                    rexBuilder.makeInputRef(deptnoField.getType(),
+                        deptnoField.getIndex()),
+                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(20L),
+                        deptnoField.getType())),
+                rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN,
+                    rexBuilder.makeInputRef(salField.getType(),
+                        salField.getIndex()),
+                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(1000L),
+                        salField.getType())));
+            return RexUtil.composeConjunction(rexBuilder, nodes, false);
+          }
+        };
+    salesSchema.addTable(Util.last(empNullables20View.getQualifiedName()));
+    empNullables20View.addColumn("EMPNO", fixture.intType);
+    empNullables20View.addColumn("ENAME", fixture.varchar20Type);
+    empNullables20View.addColumn("JOB", fixture.varchar10TypeNull);
+    empNullables20View.addColumn("MGR", fixture.intTypeNull);
+    empNullables20View.addColumn("HIREDATE", fixture.timestampTypeNull);
+    empNullables20View.addColumn("SAL", fixture.intTypeNull);
+    empNullables20View.addColumn("COMM", fixture.intTypeNull);
+    empNullables20View.addColumn("SLACKER", fixture.booleanTypeNull);
+    registerTable(empNullables20View);
+
+    MockSchema structTypeSchema = new MockSchema("STRUCT");
+    registerSchema(structTypeSchema);
+    final List<CompoundNameColumn> columns = Arrays.asList(
+        new CompoundNameColumn("", "K0", fixture.varchar20Type),
+        new CompoundNameColumn("", "C1", fixture.varchar20Type),
+        new CompoundNameColumn("F1", "A0", fixture.intType),
+        new CompoundNameColumn("F2", "A0", fixture.booleanType),
+        new CompoundNameColumn("F0", "C0", fixture.intType),
+        new CompoundNameColumn("F1", "C0", fixture.intTypeNull),
+        new CompoundNameColumn("F0", "C1", fixture.intType),
+        new CompoundNameColumn("F1", "C2", fixture.intType),
+        new CompoundNameColumn("F2", "C3", fixture.intType));
+    final CompoundNameColumnResolver structTypeTableResolver =
+        new CompoundNameColumnResolver(columns, "F0");
+    final MockTable structTypeTable =
+        MockTable.create(this, structTypeSchema, "T", false, 100,
+            structTypeTableResolver);
+    for (CompoundNameColumn column : columns) {
+      structTypeTable.addColumn(column.getName(), column.type);
+    }
+    registerTable(structTypeTable);
+
+    final List<CompoundNameColumn> columnsNullable = Arrays.asList(
+        new CompoundNameColumn("", "K0", fixture.varchar20TypeNull),
+        new CompoundNameColumn("", "C1", fixture.varchar20TypeNull),
+        new CompoundNameColumn("F1", "A0", fixture.intTypeNull),
+        new CompoundNameColumn("F2", "A0", fixture.booleanTypeNull),
+        new CompoundNameColumn("F0", "C0", fixture.intTypeNull),
+        new CompoundNameColumn("F1", "C0", fixture.intTypeNull),
+        new CompoundNameColumn("F0", "C1", fixture.intTypeNull),
+        new CompoundNameColumn("F1", "C2", fixture.intType),
+        new CompoundNameColumn("F2", "C3", fixture.intTypeNull));
+    final MockTable structNullableTypeTable =
+        MockTable.create(this, structTypeSchema, "T_NULLABLES", false, 100,
+            structTypeTableResolver);
+    for (CompoundNameColumn column : columnsNullable) {
+      structNullableTypeTable.addColumn(column.getName(), column.type);
+    }
+    registerTable(structNullableTypeTable);
+
+    // Register "STRUCT.T_10" view.
+    // Same columns as "STRUCT.T",
+    // but "F0.C0" is set to 10 by default,
+    // which is the equivalent of:
+    //   SELECT *
+    //   FROM T
+    //   WHERE F0.C0 = 10
+    // This table uses MockViewTable which does not populate the constrained columns with default
+    // values on INSERT.
+    final ImmutableIntList m1 = ImmutableIntList.of(0, 1, 2, 3, 4, 5, 6, 7, 8);
+    MockTable struct10View =
+        new MockViewTable(this, structTypeSchema.getCatalogName(),
+            structTypeSchema.getName(), "T_10", false, 20, structTypeTable,
+            m1, structTypeTableResolver,
+            NullInitializerExpressionFactory.INSTANCE) {
+          @Override public RexNode getConstraint(RexBuilder rexBuilder,
+              RelDataType tableRowType) {
+            final RelDataTypeField c0Field =
+                tableRowType.getFieldList().get(4);
+            return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
+                rexBuilder.makeInputRef(c0Field.getType(),
+                    c0Field.getIndex()),
+                rexBuilder.makeExactLiteral(BigDecimal.valueOf(10L),
+                    c0Field.getType()));
+          }
+        };
+    structTypeSchema.addTable(Util.last(struct10View.getQualifiedName()));
+    for (CompoundNameColumn column : columns) {
+      struct10View.addColumn(column.getName(), column.type);
+    }
+    registerTable(struct10View);
+    registerTablesWithRollUp(salesSchema, fixture);
+    return this;
+
+  }
+}
+
+// End MockCatalogReaderSimple.java


[3/3] calcite git commit: [CALCITE-2435] tests: refactor SqlTestFactory

Posted by vl...@apache.org.
[CALCITE-2435] tests: refactor SqlTestFactory

closes #771


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

Branch: refs/heads/master
Commit: 96b28f7ba11de22a68d984de6b6b88311cc2c57e
Parents: c113765
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Wed Aug 1 13:40:56 2018 +0300
Committer: Vladimir Sitnikov <si...@gmail.com>
Committed: Thu Aug 2 12:10:12 2018 +0300

----------------------------------------------------------------------
 .../calcite/sql/test/DefaultSqlTestFactory.java |  159 --
 .../sql/test/DelegatingSqlTestFactory.java      |   73 -
 .../apache/calcite/sql/test/SqlAdvisorTest.java |   48 +-
 .../calcite/sql/test/SqlOperatorBaseTest.java   |   14 +-
 .../apache/calcite/sql/test/SqlTestFactory.java |  181 +-
 .../apache/calcite/sql/test/SqlTesterImpl.java  |   16 +-
 .../sql/validate/SqlValidatorUtilTest.java      |    4 +-
 .../apache/calcite/test/MockCatalogReader.java  | 1750 ------------------
 .../apache/calcite/test/RelOptRulesTest.java    |    1 +
 .../org/apache/calcite/test/SqlTestGen.java     |   20 +-
 .../calcite/test/SqlToRelConverterTest.java     |    3 +-
 .../apache/calcite/test/SqlToRelTestBase.java   |    4 +-
 .../calcite/test/SqlValidatorFeatureTest.java   |   28 +-
 .../apache/calcite/test/SqlValidatorTest.java   |   11 +-
 .../calcite/test/SqlValidatorTestCase.java      |   13 +-
 .../test/catalog/CompoundNameColumn.java        |   39 +
 .../catalog/CompoundNameColumnResolver.java     |  150 ++
 .../calcite/test/catalog/CountingFactory.java   |   82 +
 .../EmpInitializerExpressionFactory.java        |   64 +
 .../apache/calcite/test/catalog/Fixture.java    |  125 ++
 .../calcite/test/catalog/MockCatalogReader.java | 1006 ++++++++++
 .../test/catalog/MockCatalogReaderExtended.java |  120 ++
 .../test/catalog/MockCatalogReaderSimple.java   |  422 +++++
 23 files changed, 2218 insertions(+), 2115 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/sql/test/DefaultSqlTestFactory.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/DefaultSqlTestFactory.java b/core/src/test/java/org/apache/calcite/sql/test/DefaultSqlTestFactory.java
deleted file mode 100644
index e2667d5..0000000
--- a/core/src/test/java/org/apache/calcite/sql/test/DefaultSqlTestFactory.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.sql.test;
-
-import org.apache.calcite.adapter.java.JavaTypeFactory;
-import org.apache.calcite.avatica.util.Casing;
-import org.apache.calcite.avatica.util.Quoting;
-import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
-import org.apache.calcite.rel.type.DelegatingTypeSystem;
-import org.apache.calcite.rel.type.RelDataTypeSystem;
-import org.apache.calcite.sql.SqlOperatorTable;
-import org.apache.calcite.sql.advise.SqlAdvisor;
-import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.sql.parser.SqlParser;
-import org.apache.calcite.sql.validate.SqlConformance;
-import org.apache.calcite.sql.validate.SqlConformanceEnum;
-import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.sql.validate.SqlValidatorUtil;
-import org.apache.calcite.sql.validate.SqlValidatorWithHints;
-import org.apache.calcite.test.CalciteAssert;
-import org.apache.calcite.test.MockCatalogReader;
-import org.apache.calcite.test.MockSqlOperatorTable;
-
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableMap;
-
-import javax.annotation.Nonnull;
-
-/**
- * Default implementation of {@link SqlTestFactory}.
- *
- * <p>Suitable for most tests. If you want different behavior, you can extend;
- * if you want a factory with different properties (e.g. SQL conformance level
- * or identifier quoting), wrap in a
- * {@link DelegatingSqlTestFactory} and
- * override {@link #get}.</p>
-*/
-public class DefaultSqlTestFactory implements SqlTestFactory {
-  public static final ImmutableMap<String, Object> DEFAULT_OPTIONS =
-      ImmutableMap.<String, Object>builder()
-          .put("quoting", Quoting.DOUBLE_QUOTE)
-          .put("quotedCasing", Casing.UNCHANGED)
-          .put("unquotedCasing", Casing.TO_UPPER)
-          .put("caseSensitive", true)
-          .put("conformance", SqlConformanceEnum.DEFAULT)
-          .put("operatorTable", SqlStdOperatorTable.instance())
-          .put("connectionFactory",
-              CalciteAssert.EMPTY_CONNECTION_FACTORY
-                  .with(
-                      new CalciteAssert.AddSchemaSpecPostProcessor(
-                          CalciteAssert.SchemaSpec.HR)))
-          .build();
-
-  /** Caches the mock catalog.
-   * Due to view parsing, initializing a mock catalog is quite expensive.
-   * Validator is not re-entrant, so we create a new one for each test.
-   * Caching improves SqlValidatorTest from 23s to 8s,
-   * and CalciteSqlOperatorTest from 65s to 43s. */
-  private final LoadingCache<SqlTestFactory, Xyz> cache =
-      CacheBuilder.newBuilder().build(CacheLoader.from(Xyz::from));
-
-  public static final DefaultSqlTestFactory INSTANCE =
-      new DefaultSqlTestFactory();
-
-  private DefaultSqlTestFactory() {
-  }
-
-  public MockCatalogReader createCatalogReader(SqlTestFactory testFactory,
-      JavaTypeFactory typeFactory) {
-    final boolean caseSensitive = (Boolean) testFactory.get("caseSensitive");
-    return new MockCatalogReader(typeFactory, caseSensitive).init();
-  }
-
-  public SqlOperatorTable createOperatorTable(SqlTestFactory factory) {
-    final SqlOperatorTable opTab0 =
-        (SqlOperatorTable) factory.get("operatorTable");
-    MockSqlOperatorTable opTab = new MockSqlOperatorTable(opTab0);
-    MockSqlOperatorTable.addRamp(opTab);
-    return opTab;
-  }
-
-  public SqlParser createParser(SqlTestFactory factory, String sql) {
-    return SqlParser.create(sql,
-        SqlParser.configBuilder()
-            .setQuoting((Quoting) factory.get("quoting"))
-            .setUnquotedCasing((Casing) factory.get("unquotedCasing"))
-            .setQuotedCasing((Casing) factory.get("quotedCasing"))
-            .setConformance((SqlConformance) factory.get("conformance"))
-            .build());
-  }
-
-  public SqlValidator getValidator(SqlTestFactory factory) {
-    final Xyz xyz = cache.getUnchecked(factory);
-    final SqlConformance conformance =
-        (SqlConformance) factory.get("conformance");
-    return SqlValidatorUtil.newValidator(xyz.operatorTable,
-        xyz.catalogReader, xyz.typeFactory, conformance);
-  }
-
-  public SqlAdvisor createAdvisor(SqlValidatorWithHints validator) {
-    throw new UnsupportedOperationException();
-  }
-
-  public Object get(String name) {
-    return DEFAULT_OPTIONS.get(name);
-  }
-
-  /** State that can be cached and shared among tests. */
-  private static class Xyz {
-    private final SqlOperatorTable operatorTable;
-    private final JavaTypeFactory typeFactory;
-    private final MockCatalogReader catalogReader;
-
-    Xyz(SqlOperatorTable operatorTable, JavaTypeFactory typeFactory,
-        MockCatalogReader catalogReader) {
-      this.operatorTable = operatorTable;
-      this.typeFactory = typeFactory;
-      this.catalogReader = catalogReader;
-    }
-
-    static Xyz from(@Nonnull SqlTestFactory factory) {
-      final SqlOperatorTable operatorTable =
-          factory.createOperatorTable(factory);
-      RelDataTypeSystem typeSystem = RelDataTypeSystem.DEFAULT;
-      final SqlConformance conformance =
-          (SqlConformance) factory.get("conformance");
-      if (conformance.shouldConvertRaggedUnionTypesToVarying()) {
-        typeSystem = new DelegatingTypeSystem(typeSystem) {
-          public boolean shouldConvertRaggedUnionTypesToVarying() {
-            return true;
-          }
-        };
-      }
-      final JavaTypeFactory typeFactory =
-          new JavaTypeFactoryImpl(typeSystem);
-      final MockCatalogReader catalogReader =
-          factory.createCatalogReader(factory, typeFactory);
-      return new Xyz(operatorTable, typeFactory, catalogReader);
-    }
-  }
-}
-
-// End DefaultSqlTestFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/sql/test/DelegatingSqlTestFactory.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/DelegatingSqlTestFactory.java b/core/src/test/java/org/apache/calcite/sql/test/DelegatingSqlTestFactory.java
deleted file mode 100644
index cfd628f..0000000
--- a/core/src/test/java/org/apache/calcite/sql/test/DelegatingSqlTestFactory.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.sql.test;
-
-import org.apache.calcite.adapter.java.JavaTypeFactory;
-import org.apache.calcite.sql.SqlOperatorTable;
-import org.apache.calcite.sql.advise.SqlAdvisor;
-import org.apache.calcite.sql.parser.SqlParser;
-import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.sql.validate.SqlValidatorWithHints;
-import org.apache.calcite.test.MockCatalogReader;
-
-/**
-* Implementation of {@link SqlTestFactory} that delegates
- * everything to an underlying factory.
- *
- * <p>Generally a chain starts with a
- * {@link org.apache.calcite.sql.test.DefaultSqlTestFactory}, and continues with
- * a succession of objects that derive from {@code DelegatingSqlTestFactory} and
- * override one method.</p>
- *
- * <p>Methods such as
- * {@link org.apache.calcite.sql.test.SqlTester#withConformance} help create
- * such chains.</p>
-*/
-public class DelegatingSqlTestFactory implements SqlTestFactory {
-  private final SqlTestFactory factory;
-
-  public DelegatingSqlTestFactory(SqlTestFactory factory) {
-    this.factory = factory;
-  }
-
-  public Object get(String name) {
-    return factory.get(name);
-  }
-
-  public MockCatalogReader createCatalogReader(SqlTestFactory factory,
-      JavaTypeFactory typeFactory) {
-    return this.factory.createCatalogReader(factory, typeFactory);
-  }
-
-  public SqlOperatorTable createOperatorTable(SqlTestFactory factory) {
-    return this.factory.createOperatorTable(factory);
-  }
-
-  public SqlAdvisor createAdvisor(SqlValidatorWithHints validator) {
-    return factory.createAdvisor(validator);
-  }
-
-  public SqlValidator getValidator(SqlTestFactory factory) {
-    return this.factory.getValidator(factory);
-  }
-
-  public SqlParser createParser(SqlTestFactory factory, String sql) {
-    return this.factory.createParser(factory, sql);
-  }
-}
-
-// End DelegatingSqlTestFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
index c8476be..0742731 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java
@@ -16,20 +16,12 @@
  */
 package org.apache.calcite.sql.test;
 
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.sql.advise.SqlAdvisor;
 import org.apache.calcite.sql.advise.SqlAdvisorValidator;
 import org.apache.calcite.sql.advise.SqlSimpleParser;
-import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParserUtil;
-import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
-import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlMoniker;
 import org.apache.calcite.sql.validate.SqlMonikerType;
-import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.sql.validate.SqlValidatorWithHints;
-import org.apache.calcite.test.MockCatalogReader;
 import org.apache.calcite.test.SqlValidatorTestCase;
 
 import org.junit.Assert;
@@ -52,6 +44,9 @@ import static org.junit.Assert.fail;
  * for SqlAdvisor.
  */
 public class SqlAdvisorTest extends SqlValidatorTestCase {
+  public static final SqlTestFactory ADVISOR_TEST_FACTORY = SqlTestFactory.INSTANCE.withValidator(
+      SqlAdvisorValidator::new);
+
   //~ Static fields/initializers ---------------------------------------------
 
   private static final List<String> STAR_KEYWORD =
@@ -413,9 +408,7 @@ public class SqlAdvisorTest extends SqlValidatorTestCase {
   protected void assertHint(
       String sql,
       String expectedResults) throws Exception {
-    SqlValidatorWithHints validator =
-        (SqlValidatorWithHints) tester.getValidator();
-    SqlAdvisor advisor = tester.getFactory().createAdvisor(validator);
+    SqlAdvisor advisor = tester.getFactory().createAdvisor();
 
     SqlParserUtil.StringAndPos sap = SqlParserUtil.findPos(sql);
 
@@ -436,9 +429,7 @@ public class SqlAdvisorTest extends SqlValidatorTestCase {
    * @param expected Expected result after simplification.
    */
   protected void assertSimplify(String sql, String expected) {
-    SqlValidatorWithHints validator =
-        (SqlValidatorWithHints) tester.getValidator();
-    SqlAdvisor advisor = tester.getFactory().createAdvisor(validator);
+    SqlAdvisor advisor = tester.getFactory().createAdvisor();
 
     SqlParserUtil.StringAndPos sap = SqlParserUtil.findPos(sql);
     String actual = advisor.simplifySql(sap.sql, sap.cursor);
@@ -467,9 +458,7 @@ public class SqlAdvisorTest extends SqlValidatorTestCase {
       String sql,
       String expectedResults,
       String expectedWord) {
-    SqlValidatorWithHints validator =
-        (SqlValidatorWithHints) tester.getValidator();
-    SqlAdvisor advisor = tester.getFactory().createAdvisor(validator);
+    SqlAdvisor advisor = tester.getFactory().createAdvisor();
 
     SqlParserUtil.StringAndPos sap = SqlParserUtil.findPos(sql);
     final String[] replaced = {null};
@@ -527,7 +516,7 @@ public class SqlAdvisorTest extends SqlValidatorTestCase {
   }
 
   @Override public SqlTester getTester() {
-    return new SqlTesterImpl(new AdvisorTesterFactory());
+    return new SqlTesterImpl(ADVISOR_TEST_FACTORY);
   }
 
   /**
@@ -1234,29 +1223,6 @@ public class SqlAdvisorTest extends SqlValidatorTestCase {
     simplified = "SELECT * FROM emp GROUP BY _suggest_";
     assertSimplify(sql, simplified);
   }
-
-  /** Factory that creates testers. */
-  private static class AdvisorTesterFactory extends DelegatingSqlTestFactory {
-    AdvisorTesterFactory() {
-      super(DefaultSqlTestFactory.INSTANCE);
-    }
-
-    @Override public SqlValidator getValidator(SqlTestFactory factory) {
-      final RelDataTypeFactory typeFactory =
-          new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
-      final SqlConformance conformance = (SqlConformance) get("conformance");
-      final boolean caseSensitive = (Boolean) factory.get("caseSensitive");
-      return new SqlAdvisorValidator(
-          SqlStdOperatorTable.instance(),
-          new MockCatalogReader(typeFactory, caseSensitive).init(),
-          typeFactory,
-          conformance);
-    }
-
-    @Override public SqlAdvisor createAdvisor(SqlValidatorWithHints validator) {
-      return new SqlAdvisor(validator);
-    }
-  }
 }
 
 // End SqlAdvisorTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 778715c..903504c 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -7641,7 +7641,7 @@ public abstract class SqlOperatorBaseTest {
   }
 
   public static SqlTester tester() {
-    return new TesterImpl(DefaultSqlTestFactory.INSTANCE);
+    return new TesterImpl(SqlTestFactory.INSTANCE);
   }
 
   /**
@@ -7672,16 +7672,8 @@ public abstract class SqlOperatorBaseTest {
       }
     }
 
-    @Override protected TesterImpl with(final String name2, final Object value) {
-      return new TesterImpl(
-          new DelegatingSqlTestFactory(factory) {
-            @Override public Object get(String name) {
-              if (name.equals(name2)) {
-                return value;
-              }
-              return super.get(name);
-            }
-          });
+    @Override protected TesterImpl with(final String name, final Object value) {
+      return new TesterImpl(factory.with(name, value));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/sql/test/SqlTestFactory.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlTestFactory.java b/core/src/test/java/org/apache/calcite/sql/test/SqlTestFactory.java
index f4dd25a..7269c8a 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlTestFactory.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlTestFactory.java
@@ -16,27 +16,184 @@
  */
 package org.apache.calcite.sql.test;
 
-import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.avatica.util.Casing;
+import org.apache.calcite.avatica.util.Quoting;
+import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
+import org.apache.calcite.rel.type.DelegatingTypeSystem;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.sql.SqlOperatorTable;
 import org.apache.calcite.sql.advise.SqlAdvisor;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.validate.SqlConformance;
+import org.apache.calcite.sql.validate.SqlConformanceEnum;
 import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
+import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.sql.validate.SqlValidatorWithHints;
-import org.apache.calcite.test.MockCatalogReader;
+import org.apache.calcite.test.CalciteAssert;
+import org.apache.calcite.test.MockSqlOperatorTable;
+import org.apache.calcite.test.catalog.MockCatalogReader;
+import org.apache.calcite.test.catalog.MockCatalogReaderSimple;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedMap;
+
+import java.util.Map;
+import java.util.Objects;
 
 /**
-* Creates the objects needed to run a SQL parsing or validation test.
+ * Default implementation of {@link SqlTestFactory}.
  *
- * @see org.apache.calcite.sql.test.SqlTester
+ * <p>Suitable for most tests. If you want different behavior, you can extend;
+ * if you want a factory with different properties (e.g. SQL conformance level
+ * or identifier quoting), use {@link #with(String, Object)} to create a new factory.</p>
 */
-public interface SqlTestFactory {
-  MockCatalogReader createCatalogReader(SqlTestFactory testFactory,
-      JavaTypeFactory typeFactory);
-  SqlOperatorTable createOperatorTable(SqlTestFactory factory);
-  SqlParser createParser(SqlTestFactory factory, String sql);
-  SqlValidator getValidator(SqlTestFactory factory);
-  SqlAdvisor createAdvisor(SqlValidatorWithHints validator);
-  Object get(String name);
+public class SqlTestFactory {
+  public static final ImmutableMap<String, Object> DEFAULT_OPTIONS =
+      ImmutableSortedMap.<String, Object>naturalOrder()
+          .put("quoting", Quoting.DOUBLE_QUOTE)
+          .put("quotedCasing", Casing.UNCHANGED)
+          .put("unquotedCasing", Casing.TO_UPPER)
+          .put("caseSensitive", true)
+          .put("conformance", SqlConformanceEnum.DEFAULT)
+          .put("operatorTable", SqlStdOperatorTable.instance())
+          .put("connectionFactory",
+              CalciteAssert.EMPTY_CONNECTION_FACTORY
+                  .with(
+                      new CalciteAssert.AddSchemaSpecPostProcessor(
+                          CalciteAssert.SchemaSpec.HR)))
+          .build();
+
+  public static final SqlTestFactory INSTANCE =
+      new SqlTestFactory();
+
+  private final ImmutableMap<String, Object> options;
+  private final MockCatalogReaderFactory catalogReaderFactory;
+  private final ValidatorFactory validatorFactory;
+
+  private final RelDataTypeFactory typeFactory;
+  private final SqlOperatorTable operatorTable;
+  private final SqlValidatorCatalogReader catalogReader;
+  private final SqlParser.Config parserConfig;
+
+  protected SqlTestFactory() {
+    this(DEFAULT_OPTIONS, MockCatalogReaderSimple::new, SqlValidatorUtil::newValidator);
+  }
+
+  protected SqlTestFactory(ImmutableMap<String, Object> options,
+      MockCatalogReaderFactory catalogReaderFactory,
+      ValidatorFactory validatorFactory) {
+    this.options = options;
+    this.catalogReaderFactory = catalogReaderFactory;
+    this.validatorFactory = validatorFactory;
+    this.operatorTable = createOperatorTable((SqlOperatorTable) options.get("operatorTable"));
+    this.typeFactory = createTypeFactory((SqlConformance) options.get("conformance"));
+    Boolean caseSensitive = (Boolean) options.get("caseSensitive");
+    this.catalogReader = catalogReaderFactory.create(typeFactory, caseSensitive).init();
+    this.parserConfig = createParserConfig(options);
+  }
+
+  public static MockCatalogReader createCatalogReader(
+      RelDataTypeFactory typeFactory,
+      boolean caseSensitive) {
+    return new MockCatalogReaderSimple(typeFactory, caseSensitive).init();
+  }
+
+  private static SqlOperatorTable createOperatorTable(SqlOperatorTable opTab0) {
+    MockSqlOperatorTable opTab = new MockSqlOperatorTable(opTab0);
+    MockSqlOperatorTable.addRamp(opTab);
+    return opTab;
+  }
+
+  public SqlParser createParser(String sql) {
+    return SqlParser.create(sql, parserConfig);
+  }
+
+  public static SqlParser.Config createParserConfig(ImmutableMap<String, Object> options) {
+    return SqlParser.configBuilder()
+        .setQuoting((Quoting) options.get("quoting"))
+        .setUnquotedCasing((Casing) options.get("unquotedCasing"))
+        .setQuotedCasing((Casing) options.get("quotedCasing"))
+        .setConformance((SqlConformance) options.get("conformance"))
+        .build();
+  }
+
+  public SqlValidator getValidator() {
+    final SqlConformance conformance =
+        (SqlConformance) options.get("conformance");
+    return validatorFactory.create(operatorTable, catalogReader, typeFactory, conformance);
+  }
+
+  public SqlAdvisor createAdvisor() {
+    SqlValidator validator = getValidator();
+    if (validator instanceof SqlValidatorWithHints) {
+      return new SqlAdvisor((SqlValidatorWithHints) validator);
+    }
+    throw new UnsupportedOperationException(
+        "Validator should implement SqlValidatorWithHints, actual validator is " + validator);
+  }
+
+  public SqlTestFactory with(String name, Object value) {
+    if (Objects.equals(value, options.get(name))) {
+      return this;
+    }
+    ImmutableMap.Builder<String, Object> builder = ImmutableSortedMap.naturalOrder();
+    // Protect from IllegalArgumentException: Multiple entries with same key
+    for (Map.Entry<String, Object> entry : options.entrySet()) {
+      if (name.equals(entry.getKey())) {
+        continue;
+      }
+      builder.put(entry);
+    }
+    builder.put(name, value);
+    return new SqlTestFactory(builder.build(), catalogReaderFactory, validatorFactory);
+  }
+
+  public SqlTestFactory withCatalogReader(MockCatalogReaderFactory newCatalogReaderFactory) {
+    return new SqlTestFactory(options, newCatalogReaderFactory, validatorFactory);
+  }
+
+  public SqlTestFactory withValidator(ValidatorFactory newValidatorFactory) {
+    return new SqlTestFactory(options, catalogReaderFactory, newValidatorFactory);
+  }
+
+  public final Object get(String name) {
+    return options.get(name);
+  }
+
+  private static RelDataTypeFactory createTypeFactory(SqlConformance conformance) {
+    RelDataTypeSystem typeSystem = RelDataTypeSystem.DEFAULT;
+    if (conformance.shouldConvertRaggedUnionTypesToVarying()) {
+      typeSystem = new DelegatingTypeSystem(typeSystem) {
+        public boolean shouldConvertRaggedUnionTypesToVarying() {
+          return true;
+        }
+      };
+    }
+    return new JavaTypeFactoryImpl(typeSystem);
+  }
+
+  /**
+   * Creates {@link SqlValidator} for tests.
+   */
+  public interface ValidatorFactory {
+    SqlValidator create(
+        SqlOperatorTable opTab,
+        SqlValidatorCatalogReader catalogReader,
+        RelDataTypeFactory typeFactory,
+        SqlConformance conformance);
+  }
+
+  /**
+   * Creates {@link MockCatalogReader} for tests.
+   * Note: {@link MockCatalogReader#init()} is to be invoked later, so a typical implementation
+   * should be via constructor reference like {@code MockCatalogReaderSimple::new}.
+   */
+  public interface MockCatalogReaderFactory {
+    MockCatalogReader create(RelDataTypeFactory typeFactory, boolean caseSensitive);
+  }
 }
 
 // End SqlTestFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java b/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
index d215b45..533cb99 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlTesterImpl.java
@@ -98,7 +98,7 @@ public class SqlTesterImpl implements SqlTester, AutoCloseable {
   }
 
   public final SqlValidator getValidator() {
-    return factory.getValidator(factory);
+    return factory.getValidator();
   }
 
   public void assertExceptionIsThrown(
@@ -163,7 +163,7 @@ public class SqlTesterImpl implements SqlTester, AutoCloseable {
   }
 
   public SqlNode parseQuery(String sql) throws SqlParseException {
-    SqlParser parser = factory.createParser(factory, sql);
+    SqlParser parser = factory.createParser(sql);
     return parser.parseQuery();
   }
 
@@ -312,16 +312,8 @@ public class SqlTesterImpl implements SqlTester, AutoCloseable {
     return with("connectionFactory", connectionFactory);
   }
 
-  protected SqlTesterImpl with(final String name2, final Object value) {
-    return new SqlTesterImpl(
-        new DelegatingSqlTestFactory(factory) {
-          @Override public Object get(String name) {
-            if (name.equals(name2)) {
-              return value;
-            }
-            return super.get(name);
-          }
-        });
+  protected SqlTesterImpl with(final String name, final Object value) {
+    return new SqlTesterImpl(factory.with(name, value));
   }
 
   // SqlTester methods

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/sql/validate/SqlValidatorUtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/validate/SqlValidatorUtilTest.java b/core/src/test/java/org/apache/calcite/sql/validate/SqlValidatorUtilTest.java
index a716002..0405308 100644
--- a/core/src/test/java/org/apache/calcite/sql/validate/SqlValidatorUtilTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/validate/SqlValidatorUtilTest.java
@@ -20,7 +20,7 @@ import org.apache.calcite.runtime.CalciteContextException;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.test.DefaultSqlTestFactory;
+import org.apache.calcite.sql.test.SqlTestFactory;
 import org.apache.calcite.sql.test.SqlTesterImpl;
 
 import com.google.common.collect.ImmutableList;
@@ -125,7 +125,7 @@ public class SqlValidatorUtilTest {
     newList.add(new SqlIdentifier(Arrays.asList("f0", "c0"), SqlParserPos.ZERO));
     newList.add(new SqlIdentifier(Arrays.asList("f0", "c0"), SqlParserPos.ZERO));
     final SqlTesterImpl tester =
-        new SqlTesterImpl(DefaultSqlTestFactory.INSTANCE);
+        new SqlTesterImpl(SqlTestFactory.INSTANCE);
     final SqlValidatorImpl validator =
         (SqlValidatorImpl) tester.getValidator();
     try {


[2/3] calcite git commit: [CALCITE-2435] tests: refactor SqlTestFactory

Posted by vl...@apache.org.
http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
deleted file mode 100644
index 9106524..0000000
--- a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java
+++ /dev/null
@@ -1,1750 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.test;
-
-import org.apache.calcite.adapter.java.JavaTypeFactory;
-import org.apache.calcite.config.CalciteConnectionConfig;
-import org.apache.calcite.jdbc.CalcitePrepare;
-import org.apache.calcite.jdbc.CalciteSchema;
-import org.apache.calcite.linq4j.Ord;
-import org.apache.calcite.linq4j.QueryProvider;
-import org.apache.calcite.linq4j.Queryable;
-import org.apache.calcite.linq4j.tree.Expression;
-import org.apache.calcite.plan.RelOptSchema;
-import org.apache.calcite.plan.RelOptTable;
-import org.apache.calcite.prepare.CalciteCatalogReader;
-import org.apache.calcite.prepare.Prepare;
-import org.apache.calcite.rel.RelCollation;
-import org.apache.calcite.rel.RelCollations;
-import org.apache.calcite.rel.RelDistribution;
-import org.apache.calcite.rel.RelDistributions;
-import org.apache.calcite.rel.RelFieldCollation;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.RelReferentialConstraint;
-import org.apache.calcite.rel.logical.LogicalFilter;
-import org.apache.calcite.rel.logical.LogicalProject;
-import org.apache.calcite.rel.logical.LogicalTableScan;
-import org.apache.calcite.rel.type.DynamicRecordTypeImpl;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeComparability;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rel.type.RelDataTypeFamily;
-import org.apache.calcite.rel.type.RelDataTypeField;
-import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
-import org.apache.calcite.rel.type.RelDataTypeImpl;
-import org.apache.calcite.rel.type.RelDataTypePrecedenceList;
-import org.apache.calcite.rel.type.RelProtoDataType;
-import org.apache.calcite.rel.type.RelRecordType;
-import org.apache.calcite.rel.type.StructKind;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexInputRef;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexUtil;
-import org.apache.calcite.schema.ColumnStrategy;
-import org.apache.calcite.schema.CustomColumnResolvingTable;
-import org.apache.calcite.schema.ExtensibleTable;
-import org.apache.calcite.schema.Path;
-import org.apache.calcite.schema.Schema;
-import org.apache.calcite.schema.SchemaPlus;
-import org.apache.calcite.schema.Schemas;
-import org.apache.calcite.schema.Statistic;
-import org.apache.calcite.schema.StreamableTable;
-import org.apache.calcite.schema.Table;
-import org.apache.calcite.schema.TableMacro;
-import org.apache.calcite.schema.TranslatableTable;
-import org.apache.calcite.schema.Wrapper;
-import org.apache.calcite.schema.impl.AbstractSchema;
-import org.apache.calcite.schema.impl.ModifiableViewTable;
-import org.apache.calcite.schema.impl.ViewTableMacro;
-import org.apache.calcite.sql.SqlAccessType;
-import org.apache.calcite.sql.SqlCall;
-import org.apache.calcite.sql.SqlCollation;
-import org.apache.calcite.sql.SqlFunction;
-import org.apache.calcite.sql.SqlIdentifier;
-import org.apache.calcite.sql.SqlIntervalQualifier;
-import org.apache.calcite.sql.SqlKind;
-import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.type.ObjectSqlType;
-import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.calcite.sql.validate.SqlModality;
-import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlNameMatcher;
-import org.apache.calcite.sql.validate.SqlNameMatchers;
-import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
-import org.apache.calcite.sql.validate.SqlValidatorUtil;
-import org.apache.calcite.sql2rel.InitializerContext;
-import org.apache.calcite.sql2rel.InitializerExpressionFactory;
-import org.apache.calcite.sql2rel.NullInitializerExpressionFactory;
-import org.apache.calcite.util.ImmutableBitSet;
-import org.apache.calcite.util.ImmutableIntList;
-import org.apache.calcite.util.Litmus;
-import org.apache.calcite.util.Pair;
-import org.apache.calcite.util.Util;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
-import java.lang.reflect.Type;
-import java.math.BigDecimal;
-import java.nio.charset.Charset;
-import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Mock implementation of {@link SqlValidatorCatalogReader} which returns tables
- * "EMP", "DEPT", "BONUS", "SALGRADE" (same as Oracle's SCOTT schema).
- * Also two streams "ORDERS", "SHIPMENTS";
- * and a view "EMP_20".
- */
-public class MockCatalogReader extends CalciteCatalogReader {
-  //~ Static fields/initializers ---------------------------------------------
-
-  static final String DEFAULT_CATALOG = "CATALOG";
-  static final String DEFAULT_SCHEMA = "SALES";
-  static final List<String> PREFIX = ImmutableList.of(DEFAULT_SCHEMA);
-
-  //~ Instance fields --------------------------------------------------------
-
-  private RelDataType addressType;
-
-  //~ Constructors -----------------------------------------------------------
-
-  /**
-   * Creates a MockCatalogReader.
-   *
-   * <p>Caller must then call {@link #init} to populate with data.</p>
-   *
-   * @param typeFactory Type factory
-   */
-  public MockCatalogReader(RelDataTypeFactory typeFactory,
-      boolean caseSensitive) {
-    super(CalciteSchema.createRootSchema(false, true, DEFAULT_CATALOG),
-        SqlNameMatchers.withCaseSensitive(caseSensitive),
-        ImmutableList.of(PREFIX, ImmutableList.of()),
-        typeFactory, null);
-  }
-
-  @Override public boolean isCaseSensitive() {
-    return nameMatcher.isCaseSensitive();
-  }
-
-  public SqlNameMatcher nameMatcher() {
-    return nameMatcher;
-  }
-
-  /**
-   * Initializes this catalog reader.
-   */
-  public MockCatalogReader init() {
-    final Fixture f = new Fixture();
-    addressType = f.addressType;
-
-    // Register "SALES" schema.
-    MockSchema salesSchema = new MockSchema("SALES");
-    registerSchema(salesSchema);
-
-    // Register "EMP" table with customer InitializerExpressionFactory
-    // to check whether newDefaultValue method called or not.
-    final InitializerExpressionFactory countingInitializerExpressionFactory =
-        new CountingFactory(ImmutableList.of("DEPTNO"));
-
-    registerType(
-        ImmutableList.of(salesSchema.getCatalogName(), salesSchema.getName(),
-            "customBigInt"),
-        typeFactory -> typeFactory.createSqlType(SqlTypeName.BIGINT));
-
-    // Register "EMP" table.
-    final MockTable empTable =
-        MockTable.create(this, salesSchema, "EMP", false, 14, null,
-            countingInitializerExpressionFactory);
-    empTable.addColumn("EMPNO", f.intType, true);
-    empTable.addColumn("ENAME", f.varchar20Type);
-    empTable.addColumn("JOB", f.varchar10Type);
-    empTable.addColumn("MGR", f.intTypeNull);
-    empTable.addColumn("HIREDATE", f.timestampType);
-    empTable.addColumn("SAL", f.intType);
-    empTable.addColumn("COMM", f.intType);
-    empTable.addColumn("DEPTNO", f.intType);
-    empTable.addColumn("SLACKER", f.booleanType);
-    registerTable(empTable);
-
-    // Register "EMPNULLABLES" table with nullable columns.
-    final MockTable empNullablesTable =
-        MockTable.create(this, salesSchema, "EMPNULLABLES", false, 14);
-    empNullablesTable.addColumn("EMPNO", f.intType, true);
-    empNullablesTable.addColumn("ENAME", f.varchar20Type);
-    empNullablesTable.addColumn("JOB", f.varchar10TypeNull);
-    empNullablesTable.addColumn("MGR", f.intTypeNull);
-    empNullablesTable.addColumn("HIREDATE", f.timestampTypeNull);
-    empNullablesTable.addColumn("SAL", f.intTypeNull);
-    empNullablesTable.addColumn("COMM", f.intTypeNull);
-    empNullablesTable.addColumn("DEPTNO", f.intTypeNull);
-    empNullablesTable.addColumn("SLACKER", f.booleanTypeNull);
-    registerTable(empNullablesTable);
-
-    // Register "EMPDEFAULTS" table with default values for some columns.
-    final MockTable empDefaultsTable =
-        MockTable.create(this, salesSchema, "EMPDEFAULTS", false, 14, null,
-            new EmpInitializerExpressionFactory());
-    empDefaultsTable.addColumn("EMPNO", f.intType, true);
-    empDefaultsTable.addColumn("ENAME", f.varchar20Type);
-    empDefaultsTable.addColumn("JOB", f.varchar10TypeNull);
-    empDefaultsTable.addColumn("MGR", f.intTypeNull);
-    empDefaultsTable.addColumn("HIREDATE", f.timestampTypeNull);
-    empDefaultsTable.addColumn("SAL", f.intTypeNull);
-    empDefaultsTable.addColumn("COMM", f.intTypeNull);
-    empDefaultsTable.addColumn("DEPTNO", f.intTypeNull);
-    empDefaultsTable.addColumn("SLACKER", f.booleanTypeNull);
-    registerTable(empDefaultsTable);
-
-    // Register "EMP_B" table. As "EMP", birth with a "BIRTHDATE" column.
-    final MockTable empBTable =
-        MockTable.create(this, salesSchema, "EMP_B", false, 14);
-    empBTable.addColumn("EMPNO", f.intType, true);
-    empBTable.addColumn("ENAME", f.varchar20Type);
-    empBTable.addColumn("JOB", f.varchar10Type);
-    empBTable.addColumn("MGR", f.intTypeNull);
-    empBTable.addColumn("HIREDATE", f.timestampType);
-    empBTable.addColumn("SAL", f.intType);
-    empBTable.addColumn("COMM", f.intType);
-    empBTable.addColumn("DEPTNO", f.intType);
-    empBTable.addColumn("SLACKER", f.booleanType);
-    empBTable.addColumn("BIRTHDATE", f.dateType);
-    registerTable(empBTable);
-
-    // Register "DEPT" table.
-    MockTable deptTable = MockTable.create(this, salesSchema, "DEPT", false, 4);
-    deptTable.addColumn("DEPTNO", f.intType, true);
-    deptTable.addColumn("NAME", f.varchar10Type);
-    registerTable(deptTable);
-
-    // Register "DEPT_NESTED" table.
-    MockTable deptNestedTable =
-        MockTable.create(this, salesSchema, "DEPT_NESTED", false, 4);
-    deptNestedTable.addColumn("DEPTNO", f.intType, true);
-    deptNestedTable.addColumn("NAME", f.varchar10Type);
-    deptNestedTable.addColumn("SKILL", f.skillRecordType);
-    deptNestedTable.addColumn("EMPLOYEES", f.empListType);
-    registerTable(deptNestedTable);
-
-    // Register "BONUS" table.
-    MockTable bonusTable =
-        MockTable.create(this, salesSchema, "BONUS", false, 0);
-    bonusTable.addColumn("ENAME", f.varchar20Type);
-    bonusTable.addColumn("JOB", f.varchar10Type);
-    bonusTable.addColumn("SAL", f.intType);
-    bonusTable.addColumn("COMM", f.intType);
-    registerTable(bonusTable);
-
-    // Register "SALGRADE" table.
-    MockTable salgradeTable =
-        MockTable.create(this, salesSchema, "SALGRADE", false, 5);
-    salgradeTable.addColumn("GRADE", f.intType, true);
-    salgradeTable.addColumn("LOSAL", f.intType);
-    salgradeTable.addColumn("HISAL", f.intType);
-    registerTable(salgradeTable);
-
-    // Register "EMP_ADDRESS" table
-    MockTable contactAddressTable =
-        MockTable.create(this, salesSchema, "EMP_ADDRESS", false, 26);
-    contactAddressTable.addColumn("EMPNO", f.intType, true);
-    contactAddressTable.addColumn("HOME_ADDRESS", addressType);
-    contactAddressTable.addColumn("MAILING_ADDRESS", addressType);
-    registerTable(contactAddressTable);
-
-    // Register "DYNAMIC" schema.
-    MockSchema dynamicSchema = new MockSchema("DYNAMIC");
-    registerSchema(dynamicSchema);
-
-    MockTable nationTable =
-        new MockDynamicTable(this, dynamicSchema.getCatalogName(),
-            dynamicSchema.getName(), "NATION", false, 100);
-    registerTable(nationTable);
-
-    MockTable customerTable =
-        new MockDynamicTable(this, dynamicSchema.getCatalogName(),
-            dynamicSchema.getName(), "CUSTOMER", false, 100);
-    registerTable(customerTable);
-
-    // Register "CUSTOMER" schema.
-    MockSchema customerSchema = new MockSchema("CUSTOMER");
-    registerSchema(customerSchema);
-
-    // Register "CONTACT" table.
-    MockTable contactTable = MockTable.create(this, customerSchema, "CONTACT",
-        false, 1000);
-    contactTable.addColumn("CONTACTNO", f.intType);
-    contactTable.addColumn("FNAME", f.varchar10Type);
-    contactTable.addColumn("LNAME", f.varchar10Type);
-    contactTable.addColumn("EMAIL", f.varchar20Type);
-    contactTable.addColumn("COORD", f.rectilinearCoordType);
-    registerTable(contactTable);
-
-    // Register "CONTACT_PEEK" table. The
-    MockTable contactPeekTable =
-        MockTable.create(this, customerSchema, "CONTACT_PEEK", false, 1000);
-    contactPeekTable.addColumn("CONTACTNO", f.intType);
-    contactPeekTable.addColumn("FNAME", f.varchar10Type);
-    contactPeekTable.addColumn("LNAME", f.varchar10Type);
-    contactPeekTable.addColumn("EMAIL", f.varchar20Type);
-    contactPeekTable.addColumn("COORD", f.rectilinearPeekCoordType);
-    contactPeekTable.addColumn("COORD_NE", f.rectilinearPeekNoExpandCoordType);
-    registerTable(contactPeekTable);
-
-    // Register "ACCOUNT" table.
-    MockTable accountTable = MockTable.create(this, customerSchema, "ACCOUNT",
-        false, 457);
-    accountTable.addColumn("ACCTNO", f.intType);
-    accountTable.addColumn("TYPE", f.varchar20Type);
-    accountTable.addColumn("BALANCE", f.intType);
-    registerTable(accountTable);
-
-    // Register "ORDERS" stream.
-    MockTable ordersStream = MockTable.create(this, salesSchema, "ORDERS",
-        true, Double.POSITIVE_INFINITY);
-    ordersStream.addColumn("ROWTIME", f.timestampType);
-    ordersStream.addMonotonic("ROWTIME");
-    ordersStream.addColumn("PRODUCTID", f.intType);
-    ordersStream.addColumn("ORDERID", f.intType);
-    registerTable(ordersStream);
-
-    // Register "SHIPMENTS" stream.
-    // "ROWTIME" is not column 0, just to mix things up.
-    MockTable shipmentsStream = MockTable.create(this, salesSchema, "SHIPMENTS",
-        true, Double.POSITIVE_INFINITY);
-    shipmentsStream.addColumn("ORDERID", f.intType);
-    shipmentsStream.addColumn("ROWTIME", f.timestampType);
-    shipmentsStream.addMonotonic("ROWTIME");
-    registerTable(shipmentsStream);
-
-    // Register "PRODUCTS" table.
-    MockTable productsTable = MockTable.create(this, salesSchema, "PRODUCTS",
-        false, 200D);
-    productsTable.addColumn("PRODUCTID", f.intType);
-    productsTable.addColumn("NAME", f.varchar20Type);
-    productsTable.addColumn("SUPPLIERID", f.intType);
-    registerTable(productsTable);
-
-    // Register "SUPPLIERS" table.
-    MockTable suppliersTable = MockTable.create(this, salesSchema, "SUPPLIERS",
-        false, 10D);
-    suppliersTable.addColumn("SUPPLIERID", f.intType);
-    suppliersTable.addColumn("NAME", f.varchar20Type);
-    suppliersTable.addColumn("CITY", f.intType);
-    registerTable(suppliersTable);
-
-    // Register "EMP_20" and "EMPNULLABLES_20 views.
-    // Same columns as "EMP" amd "EMPNULLABLES",
-    // but "DEPTNO" not visible and set to 20 by default
-    // and "SAL" is visible but must be greater than 1000,
-    // which is the equivalent of:
-    //   SELECT EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, SLACKER
-    //   FROM EMP
-    //   WHERE DEPTNO = 20 AND SAL > 1000
-    final ImmutableIntList m0 = ImmutableIntList.of(0, 1, 2, 3, 4, 5, 6, 8);
-    MockTable emp20View =
-        new MockViewTable(this, salesSchema.getCatalogName(), salesSchema.name,
-            "EMP_20", false, 600, empTable, m0, null,
-            NullInitializerExpressionFactory.INSTANCE) {
-          public RexNode getConstraint(RexBuilder rexBuilder,
-              RelDataType tableRowType) {
-            final RelDataTypeField deptnoField =
-                tableRowType.getFieldList().get(7);
-            final RelDataTypeField salField =
-                tableRowType.getFieldList().get(5);
-            final List<RexNode> nodes = Arrays.asList(
-                rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
-                    rexBuilder.makeInputRef(deptnoField.getType(),
-                        deptnoField.getIndex()),
-                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(20L),
-                        deptnoField.getType())),
-                rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN,
-                    rexBuilder.makeInputRef(salField.getType(),
-                        salField.getIndex()),
-                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(1000L),
-                        salField.getType())));
-            return RexUtil.composeConjunction(rexBuilder, nodes, false);
-          }
-        };
-    salesSchema.addTable(Util.last(emp20View.getQualifiedName()));
-    emp20View.addColumn("EMPNO", f.intType);
-    emp20View.addColumn("ENAME", f.varchar20Type);
-    emp20View.addColumn("JOB", f.varchar10Type);
-    emp20View.addColumn("MGR", f.intTypeNull);
-    emp20View.addColumn("HIREDATE", f.timestampType);
-    emp20View.addColumn("SAL", f.intType);
-    emp20View.addColumn("COMM", f.intType);
-    emp20View.addColumn("SLACKER", f.booleanType);
-    registerTable(emp20View);
-
-    MockTable empNullables20View =
-        new MockViewTable(this, salesSchema.getCatalogName(), salesSchema.name,
-            "EMPNULLABLES_20", false, 600, empNullablesTable, m0, null,
-            NullInitializerExpressionFactory.INSTANCE) {
-          public RexNode getConstraint(RexBuilder rexBuilder,
-              RelDataType tableRowType) {
-            final RelDataTypeField deptnoField =
-                tableRowType.getFieldList().get(7);
-            final RelDataTypeField salField =
-                tableRowType.getFieldList().get(5);
-            final List<RexNode> nodes = Arrays.asList(
-                rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
-                    rexBuilder.makeInputRef(deptnoField.getType(),
-                        deptnoField.getIndex()),
-                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(20L),
-                        deptnoField.getType())),
-                rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN,
-                    rexBuilder.makeInputRef(salField.getType(),
-                        salField.getIndex()),
-                    rexBuilder.makeExactLiteral(BigDecimal.valueOf(1000L),
-                        salField.getType())));
-            return RexUtil.composeConjunction(rexBuilder, nodes, false);
-          }
-        };
-    salesSchema.addTable(Util.last(empNullables20View.getQualifiedName()));
-    empNullables20View.addColumn("EMPNO", f.intType);
-    empNullables20View.addColumn("ENAME", f.varchar20Type);
-    empNullables20View.addColumn("JOB", f.varchar10TypeNull);
-    empNullables20View.addColumn("MGR", f.intTypeNull);
-    empNullables20View.addColumn("HIREDATE", f.timestampTypeNull);
-    empNullables20View.addColumn("SAL", f.intTypeNull);
-    empNullables20View.addColumn("COMM", f.intTypeNull);
-    empNullables20View.addColumn("SLACKER", f.booleanTypeNull);
-    registerTable(empNullables20View);
-
-    MockSchema structTypeSchema = new MockSchema("STRUCT");
-    registerSchema(structTypeSchema);
-    final List<CompoundNameColumn> columns = Arrays.asList(
-        new CompoundNameColumn("", "K0", f.varchar20Type),
-        new CompoundNameColumn("", "C1", f.varchar20Type),
-        new CompoundNameColumn("F1", "A0", f.intType),
-        new CompoundNameColumn("F2", "A0", f.booleanType),
-        new CompoundNameColumn("F0", "C0", f.intType),
-        new CompoundNameColumn("F1", "C0", f.intTypeNull),
-        new CompoundNameColumn("F0", "C1", f.intType),
-        new CompoundNameColumn("F1", "C2", f.intType),
-        new CompoundNameColumn("F2", "C3", f.intType));
-    final CompoundNameColumnResolver structTypeTableResolver =
-        new CompoundNameColumnResolver(columns, "F0");
-    final MockTable structTypeTable =
-        MockTable.create(this, structTypeSchema, "T", false, 100,
-            structTypeTableResolver);
-    for (CompoundNameColumn column : columns) {
-      structTypeTable.addColumn(column.getName(), column.type);
-    }
-    registerTable(structTypeTable);
-
-    final List<CompoundNameColumn> columnsNullable = Arrays.asList(
-        new CompoundNameColumn("", "K0", f.varchar20TypeNull),
-        new CompoundNameColumn("", "C1", f.varchar20TypeNull),
-        new CompoundNameColumn("F1", "A0", f.intTypeNull),
-        new CompoundNameColumn("F2", "A0", f.booleanTypeNull),
-        new CompoundNameColumn("F0", "C0", f.intTypeNull),
-        new CompoundNameColumn("F1", "C0", f.intTypeNull),
-        new CompoundNameColumn("F0", "C1", f.intTypeNull),
-        new CompoundNameColumn("F1", "C2", f.intType),
-        new CompoundNameColumn("F2", "C3", f.intTypeNull));
-    final MockTable structNullableTypeTable =
-        MockTable.create(this, structTypeSchema, "T_NULLABLES", false, 100,
-            structTypeTableResolver);
-    for (CompoundNameColumn column : columnsNullable) {
-      structNullableTypeTable.addColumn(column.getName(), column.type);
-    }
-    registerTable(structNullableTypeTable);
-
-    // Register "STRUCT.T_10" view.
-    // Same columns as "STRUCT.T",
-    // but "F0.C0" is set to 10 by default,
-    // which is the equivalent of:
-    //   SELECT *
-    //   FROM T
-    //   WHERE F0.C0 = 10
-    // This table uses MockViewTable which does not populate the constrained columns with default
-    // values on INSERT.
-    final ImmutableIntList m1 = ImmutableIntList.of(0, 1, 2, 3, 4, 5, 6, 7, 8);
-    MockTable struct10View =
-        new MockViewTable(this, structTypeSchema.getCatalogName(),
-            structTypeSchema.name, "T_10", false, 20, structTypeTable,
-            m1, structTypeTableResolver,
-            NullInitializerExpressionFactory.INSTANCE) {
-          @Override public RexNode getConstraint(RexBuilder rexBuilder,
-              RelDataType tableRowType) {
-            final RelDataTypeField c0Field =
-                tableRowType.getFieldList().get(4);
-            return rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
-                rexBuilder.makeInputRef(c0Field.getType(),
-                    c0Field.getIndex()),
-                rexBuilder.makeExactLiteral(BigDecimal.valueOf(10L),
-                    c0Field.getType()));
-          }
-        };
-    structTypeSchema.addTable(Util.last(struct10View.getQualifiedName()));
-    for (CompoundNameColumn column : columns) {
-      struct10View.addColumn(column.getName(), column.type);
-    }
-    registerTable(struct10View);
-    registerTablesWithRollUp(salesSchema, f);
-    return this;
-  }
-
-  private void registerTablesWithRollUp(MockSchema schema, Fixture f) {
-    // Register "EMP_R" table. Contains a rolled up column.
-    final MockTable empRolledTable =
-            MockTable.create(this, schema, "EMP_R", false, 14);
-    empRolledTable.addColumn("EMPNO", f.intType, true);
-    empRolledTable.addColumn("DEPTNO", f.intType);
-    empRolledTable.addColumn("SLACKER", f.booleanType);
-    empRolledTable.addColumn("SLACKINGMIN", f.intType);
-    empRolledTable.registerRolledUpColumn("SLACKINGMIN");
-    registerTable(empRolledTable);
-
-    // Register the "DEPT_R" table. Doesn't contain a rolled up column,
-    // but is useful for testing join
-    MockTable deptSlackingTable = MockTable.create(this, schema, "DEPT_R", false, 4);
-    deptSlackingTable.addColumn("DEPTNO", f.intType, true);
-    deptSlackingTable.addColumn("SLACKINGMIN", f.intType);
-    registerTable(deptSlackingTable);
-
-    // Register nested schema NEST that contains table with a rolled up column.
-    MockSchema nestedSchema = new MockSchema("NEST");
-    registerNestedSchema(schema, nestedSchema);
-
-    // Register "EMP_R" table which contains a rolled up column in NEST schema.
-    ImmutableList<String> tablePath =
-        ImmutableList.of(schema.getCatalogName(), schema.name, nestedSchema.name, "EMP_R");
-    final MockTable nestedEmpRolledTable = MockTable.create(this, tablePath, false, 14);
-    nestedEmpRolledTable.addColumn("EMPNO", f.intType, true);
-    nestedEmpRolledTable.addColumn("DEPTNO", f.intType);
-    nestedEmpRolledTable.addColumn("SLACKER", f.booleanType);
-    nestedEmpRolledTable.addColumn("SLACKINGMIN", f.intType);
-    nestedEmpRolledTable.registerRolledUpColumn("SLACKINGMIN");
-    registerTable(nestedEmpRolledTable);
-  }
-
-  /** Adds some extra tables to the mock catalog. These increase the time and
-   * complexity of initializing the catalog (because they contain views whose
-   * SQL needs to be parsed) and so are not used for all tests. */
-  public MockCatalogReader init2() {
-    MockSchema salesSchema = new MockSchema("SALES");
-    // Same as "EMP_20" except it uses ModifiableViewTable which populates
-    // constrained columns with default values on INSERT and has a single constraint on DEPTNO.
-    List<String> empModifiableViewNames = ImmutableList.of(
-        salesSchema.getCatalogName(), salesSchema.name, "EMP_MODIFIABLEVIEW");
-    TableMacro empModifiableViewMacro = MockModifiableViewRelOptTable.viewMacro(rootSchema,
-        "select EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, SLACKER from EMPDEFAULTS"
-            + " where DEPTNO = 20", empModifiableViewNames.subList(0, 2),
-        ImmutableList.of(empModifiableViewNames.get(2)), true);
-    TranslatableTable empModifiableView = empModifiableViewMacro.apply(ImmutableList.of());
-    MockModifiableViewRelOptTable mockEmpViewTable = MockModifiableViewRelOptTable.create(
-        (MockModifiableViewRelOptTable.MockModifiableViewTable) empModifiableView, this,
-        empModifiableViewNames.get(0), empModifiableViewNames.get(1),
-        empModifiableViewNames.get(2), false, 20, null);
-    registerTable(mockEmpViewTable);
-
-    // Same as "EMP_MODIFIABLEVIEW" except that all columns are in the view, columns are reordered,
-    // and there is an `extra` extended column.
-    List<String> empModifiableViewNames2 = ImmutableList.of(
-        salesSchema.getCatalogName(), salesSchema.name, "EMP_MODIFIABLEVIEW2");
-    TableMacro empModifiableViewMacro2 = MockModifiableViewRelOptTable.viewMacro(rootSchema,
-        "select ENAME, EMPNO, JOB, DEPTNO, SLACKER, SAL, EXTRA, HIREDATE, MGR, COMM"
-            + " from EMPDEFAULTS extend (EXTRA boolean)"
-            + " where DEPTNO = 20", empModifiableViewNames2.subList(0, 2),
-        ImmutableList.of(empModifiableViewNames.get(2)), true);
-    TranslatableTable empModifiableView2 = empModifiableViewMacro2.apply(ImmutableList.of());
-    MockModifiableViewRelOptTable mockEmpViewTable2 = MockModifiableViewRelOptTable.create(
-        (MockModifiableViewRelOptTable.MockModifiableViewTable) empModifiableView2, this,
-        empModifiableViewNames2.get(0), empModifiableViewNames2.get(1),
-        empModifiableViewNames2.get(2), false, 20, null);
-    registerTable(mockEmpViewTable2);
-
-    // Same as "EMP_MODIFIABLEVIEW" except that comm is not in the view.
-    List<String> empModifiableViewNames3 = ImmutableList.of(
-        salesSchema.getCatalogName(), salesSchema.name, "EMP_MODIFIABLEVIEW3");
-    TableMacro empModifiableViewMacro3 = MockModifiableViewRelOptTable.viewMacro(rootSchema,
-        "select EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, SLACKER from EMPDEFAULTS"
-            + " where DEPTNO = 20", empModifiableViewNames3.subList(0, 2),
-        ImmutableList.of(empModifiableViewNames3.get(2)), true);
-    TranslatableTable empModifiableView3 = empModifiableViewMacro3.apply(ImmutableList.of());
-    MockModifiableViewRelOptTable mockEmpViewTable3 = MockModifiableViewRelOptTable.create(
-        (MockModifiableViewRelOptTable.MockModifiableViewTable) empModifiableView3, this,
-        empModifiableViewNames3.get(0), empModifiableViewNames3.get(1),
-        empModifiableViewNames3.get(2), false, 20, null);
-    registerTable(mockEmpViewTable3);
-
-    MockSchema structTypeSchema = new MockSchema("STRUCT");
-    registerSchema(structTypeSchema);
-    final Fixture f = new Fixture();
-    final List<CompoundNameColumn> columnsExtended = Arrays.asList(
-        new CompoundNameColumn("", "K0", f.varchar20TypeNull),
-        new CompoundNameColumn("", "C1", f.varchar20TypeNull),
-        new CompoundNameColumn("F0", "C0", f.intType),
-        new CompoundNameColumn("F1", "C1", f.intTypeNull));
-    final List<CompoundNameColumn> extendedColumns =
-        new ArrayList<CompoundNameColumn>(columnsExtended);
-    extendedColumns.add(new CompoundNameColumn("F2", "C2", f.varchar20Type));
-    final CompoundNameColumnResolver structExtendedTableResolver =
-        new CompoundNameColumnResolver(extendedColumns, "F0");
-    final MockTable structExtendedTypeTable =
-        MockTable.create(this, structTypeSchema, "T_EXTEND", false, 100,
-            structExtendedTableResolver);
-    for (CompoundNameColumn column : columnsExtended) {
-      structExtendedTypeTable.addColumn(column.getName(), column.type);
-    }
-    registerTable(structExtendedTypeTable);
-
-    return this;
-  }
-
-  //~ Methods ----------------------------------------------------------------
-
-  protected void registerType(final List<String> names, final RelProtoDataType relProtoDataType) {
-    assert names.get(0).equals(DEFAULT_CATALOG);
-    final List<String> schemaPath = Util.skipLast(names);
-    final CalciteSchema schema = SqlValidatorUtil.getSchema(rootSchema,
-        schemaPath, SqlNameMatchers.withCaseSensitive(true));
-    schema.add(Util.last(names), relProtoDataType);
-  }
-
-  protected void registerTable(final MockTable table) {
-    table.onRegister(typeFactory);
-    final WrapperTable wrapperTable = new WrapperTable(table);
-    if (table.stream) {
-      registerTable(table.names,
-          new StreamableWrapperTable(table) {
-            public Table stream() {
-              return wrapperTable;
-            }
-          });
-    } else {
-      registerTable(table.names, wrapperTable);
-    }
-  }
-
-  private void registerTable(final List<String> names, final Table table) {
-    assert names.get(0).equals(DEFAULT_CATALOG);
-    final List<String> schemaPath = Util.skipLast(names);
-    final String tableName = Util.last(names);
-    final CalciteSchema schema = SqlValidatorUtil.getSchema(rootSchema,
-        schemaPath, SqlNameMatchers.withCaseSensitive(true));
-    schema.add(tableName, table);
-  }
-
-  protected void registerSchema(MockSchema schema) {
-    rootSchema.add(schema.name, new AbstractSchema());
-  }
-
-  private void registerNestedSchema(MockSchema parentSchema, MockSchema schema) {
-    rootSchema.getSubSchema(parentSchema.getName(), true)
-        .add(schema.name, new AbstractSchema());
-  }
-
-  public RelDataType getNamedType(SqlIdentifier typeName) {
-    if (typeName.equalsDeep(addressType.getSqlIdentifier(), Litmus.IGNORE)) {
-      return addressType;
-    } else {
-      return super.getNamedType(typeName);
-    }
-  }
-
-  private static List<RelCollation> deduceMonotonicity(
-      Prepare.PreparingTable table) {
-    final List<RelCollation> collationList = new ArrayList<>();
-
-    // Deduce which fields the table is sorted on.
-    int i = -1;
-    for (RelDataTypeField field : table.getRowType().getFieldList()) {
-      ++i;
-      final SqlMonotonicity monotonicity =
-          table.getMonotonicity(field.getName());
-      if (monotonicity != SqlMonotonicity.NOT_MONOTONIC) {
-        final RelFieldCollation.Direction direction =
-            monotonicity.isDecreasing()
-                ? RelFieldCollation.Direction.DESCENDING
-                : RelFieldCollation.Direction.ASCENDING;
-        collationList.add(
-            RelCollations.of(
-                new RelFieldCollation(i, direction)));
-      }
-    }
-    return collationList;
-  }
-
-  //~ Inner Classes ----------------------------------------------------------
-
-  /** Column resolver*/
-  public interface ColumnResolver {
-    List<Pair<RelDataTypeField, List<String>>> resolveColumn(
-        RelDataType rowType, RelDataTypeFactory typeFactory, List<String> names);
-  }
-
-  /** Mock schema. */
-  public static class MockSchema {
-    private final List<String> tableNames = new ArrayList<>();
-    private String name;
-
-    public MockSchema(String name) {
-      this.name = name;
-    }
-
-    public void addTable(String name) {
-      tableNames.add(name);
-    }
-
-    public String getCatalogName() {
-      return DEFAULT_CATALOG;
-    }
-
-    public String getName() {
-      return name;
-    }
-  }
-
-  /**
-   * Mock implementation of
-   * {@link org.apache.calcite.prepare.Prepare.PreparingTable}.
-   */
-  public static class MockTable extends Prepare.AbstractPreparingTable {
-    protected final MockCatalogReader catalogReader;
-    protected final boolean stream;
-    protected final double rowCount;
-    protected final List<Map.Entry<String, RelDataType>> columnList =
-        new ArrayList<>();
-    protected final List<Integer> keyList = new ArrayList<>();
-    protected final List<RelReferentialConstraint> referentialConstraints =
-        new ArrayList<>();
-    protected RelDataType rowType;
-    protected List<RelCollation> collationList;
-    protected final List<String> names;
-    protected final Set<String> monotonicColumnSet = new HashSet<>();
-    protected StructKind kind = StructKind.FULLY_QUALIFIED;
-    protected final ColumnResolver resolver;
-    protected final InitializerExpressionFactory initializerFactory;
-    protected final Set<String> rolledUpColumns = new HashSet<>();
-
-    public MockTable(MockCatalogReader catalogReader, String catalogName,
-        String schemaName, String name, boolean stream, double rowCount,
-        ColumnResolver resolver,
-        InitializerExpressionFactory initializerFactory) {
-      this(catalogReader, ImmutableList.of(catalogName, schemaName, name), stream, rowCount,
-          resolver, initializerFactory);
-    }
-
-    public void registerRolledUpColumn(String columnName) {
-      rolledUpColumns.add(columnName);
-    }
-
-    private MockTable(MockCatalogReader catalogReader, List<String> names, boolean stream,
-        double rowCount, ColumnResolver resolver, InitializerExpressionFactory initializerFactory) {
-      this.catalogReader = catalogReader;
-      this.stream = stream;
-      this.rowCount = rowCount;
-      this.names = names;
-      this.resolver = resolver;
-      this.initializerFactory = initializerFactory;
-    }
-
-    /**
-     * Copy constructor.
-     */
-    protected MockTable(MockCatalogReader catalogReader, boolean stream, double rowCount,
-        List<Map.Entry<String, RelDataType>> columnList, List<Integer> keyList,
-        RelDataType rowType, List<RelCollation> collationList, List<String> names,
-        Set<String> monotonicColumnSet, StructKind kind, ColumnResolver resolver,
-        InitializerExpressionFactory initializerFactory) {
-      this.catalogReader = catalogReader;
-      this.stream = stream;
-      this.rowCount = rowCount;
-      this.rowType = rowType;
-      this.collationList = collationList;
-      this.names = names;
-      this.kind = kind;
-      this.resolver = resolver;
-      this.initializerFactory = initializerFactory;
-      for (String name : monotonicColumnSet) {
-        addMonotonic(name);
-      }
-    }
-
-    /** Implementation of AbstractModifiableTable. */
-    private class ModifiableTable extends JdbcTest.AbstractModifiableTable
-        implements ExtensibleTable, Wrapper {
-      protected ModifiableTable(String tableName) {
-        super(tableName);
-      }
-
-      @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
-        return typeFactory.createStructType(MockTable.this.getRowType().getFieldList());
-      }
-
-      @Override public Collection getModifiableCollection() {
-        return null;
-      }
-
-      @Override public <E> Queryable<E>
-      asQueryable(QueryProvider queryProvider, SchemaPlus schema,
-          String tableName) {
-        return null;
-      }
-
-      @Override public Type getElementType() {
-        return null;
-      }
-
-      @Override public Expression getExpression(SchemaPlus schema,
-          String tableName, Class clazz) {
-        return null;
-      }
-
-      @Override public <C> C unwrap(Class<C> aClass) {
-        if (aClass.isInstance(initializerFactory)) {
-          return aClass.cast(initializerFactory);
-        } else if (aClass.isInstance(MockTable.this)) {
-          return aClass.cast(MockTable.this);
-        }
-        return super.unwrap(aClass);
-      }
-
-      @Override public Table extend(final List<RelDataTypeField> fields) {
-        return new ModifiableTable(Util.last(names)) {
-          @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
-            ImmutableList<RelDataTypeField> allFields = ImmutableList.copyOf(
-                Iterables.concat(
-                    ModifiableTable.this.getRowType(typeFactory).getFieldList(),
-                    fields));
-            return typeFactory.createStructType(allFields);
-          }
-        };
-      }
-
-      @Override public int getExtendedColumnOffset() {
-        return rowType.getFieldCount();
-      }
-    }
-
-    @Override protected RelOptTable extend(final Table extendedTable) {
-      return new MockTable(catalogReader, names, stream, rowCount, resolver, initializerFactory) {
-        @Override public RelDataType getRowType() {
-          return extendedTable.getRowType(catalogReader.typeFactory);
-        }
-      };
-    }
-
-    public static MockTable create(MockCatalogReader catalogReader,
-        MockSchema schema, String name, boolean stream, double rowCount) {
-      return create(catalogReader, schema, name, stream, rowCount, null);
-    }
-
-    public static MockTable create(MockCatalogReader catalogReader,
-        List<String> names, boolean stream, double rowCount) {
-      return new MockTable(catalogReader, names, stream, rowCount, null,
-          NullInitializerExpressionFactory.INSTANCE);
-    }
-
-    public static MockTable create(MockCatalogReader catalogReader,
-        MockSchema schema, String name, boolean stream, double rowCount,
-        ColumnResolver resolver) {
-      return create(catalogReader, schema, name, stream, rowCount, resolver,
-          NullInitializerExpressionFactory.INSTANCE);
-    }
-
-    public static MockTable create(MockCatalogReader catalogReader,
-        MockSchema schema, String name, boolean stream, double rowCount,
-        ColumnResolver resolver,
-        InitializerExpressionFactory initializerExpressionFactory) {
-      MockTable table =
-          new MockTable(catalogReader, schema.getCatalogName(), schema.name,
-              name, stream, rowCount, resolver, initializerExpressionFactory);
-      schema.addTable(name);
-      return table;
-    }
-
-    public <T> T unwrap(Class<T> clazz) {
-      if (clazz.isInstance(this)) {
-        return clazz.cast(this);
-      }
-      if (clazz.isInstance(initializerFactory)) {
-        return clazz.cast(initializerFactory);
-      }
-      if (clazz.isAssignableFrom(Table.class)) {
-        final Table table = resolver == null
-            ? new ModifiableTable(Util.last(names))
-                : new ModifiableTableWithCustomColumnResolving(Util.last(names));
-        return clazz.cast(table);
-      }
-      return null;
-    }
-
-    public double getRowCount() {
-      return rowCount;
-    }
-
-    public RelOptSchema getRelOptSchema() {
-      return catalogReader;
-    }
-
-    public RelNode toRel(ToRelContext context) {
-      return LogicalTableScan.create(context.getCluster(), this);
-    }
-
-    public List<RelCollation> getCollationList() {
-      return collationList;
-    }
-
-    public RelDistribution getDistribution() {
-      return RelDistributions.BROADCAST_DISTRIBUTED;
-    }
-
-    public boolean isKey(ImmutableBitSet columns) {
-      return !keyList.isEmpty()
-          && columns.contains(ImmutableBitSet.of(keyList));
-    }
-
-    public List<RelReferentialConstraint> getReferentialConstraints() {
-      return referentialConstraints;
-    }
-
-    public RelDataType getRowType() {
-      return rowType;
-    }
-
-    public boolean supportsModality(SqlModality modality) {
-      return modality == (stream ? SqlModality.STREAM : SqlModality.RELATION);
-    }
-
-    public void onRegister(RelDataTypeFactory typeFactory) {
-      rowType = typeFactory.createStructType(kind, Pair.right(columnList),
-          Pair.left(columnList));
-      collationList = deduceMonotonicity(this);
-    }
-
-    public List<String> getQualifiedName() {
-      return names;
-    }
-
-    public SqlMonotonicity getMonotonicity(String columnName) {
-      return monotonicColumnSet.contains(columnName)
-          ? SqlMonotonicity.INCREASING
-          : SqlMonotonicity.NOT_MONOTONIC;
-    }
-
-    public SqlAccessType getAllowedAccess() {
-      return SqlAccessType.ALL;
-    }
-
-    public Expression getExpression(Class clazz) {
-      throw new UnsupportedOperationException();
-    }
-
-    public void addColumn(String name, RelDataType type) {
-      addColumn(name, type, false);
-    }
-
-    public void addColumn(String name, RelDataType type, boolean isKey) {
-      if (isKey) {
-        keyList.add(columnList.size());
-      }
-      columnList.add(Pair.of(name, type));
-    }
-
-    public void addMonotonic(String name) {
-      monotonicColumnSet.add(name);
-      assert Pair.left(columnList).contains(name);
-    }
-
-    public void setKind(StructKind kind) {
-      this.kind = kind;
-    }
-
-    public StructKind getKind() {
-      return kind;
-    }
-
-    /**
-     * Subclass of {@link ModifiableTable} that also implements
-     * {@link CustomColumnResolvingTable}.
-     */
-    private class ModifiableTableWithCustomColumnResolving
-        extends ModifiableTable implements CustomColumnResolvingTable, Wrapper {
-
-      ModifiableTableWithCustomColumnResolving(String tableName) {
-        super(tableName);
-      }
-
-      @Override public List<Pair<RelDataTypeField, List<String>>> resolveColumn(
-          RelDataType rowType, RelDataTypeFactory typeFactory,
-          List<String> names) {
-        return resolver.resolveColumn(rowType, typeFactory, names);
-      }
-    }
-  }
-
-  /**
-   * Alternative to MockViewTable that exercises code paths in ModifiableViewTable
-   * and ModifiableViewTableInitializerExpressionFactory.
-   */
-  public static class MockModifiableViewRelOptTable extends MockTable {
-    private final MockModifiableViewTable modifiableViewTable;
-
-    private MockModifiableViewRelOptTable(MockModifiableViewTable modifiableViewTable,
-        MockCatalogReader catalogReader, String catalogName, String schemaName, String name,
-        boolean stream, double rowCount, ColumnResolver resolver,
-        InitializerExpressionFactory initializerExpressionFactory) {
-      super(catalogReader, ImmutableList.of(catalogName, schemaName, name), stream, rowCount,
-          resolver, initializerExpressionFactory);
-      this.modifiableViewTable = modifiableViewTable;
-    }
-
-    /**
-     * Copy constructor.
-     */
-    private MockModifiableViewRelOptTable(MockModifiableViewTable modifiableViewTable,
-        MockCatalogReader catalogReader, boolean stream, double rowCount,
-        List<Map.Entry<String, RelDataType>> columnList, List<Integer> keyList,
-        RelDataType rowType, List<RelCollation> collationList, List<String> names,
-        Set<String> monotonicColumnSet, StructKind kind, ColumnResolver resolver,
-        InitializerExpressionFactory initializerFactory) {
-      super(catalogReader, stream, rowCount, columnList, keyList, rowType, collationList, names,
-          monotonicColumnSet, kind, resolver, initializerFactory);
-      this.modifiableViewTable = modifiableViewTable;
-    }
-
-    public static MockModifiableViewRelOptTable create(MockModifiableViewTable modifiableViewTable,
-        MockCatalogReader catalogReader, String catalogName, String schemaName, String name,
-        boolean stream, double rowCount, ColumnResolver resolver) {
-      final Table underlying = modifiableViewTable.unwrap(Table.class);
-      final InitializerExpressionFactory initializerExpressionFactory =
-          underlying != null && underlying instanceof Wrapper
-              ? ((Wrapper) underlying).unwrap(InitializerExpressionFactory.class)
-              : NullInitializerExpressionFactory.INSTANCE;
-      return new MockModifiableViewRelOptTable(modifiableViewTable,
-          catalogReader, catalogName, schemaName, name, stream, rowCount,
-          resolver, Util.first(initializerExpressionFactory,
-          NullInitializerExpressionFactory.INSTANCE));
-    }
-
-    public static MockViewTableMacro viewMacro(CalciteSchema schema, String viewSql,
-        List<String> schemaPath, List<String> viewPath, Boolean modifiable) {
-      return new MockViewTableMacro(schema, viewSql, schemaPath, viewPath, modifiable);
-    }
-
-    @Override public RelDataType getRowType() {
-      return modifiableViewTable.getRowType(catalogReader.typeFactory);
-    }
-
-    @Override protected RelOptTable extend(Table extendedTable) {
-      return new MockModifiableViewRelOptTable((MockModifiableViewTable) extendedTable,
-          catalogReader, stream, rowCount, columnList, keyList, rowType, collationList, names,
-          monotonicColumnSet, kind, resolver, initializerFactory);
-    }
-
-    @Override public <T> T unwrap(Class<T> clazz) {
-      if (clazz.isInstance(modifiableViewTable)) {
-        return clazz.cast(modifiableViewTable);
-      }
-      return super.unwrap(clazz);
-    }
-
-    /**
-     * A TableMacro that creates mock ModifiableViewTable.
-     */
-    public static class MockViewTableMacro extends ViewTableMacro {
-      MockViewTableMacro(CalciteSchema schema, String viewSql, List<String> schemaPath,
-          List<String> viewPath, Boolean modifiable) {
-        super(schema, viewSql, schemaPath, viewPath, modifiable);
-      }
-
-      @Override protected ModifiableViewTable modifiableViewTable(
-          CalcitePrepare.AnalyzeViewResult parsed, String viewSql,
-          List<String> schemaPath, List<String> viewPath, CalciteSchema schema) {
-        final JavaTypeFactory typeFactory = (JavaTypeFactory) parsed.typeFactory;
-        final Type elementType = typeFactory.getJavaClass(parsed.rowType);
-        return new MockModifiableViewTable(elementType,
-            RelDataTypeImpl.proto(parsed.rowType), viewSql, schemaPath, viewPath,
-            parsed.table, Schemas.path(schema.root(), parsed.tablePath),
-            parsed.constraint, parsed.columnMapping);
-      }
-    }
-
-    /**
-     * A mock of ModifiableViewTable that can unwrap a mock RelOptTable.
-     */
-    private static class MockModifiableViewTable extends ModifiableViewTable {
-      private final RexNode constraint;
-
-      MockModifiableViewTable(Type elementType, RelProtoDataType rowType,
-          String viewSql, List<String> schemaPath, List<String> viewPath,
-          Table table, Path tablePath, RexNode constraint,
-          ImmutableIntList columnMapping) {
-        super(elementType, rowType, viewSql, schemaPath, viewPath, table,
-            tablePath, constraint, columnMapping);
-        this.constraint = constraint;
-      }
-
-      @Override public ModifiableViewTable extend(Table extendedTable,
-          RelProtoDataType protoRowType, ImmutableIntList newColumnMapping) {
-        return new MockModifiableViewTable(getElementType(), protoRowType,
-            getViewSql(), getSchemaPath(), getViewPath(), extendedTable,
-            getTablePath(), constraint, newColumnMapping);
-      }
-    }
-  }
-
-  /**
-   * Mock implementation of
-   * {@link org.apache.calcite.prepare.Prepare.PreparingTable} for views.
-   */
-  public abstract static class MockViewTable extends MockTable {
-    private final MockTable fromTable;
-    private final Table table;
-    private final ImmutableIntList mapping;
-
-    MockViewTable(MockCatalogReader catalogReader, String catalogName,
-        String schemaName, String name, boolean stream, double rowCount,
-        MockTable fromTable, ImmutableIntList mapping, ColumnResolver resolver,
-        InitializerExpressionFactory initializerFactory) {
-      super(catalogReader, catalogName, schemaName, name, stream, rowCount,
-          resolver, initializerFactory);
-      this.fromTable = fromTable;
-      this.table = fromTable.unwrap(Table.class);
-      this.mapping = mapping;
-    }
-
-    /** Implementation of AbstractModifiableView. */
-    private class ModifiableView extends JdbcTest.AbstractModifiableView
-        implements Wrapper {
-      @Override public Table getTable() {
-        return fromTable.unwrap(Table.class);
-      }
-
-      @Override public Path getTablePath() {
-        final ImmutableList.Builder<Pair<String, Schema>> builder =
-            ImmutableList.builder();
-        for (String name : fromTable.names) {
-          builder.add(Pair.of(name, null));
-        }
-        return Schemas.path(builder.build());
-      }
-
-      @Override public ImmutableIntList getColumnMapping() {
-        return mapping;
-      }
-
-      @Override public RexNode getConstraint(RexBuilder rexBuilder,
-          RelDataType tableRowType) {
-        return MockViewTable.this.getConstraint(rexBuilder, tableRowType);
-      }
-
-      @Override public RelDataType
-      getRowType(final RelDataTypeFactory typeFactory) {
-        return typeFactory.createStructType(
-            new AbstractList<Map.Entry<String, RelDataType>>() {
-              @Override public Map.Entry<String, RelDataType>
-              get(int index) {
-                return table.getRowType(typeFactory).getFieldList()
-                    .get(mapping.get(index));
-              }
-
-              @Override public int size() {
-                return mapping.size();
-              }
-            });
-      }
-
-      @Override public <C> C unwrap(Class<C> aClass) {
-        if (table instanceof Wrapper) {
-          final C c = ((Wrapper) table).unwrap(aClass);
-          if (c != null) {
-            return c;
-          }
-        }
-        return super.unwrap(aClass);
-      }
-    }
-
-    /**
-     * Subclass of ModifiableView that also implements
-     * CustomColumnResolvingTable.
-     */
-    private class ModifiableViewWithCustomColumnResolving
-        extends ModifiableView implements CustomColumnResolvingTable, Wrapper {
-
-      @Override public List<Pair<RelDataTypeField, List<String>>> resolveColumn(
-          RelDataType rowType, RelDataTypeFactory typeFactory, List<String> names) {
-        return resolver.resolveColumn(rowType, typeFactory, names);
-      }
-
-      @Override public <C> C unwrap(Class<C> aClass) {
-        if (table instanceof Wrapper) {
-          final C c = ((Wrapper) table).unwrap(aClass);
-          if (c != null) {
-            return c;
-          }
-        }
-        return super.unwrap(aClass);
-      }
-    }
-
-    protected abstract RexNode getConstraint(RexBuilder rexBuilder,
-        RelDataType tableRowType);
-
-    @Override public void onRegister(RelDataTypeFactory typeFactory) {
-      super.onRegister(typeFactory);
-      // To simulate getRowType() behavior in ViewTable.
-      final RelProtoDataType protoRowType = RelDataTypeImpl.proto(rowType);
-      rowType = protoRowType.apply(typeFactory);
-    }
-
-    @Override public RelNode toRel(ToRelContext context) {
-      RelNode rel = LogicalTableScan.create(context.getCluster(), fromTable);
-      final RexBuilder rexBuilder = context.getCluster().getRexBuilder();
-      rel = LogicalFilter.create(
-          rel, getConstraint(rexBuilder, rel.getRowType()));
-      final List<RelDataTypeField> fieldList =
-          rel.getRowType().getFieldList();
-      final List<Pair<RexNode, String>> projects =
-          new AbstractList<Pair<RexNode, String>>() {
-            @Override public Pair<RexNode, String> get(int index) {
-              return RexInputRef.of2(mapping.get(index), fieldList);
-            }
-
-            @Override public int size() {
-              return mapping.size();
-            }
-          };
-      return LogicalProject.create(rel, Pair.left(projects),
-          Pair.right(projects));
-    }
-
-    @Override public <T> T unwrap(Class<T> clazz) {
-      if (clazz.isAssignableFrom(ModifiableView.class)) {
-        ModifiableView view = resolver == null
-            ? new ModifiableView()
-                : new ModifiableViewWithCustomColumnResolving();
-        return clazz.cast(view);
-      }
-      return super.unwrap(clazz);
-    }
-  }
-
-  /**
-   * Mock implementation of
-   * {@link org.apache.calcite.prepare.Prepare.PreparingTable} with dynamic record type.
-   */
-  public static class MockDynamicTable extends MockTable {
-    MockDynamicTable(MockCatalogReader catalogReader, String catalogName,
-        String schemaName, String name, boolean stream, double rowCount) {
-      super(catalogReader, catalogName, schemaName, name, stream, rowCount,
-          null, NullInitializerExpressionFactory.INSTANCE);
-    }
-
-    public void onRegister(RelDataTypeFactory typeFactory) {
-      rowType = new DynamicRecordTypeImpl(typeFactory);
-    }
-
-    /**
-     * Recreates an immutable rowType, if the table has Dynamic Record Type,
-     * when converts table to Rel.
-     */
-    public RelNode toRel(ToRelContext context) {
-      if (rowType.isDynamicStruct()) {
-        rowType = new RelRecordType(rowType.getFieldList());
-      }
-      return super.toRel(context);
-    }
-  }
-
-  /** Struct type based on another struct type. */
-  private static class DelegateStructType implements RelDataType {
-    private RelDataType delegate;
-    private StructKind structKind;
-
-    DelegateStructType(RelDataType delegate, StructKind structKind) {
-      assert delegate.isStruct();
-      this.delegate = delegate;
-      this.structKind = structKind;
-    }
-
-    public boolean isStruct() {
-      return delegate.isStruct();
-    }
-
-    public boolean isDynamicStruct() {
-      return delegate.isDynamicStruct();
-    }
-
-    public List<RelDataTypeField> getFieldList() {
-      return delegate.getFieldList();
-    }
-
-    public List<String> getFieldNames() {
-      return delegate.getFieldNames();
-    }
-
-    public int getFieldCount() {
-      return delegate.getFieldCount();
-    }
-
-    public StructKind getStructKind() {
-      return structKind;
-    }
-
-    public RelDataTypeField getField(String fieldName, boolean caseSensitive,
-        boolean elideRecord) {
-      return delegate.getField(fieldName, caseSensitive, elideRecord);
-    }
-
-    public boolean isNullable() {
-      return delegate.isNullable();
-    }
-
-    public RelDataType getComponentType() {
-      return delegate.getComponentType();
-    }
-
-    public RelDataType getKeyType() {
-      return delegate.getKeyType();
-    }
-
-    public RelDataType getValueType() {
-      return delegate.getValueType();
-    }
-
-    public Charset getCharset() {
-      return delegate.getCharset();
-    }
-
-    public SqlCollation getCollation() {
-      return delegate.getCollation();
-    }
-
-    public SqlIntervalQualifier getIntervalQualifier() {
-      return delegate.getIntervalQualifier();
-    }
-
-    public int getPrecision() {
-      return delegate.getPrecision();
-    }
-
-    public int getScale() {
-      return delegate.getScale();
-    }
-
-    public SqlTypeName getSqlTypeName() {
-      return delegate.getSqlTypeName();
-    }
-
-    public SqlIdentifier getSqlIdentifier() {
-      return delegate.getSqlIdentifier();
-    }
-
-    public String getFullTypeString() {
-      return delegate.getFullTypeString();
-    }
-
-    public RelDataTypeFamily getFamily() {
-      return delegate.getFamily();
-    }
-
-    public RelDataTypePrecedenceList getPrecedenceList() {
-      return delegate.getPrecedenceList();
-    }
-
-    public RelDataTypeComparability getComparability() {
-      return delegate.getComparability();
-    }
-  }
-
-  /** Column having names with multiple parts. */
-  private static final class CompoundNameColumn {
-    final String first;
-    final String second;
-    final RelDataType type;
-
-    CompoundNameColumn(String first, String second, RelDataType type) {
-      this.first = first;
-      this.second = second;
-      this.type = type;
-    }
-
-    String getName() {
-      return (first.isEmpty() ? "" : ("\"" + first + "\"."))
-          + ("\"" + second + "\"");
-    }
-  }
-
-  /** ColumnResolver implementation that resolves CompoundNameColumn by simulating
-   *  Phoenix behaviors. */
-  private static final class CompoundNameColumnResolver implements ColumnResolver {
-    private final Map<String, Integer> nameMap = new HashMap<>();
-    private final Map<String, Map<String, Integer>> groupMap = new HashMap<>();
-    private final String defaultColumnGroup;
-
-    CompoundNameColumnResolver(
-        List<CompoundNameColumn> columns, String defaultColumnGroup) {
-      this.defaultColumnGroup = defaultColumnGroup;
-      for (Ord<CompoundNameColumn> column : Ord.zip(columns)) {
-        nameMap.put(column.e.getName(), column.i);
-        Map<String, Integer> subMap =
-            groupMap.computeIfAbsent(column.e.first, k -> new HashMap<>());
-        subMap.put(column.e.second, column.i);
-      }
-    }
-
-    @Override public List<Pair<RelDataTypeField, List<String>>> resolveColumn(
-        RelDataType rowType, RelDataTypeFactory typeFactory, List<String> names) {
-      List<Pair<RelDataTypeField, List<String>>> ret = new ArrayList<>();
-      if (names.size() >= 2) {
-        Map<String, Integer> subMap = groupMap.get(names.get(0));
-        if (subMap != null) {
-          Integer index = subMap.get(names.get(1));
-          if (index != null) {
-            ret.add(
-                new Pair<RelDataTypeField, List<String>>(
-                    rowType.getFieldList().get(index),
-                    names.subList(2, names.size())));
-          }
-        }
-      }
-
-      final String columnName = names.get(0);
-      final List<String> remainder = names.subList(1, names.size());
-      Integer index = nameMap.get(columnName);
-      if (index != null) {
-        ret.add(
-            new Pair<RelDataTypeField, List<String>>(
-                rowType.getFieldList().get(index), remainder));
-        return ret;
-      }
-
-      final List<String> priorityGroups = Arrays.asList("", defaultColumnGroup);
-      for (String group : priorityGroups) {
-        Map<String, Integer> subMap = groupMap.get(group);
-        if (subMap != null) {
-          index = subMap.get(columnName);
-          if (index != null) {
-            ret.add(
-                new Pair<RelDataTypeField, List<String>>(
-                    rowType.getFieldList().get(index), remainder));
-            return ret;
-          }
-        }
-      }
-      for (Map.Entry<String, Map<String, Integer>> entry : groupMap.entrySet()) {
-        if (priorityGroups.contains(entry.getKey())) {
-          continue;
-        }
-        index = entry.getValue().get(columnName);
-        if (index != null) {
-          ret.add(
-              new Pair<RelDataTypeField, List<String>>(
-                  rowType.getFieldList().get(index), remainder));
-        }
-      }
-
-      if (ret.isEmpty() && names.size() == 1) {
-        Map<String, Integer> subMap = groupMap.get(columnName);
-        if (subMap != null) {
-          List<Map.Entry<String, Integer>> entries =
-              new ArrayList<>(subMap.entrySet());
-          entries.sort((o1, o2) -> o1.getValue() - o2.getValue());
-          ret.add(
-              new Pair<RelDataTypeField, List<String>>(
-                  new RelDataTypeFieldImpl(
-                      columnName, -1,
-                      createStructType(
-                          rowType,
-                          typeFactory,
-                          entries)),
-                  remainder));
-        }
-      }
-
-      return ret;
-    }
-
-    private static RelDataType createStructType(
-        final RelDataType rowType,
-        RelDataTypeFactory typeFactory,
-        final List<Map.Entry<String, Integer>> entries) {
-      return typeFactory.createStructType(
-          StructKind.PEEK_FIELDS,
-          new AbstractList<RelDataType>() {
-            @Override public RelDataType get(int index) {
-              final int i = entries.get(index).getValue();
-              return rowType.getFieldList().get(i).getType();
-            }
-            @Override public int size() {
-              return entries.size();
-            }
-          },
-          new AbstractList<String>() {
-            @Override public String get(int index) {
-              return entries.get(index).getKey();
-            }
-            @Override public int size() {
-              return entries.size();
-            }
-          });
-    }
-  }
-
-  /** Wrapper around a {@link MockTable}, giving it a {@link Table} interface.
-   * You can get the {@code MockTable} by calling {@link #unwrap(Class)}. */
-  private static class WrapperTable implements Table, Wrapper {
-    private final MockTable table;
-
-    WrapperTable(MockTable table) {
-      this.table = table;
-    }
-
-    public <C> C unwrap(Class<C> aClass) {
-      return aClass.isInstance(this) ? aClass.cast(this)
-          : aClass.isInstance(table) ? aClass.cast(table)
-          : null;
-    }
-
-    public RelDataType getRowType(RelDataTypeFactory typeFactory) {
-      return table.getRowType();
-    }
-
-    public Statistic getStatistic() {
-      return new Statistic() {
-        public Double getRowCount() {
-          return table.rowCount;
-        }
-
-        public boolean isKey(ImmutableBitSet columns) {
-          return table.isKey(columns);
-        }
-
-        public List<RelReferentialConstraint> getReferentialConstraints() {
-          return table.getReferentialConstraints();
-        }
-
-        public List<RelCollation> getCollations() {
-          return table.collationList;
-        }
-
-        public RelDistribution getDistribution() {
-          return table.getDistribution();
-        }
-      };
-    }
-
-    @Override public boolean isRolledUp(String column) {
-      return table.rolledUpColumns.contains(column);
-    }
-
-    @Override public boolean rolledUpColumnValidInsideAgg(String column,
-        SqlCall call, SqlNode parent, CalciteConnectionConfig config) {
-      // For testing
-      return call.getKind() != SqlKind.MAX
-              && (parent.getKind() == SqlKind.SELECT || parent.getKind() == SqlKind.FILTER);
-    }
-
-    public Schema.TableType getJdbcTableType() {
-      return table.stream ? Schema.TableType.STREAM : Schema.TableType.TABLE;
-    }
-  }
-
-  /** Wrapper around a {@link MockTable}, giving it a {@link StreamableTable}
-   * interface. */
-  private static class StreamableWrapperTable extends WrapperTable
-      implements StreamableTable {
-    StreamableWrapperTable(MockTable table) {
-      super(table);
-    }
-
-    public Table stream() {
-      return this;
-    }
-  }
-
-  /** Default values for the "EMPDEFAULTS" table. */
-  private static class EmpInitializerExpressionFactory
-      extends NullInitializerExpressionFactory {
-    @Override public ColumnStrategy generationStrategy(RelOptTable table,
-        int iColumn) {
-      switch (iColumn) {
-      case 0:
-      case 1:
-      case 5:
-        return ColumnStrategy.DEFAULT;
-      default:
-        return super.generationStrategy(table, iColumn);
-      }
-    }
-
-    @Override public RexNode newColumnDefaultValue(RelOptTable table,
-        int iColumn, InitializerContext context) {
-      final RexBuilder rexBuilder = context.getRexBuilder();
-      final RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
-      switch (iColumn) {
-      case 0:
-        return rexBuilder.makeExactLiteral(new BigDecimal(123),
-            typeFactory.createSqlType(SqlTypeName.INTEGER));
-      case 1:
-        return rexBuilder.makeLiteral("Bob");
-      case 5:
-        return rexBuilder.makeExactLiteral(new BigDecimal(555),
-            typeFactory.createSqlType(SqlTypeName.INTEGER));
-      default:
-        return rexBuilder.constantNull();
-      }
-    }
-  }
-
-  /** Types used during initialization. */
-  private class Fixture {
-    final RelDataType intType =
-        typeFactory.createSqlType(SqlTypeName.INTEGER);
-    final RelDataType intTypeNull =
-        typeFactory.createTypeWithNullability(intType, true);
-    final RelDataType varchar10Type =
-        typeFactory.createSqlType(SqlTypeName.VARCHAR, 10);
-    final RelDataType varchar10TypeNull =
-        typeFactory.createTypeWithNullability(varchar10Type, true);
-    final RelDataType varchar20Type =
-        typeFactory.createSqlType(SqlTypeName.VARCHAR, 20);
-    final RelDataType varchar20TypeNull =
-        typeFactory.createTypeWithNullability(varchar20Type, true);
-    final RelDataType timestampType =
-        typeFactory.createSqlType(SqlTypeName.TIMESTAMP);
-    final RelDataType timestampTypeNull =
-        typeFactory.createTypeWithNullability(timestampType, true);
-    final RelDataType dateType =
-        typeFactory.createSqlType(SqlTypeName.DATE);
-    final RelDataType booleanType =
-        typeFactory.createSqlType(SqlTypeName.BOOLEAN);
-    final RelDataType booleanTypeNull =
-        typeFactory.createTypeWithNullability(booleanType, true);
-    final RelDataType rectilinearCoordType =
-        typeFactory.builder()
-            .add("X", intType)
-            .add("Y", intType)
-            .build();
-    final RelDataType rectilinearPeekCoordType =
-        typeFactory.builder()
-            .add("X", intType)
-            .add("Y", intType)
-            .kind(StructKind.PEEK_FIELDS)
-            .build();
-    final RelDataType rectilinearPeekNoExpandCoordType =
-        typeFactory.builder()
-            .add("M", intType)
-            .add("SUB",
-                typeFactory.builder()
-                    .add("A", intType)
-                    .add("B", intType)
-                    .kind(StructKind.PEEK_FIELDS_NO_EXPAND)
-                    .build())
-            .kind(StructKind.PEEK_FIELDS_NO_EXPAND)
-            .build();
-    final RelDataType abRecordType =
-        typeFactory.builder()
-            .add("A", varchar10Type)
-            .add("B", varchar10Type)
-            .build();
-    final RelDataType skillRecordType =
-        typeFactory.builder()
-            .add("TYPE", varchar10Type)
-            .add("DESC", varchar20Type)
-            .add("OTHERS", abRecordType)
-            .build();
-    final RelDataType empRecordType =
-        typeFactory.builder()
-            .add("EMPNO", intType)
-            .add("ENAME", varchar10Type)
-            .add("DETAIL",
-                typeFactory.builder().add("SKILLS",
-                    typeFactory.createArrayType(skillRecordType, -1)).build())
-            .build();
-    final RelDataType empListType =
-        typeFactory.createArrayType(empRecordType, -1);
-
-    // TODO jvs 12-Feb-2005: register this canonical instance with type
-    // factory
-    final ObjectSqlType addressType =
-        new ObjectSqlType(SqlTypeName.STRUCTURED,
-            new SqlIdentifier("ADDRESS", SqlParserPos.ZERO),
-            false,
-            Arrays.asList(
-                new RelDataTypeFieldImpl("STREET", 0, varchar20Type),
-                new RelDataTypeFieldImpl("CITY", 1, varchar20Type),
-                new RelDataTypeFieldImpl("ZIP", 2, intType),
-                new RelDataTypeFieldImpl("STATE", 3, varchar20Type)),
-            RelDataTypeComparability.NONE);
-  }
-
-  /** To check whether
-   * {@link InitializerExpressionFactory#newColumnDefaultValue} is called.
-   *
-   * <p>If a column is in {@code defaultColumns}, returns 1 as the default
-   * value. */
-  public static class CountingFactory extends NullInitializerExpressionFactory {
-    static final ThreadLocal<AtomicInteger> THREAD_CALL_COUNT =
-        ThreadLocal.withInitial(AtomicInteger::new);
-
-    private final List<String> defaultColumns;
-
-    CountingFactory(List<String> defaultColumns) {
-      this.defaultColumns = ImmutableList.copyOf(defaultColumns);
-    }
-
-    @Override public ColumnStrategy generationStrategy(RelOptTable table,
-        int iColumn) {
-      final RelDataTypeField field =
-          table.getRowType().getFieldList().get(iColumn);
-      if (defaultColumns.contains(field.getName())) {
-        return ColumnStrategy.DEFAULT;
-      }
-      return super.generationStrategy(table, iColumn);
-    }
-
-    @Override public RexNode newColumnDefaultValue(RelOptTable table,
-        int iColumn, InitializerContext context) {
-      THREAD_CALL_COUNT.get().incrementAndGet();
-      final RelDataTypeField field =
-          table.getRowType().getFieldList().get(iColumn);
-      if (defaultColumns.contains(field.getName())) {
-        final RexBuilder rexBuilder = context.getRexBuilder();
-        return rexBuilder.makeExactLiteral(BigDecimal.ONE);
-      }
-      return super.newColumnDefaultValue(table, iColumn, context);
-    }
-
-    @Override public RexNode newAttributeInitializer(RelDataType type,
-        SqlFunction constructor, int iAttribute,
-        List<RexNode> constructorArgs, InitializerContext context) {
-      THREAD_CALL_COUNT.get().incrementAndGet();
-      return super.newAttributeInitializer(type, constructor, iAttribute,
-         constructorArgs, context);
-    }
-  }
-}
-
-// End MockCatalogReader.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 07dd0b0..11bf234 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -115,6 +115,7 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
+import org.apache.calcite.test.catalog.MockCatalogReader;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/SqlTestGen.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlTestGen.java b/core/src/test/java/org/apache/calcite/test/SqlTestGen.java
index 54ddd61..ceac204 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlTestGen.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlTestGen.java
@@ -17,8 +17,6 @@
 package org.apache.calcite.test;
 
 import org.apache.calcite.sql.SqlCollation;
-import org.apache.calcite.sql.test.DefaultSqlTestFactory;
-import org.apache.calcite.sql.test.DelegatingSqlTestFactory;
 import org.apache.calcite.sql.test.SqlTestFactory;
 import org.apache.calcite.sql.test.SqlTester;
 import org.apache.calcite.sql.test.SqlTesterImpl;
@@ -90,6 +88,13 @@ public class SqlTestGen {
    * tests.
    */
   private static class SqlValidatorSpooler extends SqlValidatorTest {
+    private static final SqlTestFactory SPOOLER_VALIDATOR = SqlTestFactory.INSTANCE.withValidator(
+        (opTab, catalogReader, typeFactory, conformance) ->
+            (SqlValidator) Proxy.newProxyInstance(
+                SqlValidatorSpooler.class.getClassLoader(),
+                new Class[]{SqlValidator.class},
+                new MyInvocationHandler()));
+
     private final PrintWriter pw;
 
     private SqlValidatorSpooler(PrintWriter pw) {
@@ -97,16 +102,7 @@ public class SqlTestGen {
     }
 
     public SqlTester getTester() {
-      final SqlTestFactory factory =
-          new DelegatingSqlTestFactory(DefaultSqlTestFactory.INSTANCE) {
-            @Override public SqlValidator getValidator(SqlTestFactory factory) {
-              return (SqlValidator) Proxy.newProxyInstance(
-                  SqlValidatorSpooler.class.getClassLoader(),
-                  new Class[]{SqlValidator.class},
-                  new MyInvocationHandler());
-            }
-          };
-      return new SqlTesterImpl(factory) {
+      return new SqlTesterImpl(SPOOLER_VALIDATOR) {
         public void assertExceptionIsThrown(
             String sql,
             String expectedMsgPattern) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
index 6cc02de..b62438a 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -30,6 +30,7 @@ import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlConformanceEnum;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
+import org.apache.calcite.test.catalog.MockCatalogReaderExtended;
 import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.TestUtil;
@@ -2637,7 +2638,7 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
 
   private Tester getExtendedTester() {
     return tester.withCatalogReaderFactory(typeFactory ->
-        new MockCatalogReader(typeFactory, true).init().init2());
+        new MockCatalogReaderExtended(typeFactory, true).init());
   }
 
   @Test public void testLarge() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
index d2192ae..58fc09e 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -59,6 +59,8 @@ import org.apache.calcite.sql.validate.SqlValidatorTable;
 import org.apache.calcite.sql2rel.RelFieldTrimmer;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
 import org.apache.calcite.sql2rel.StandardConvertletTable;
+import org.apache.calcite.test.catalog.MockCatalogReader;
+import org.apache.calcite.test.catalog.MockCatalogReaderSimple;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.util.ImmutableBitSet;
 
@@ -732,7 +734,7 @@ public abstract class SqlToRelTestBase {
       if (this.catalogReaderFactory != null) {
         return catalogReaderFactory.apply(typeFactory);
       }
-      return new MockCatalogReader(typeFactory, true).init();
+      return new MockCatalogReaderSimple(typeFactory, true).init();
     }
 
     public RelOptPlanner createPlanner() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/SqlValidatorFeatureTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorFeatureTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorFeatureTest.java
index 1aae8b3..48cbf0f 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorFeatureTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorFeatureTest.java
@@ -17,20 +17,15 @@
 package org.apache.calcite.test;
 
 import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.runtime.CalciteContextException;
 import org.apache.calcite.runtime.CalciteException;
 import org.apache.calcite.runtime.Feature;
 import org.apache.calcite.sql.SqlOperatorTable;
 import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.test.DefaultSqlTestFactory;
-import org.apache.calcite.sql.test.DelegatingSqlTestFactory;
 import org.apache.calcite.sql.test.SqlTestFactory;
 import org.apache.calcite.sql.test.SqlTester;
 import org.apache.calcite.sql.test.SqlTesterImpl;
-import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
 import org.apache.calcite.sql.validate.SqlConformance;
-import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
 import org.apache.calcite.sql.validate.SqlValidatorImpl;
 
@@ -60,7 +55,7 @@ public class SqlValidatorFeatureTest extends SqlValidatorTestCase {
   //~ Methods ----------------------------------------------------------------
 
   @Override public SqlTester getTester() {
-    return new SqlTesterImpl(new FeatureTesterFactory());
+    return new SqlTesterImpl(SqlTestFactory.INSTANCE.withValidator(FeatureValidator::new));
   }
 
   @Test public void testDistinct() {
@@ -125,27 +120,8 @@ public class SqlValidatorFeatureTest extends SqlValidatorTestCase {
 
   //~ Inner Classes ----------------------------------------------------------
 
-  /** Factory for tester objects. */
-  private class FeatureTesterFactory extends DelegatingSqlTestFactory {
-    FeatureTesterFactory() {
-      super(DefaultSqlTestFactory.INSTANCE);
-    }
-
-    @Override public SqlValidator getValidator(SqlTestFactory factory) {
-      final RelDataTypeFactory typeFactory =
-          new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
-      SqlConformance conformance = (SqlConformance) get("conformance");
-      final boolean caseSensitive = (Boolean) get("caseSensitive");
-      return new FeatureValidator(
-          factory.createOperatorTable(factory),
-          new MockCatalogReader(typeFactory, caseSensitive).init(),
-          typeFactory,
-          conformance);
-    }
-  }
-
   /** Extension to {@link SqlValidatorImpl} that validates features. */
-  private class FeatureValidator extends SqlValidatorImpl {
+  public class FeatureValidator extends SqlValidatorImpl {
     protected FeatureValidator(
         SqlOperatorTable opTab,
         SqlValidatorCatalogReader catalogReader,

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 6f422bd..45fe7b4 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -40,6 +40,7 @@ import org.apache.calcite.sql.validate.SqlDelegatingConformance;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.test.catalog.CountingFactory;
 import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.ImmutableBitSet;
 
@@ -8854,14 +8855,14 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
    * check for default value only when target field is null. */
   @Test public void testInsertShouldNotCheckForDefaultValue() {
     final int c =
-        MockCatalogReader.CountingFactory.THREAD_CALL_COUNT.get().get();
+        CountingFactory.THREAD_CALL_COUNT.get().get();
     final SqlTester pragmaticTester =
         tester.withConformance(SqlConformanceEnum.PRAGMATIC_2003);
     final String sql1 = "insert into emp values(1, 'nom', 'job', 0, "
         + "timestamp '1970-01-01 00:00:00', 1, 1, 1, false)";
     pragmaticTester.checkQuery(sql1);
     assertThat("Should not check for default value if column is in INSERT",
-        MockCatalogReader.CountingFactory.THREAD_CALL_COUNT.get().get(), is(c));
+        CountingFactory.THREAD_CALL_COUNT.get().get(), is(c));
 
     // Now add a list of target columns, keeping the query otherwise the same.
     final String sql2 = "insert into emp (empno, ename, job, mgr, hiredate,\n"
@@ -8870,7 +8871,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
         + "  timestamp '1970-01-01 00:00:00', 1, 1, 1, false)";
     pragmaticTester.checkQuery(sql2);
     assertThat("Should not check for default value if column is in INSERT",
-        MockCatalogReader.CountingFactory.THREAD_CALL_COUNT.get().get(), is(c));
+        CountingFactory.THREAD_CALL_COUNT.get().get(), is(c));
 
     // Now remove SLACKER, which is NOT NULL, from the target list.
     final String sql3 = "insert into ^emp^ (empno, ename, job, mgr, hiredate,\n"
@@ -8881,7 +8882,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
         "Column 'SLACKER' has no default value and does not allow NULLs");
     assertThat("Should not check for default value, even if if column is missing"
             + "from INSERT and nullable",
-        MockCatalogReader.CountingFactory.THREAD_CALL_COUNT.get().get(),
+        CountingFactory.THREAD_CALL_COUNT.get().get(),
         is(c));
 
     // Now remove DEPTNO, which has a default value, from the target list.
@@ -8893,7 +8894,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
         + "  timestamp '1970-01-01 00:00:00', 1, 1, false)";
     pragmaticTester.checkQuery(sql4);
     assertThat("Missing DEFAULT column generates a call to factory",
-        MockCatalogReader.CountingFactory.THREAD_CALL_COUNT.get().get(),
+        CountingFactory.THREAD_CALL_COUNT.get().get(),
         is(c));
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
index f09009c..a281c1c 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java
@@ -16,15 +16,12 @@
  */
 package org.apache.calcite.test;
 
-import org.apache.calcite.adapter.java.JavaTypeFactory;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.runtime.CalciteContextException;
 import org.apache.calcite.sql.SqlCollation;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.parser.SqlParseException;
 import org.apache.calcite.sql.parser.SqlParserUtil;
-import org.apache.calcite.sql.test.DefaultSqlTestFactory;
-import org.apache.calcite.sql.test.DelegatingSqlTestFactory;
 import org.apache.calcite.sql.test.SqlTestFactory;
 import org.apache.calcite.sql.test.SqlTester;
 import org.apache.calcite.sql.test.SqlTesterImpl;
@@ -32,6 +29,7 @@ import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlConformanceEnum;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.test.catalog.MockCatalogReaderExtended;
 import org.apache.calcite.util.TestUtil;
 import org.apache.calcite.util.Util;
 
@@ -65,12 +63,7 @@ public class SqlValidatorTestCase {
           "(?s)From line ([0-9]+), column ([0-9]+) to line ([0-9]+), column ([0-9]+): (.*)");
 
   private static final SqlTestFactory EXTENDED_TEST_FACTORY =
-      new DelegatingSqlTestFactory(DefaultSqlTestFactory.INSTANCE) {
-        @Override public MockCatalogReader createCatalogReader(
-            SqlTestFactory factory, JavaTypeFactory typeFactory) {
-          return super.createCatalogReader(this, typeFactory).init2();
-        }
-      };
+      SqlTestFactory.INSTANCE.withCatalogReader(MockCatalogReaderExtended::new);
 
   static final SqlTesterImpl EXTENDED_CATALOG_TESTER =
       new SqlTesterImpl(EXTENDED_TEST_FACTORY);
@@ -103,7 +96,7 @@ public class SqlValidatorTestCase {
    * same set of tests in a different testing environment.
    */
   public SqlTester getTester() {
-    return new SqlTesterImpl(DefaultSqlTestFactory.INSTANCE);
+    return new SqlTesterImpl(SqlTestFactory.INSTANCE);
   }
 
   public final Sql sql(String sql) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/96b28f7b/core/src/test/java/org/apache/calcite/test/catalog/CompoundNameColumn.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/catalog/CompoundNameColumn.java b/core/src/test/java/org/apache/calcite/test/catalog/CompoundNameColumn.java
new file mode 100644
index 0000000..b29c8d3
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/catalog/CompoundNameColumn.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.test.catalog;
+
+import org.apache.calcite.rel.type.RelDataType;
+
+/** Column having names with multiple parts. */
+final class CompoundNameColumn {
+  final String first;
+  final String second;
+  final RelDataType type;
+
+  CompoundNameColumn(String first, String second, RelDataType type) {
+    this.first = first;
+    this.second = second;
+    this.type = type;
+  }
+
+  String getName() {
+    return (first.isEmpty() ? "" : ("\"" + first + "\"."))
+        + ("\"" + second + "\"");
+  }
+}
+
+// End CompoundNameColumn.java