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
