metaColumnFactoryClass,
+ @PolyNull T defaultMetaColumnFactory) {
+ return CalciteConnectionProperty.META_COLUMN_FACTORY.wrap(properties)
+ .getPlugin(metaColumnFactoryClass, defaultMetaColumnFactory);
}
}
diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
index 7117787c4a7..7e4b9656244 100644
--- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
+++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionProperty.java
@@ -106,6 +106,12 @@ public enum CalciteConnectionProperty implements ConnectionProperty {
* {@link org.apache.calcite.sql.parser.SqlParserImplFactory}. */
PARSER_FACTORY("parserFactory", Type.PLUGIN, null, false),
+ /** MetaTableFactory plugin. */
+ META_TABLE_FACTORY("metaTableFactory", Type.PLUGIN, null, false),
+
+ /** MetaColumnFactory plugin. */
+ META_COLUMN_FACTORY("metaColumnFactory", Type.PLUGIN, null, false),
+
/** Name of initial schema. */
SCHEMA("schema", Type.STRING, null, false),
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaColumnFactory.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaColumnFactory.java
new file mode 100644
index 00000000000..1f9d1a487b9
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaColumnFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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.jdbc;
+
+import org.apache.calcite.avatica.MetaImpl.MetaColumn;
+import org.apache.calcite.schema.Table;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import java.util.List;
+
+/** Factory for creating instances of {@link MetaColumn}.
+ *
+ * @see java.sql.DatabaseMetaData#getColumns */
+public interface CalciteMetaColumnFactory {
+ /** Instantiates a MetaColumn. */
+ MetaColumn createColumn(Table table, String tableCat, String tableSchem,
+ String tableName, String columnName, int dataType, String typeName,
+ Integer columnSize, @Nullable Integer decimalDigits, int numPrecRadix,
+ int nullable, Integer charOctetLength, int ordinalPosition,
+ String isNullable);
+
+ /** Returns the list of expected column names.
+ *
+ * The default implementation returns the columns described in the JDBC
+ * specification. */
+ default List getColumnNames() {
+ return CalciteMetaImpl.COLUMN_COLUMNS;
+ }
+
+ /** Returns the type of object created. Must be a subclass of MetaColumn. */
+ Class extends MetaColumn> getMetaColumnClass();
+
+}
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaColumnFactoryImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaColumnFactoryImpl.java
new file mode 100644
index 00000000000..be320626cf1
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaColumnFactoryImpl.java
@@ -0,0 +1,69 @@
+/*
+ * 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.jdbc;
+
+import org.apache.calcite.avatica.MetaImpl.MetaColumn;
+import org.apache.calcite.schema.Table;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+/** Default implementation of CalciteMetaColumnFactoryImpl. */
+public class CalciteMetaColumnFactoryImpl
+ implements CalciteMetaColumnFactory {
+
+ /** Singleton instance. */
+ public static final CalciteMetaColumnFactoryImpl INSTANCE =
+ new CalciteMetaColumnFactoryImpl();
+
+ /** Internal constructor; protected to allow subclassing. */
+ protected CalciteMetaColumnFactoryImpl() {}
+
+ @Override public MetaColumn createColumn(
+ Table table,
+ String tableCat,
+ String tableSchem,
+ String tableName,
+ String columnName,
+ int dataType,
+ String typeName,
+ Integer columnSize,
+ @Nullable Integer decimalDigits,
+ int numPrecRadix,
+ int nullable,
+ Integer charOctetLength,
+ int ordinalPosition,
+ String isNullable) {
+ return new MetaColumn(
+ tableCat,
+ tableSchem,
+ tableName,
+ columnName,
+ dataType,
+ typeName,
+ columnSize,
+ decimalDigits,
+ numPrecRadix,
+ nullable,
+ charOctetLength,
+ ordinalPosition,
+ isNullable);
+ }
+
+ @Override public Class extends MetaColumn> getMetaColumnClass() {
+ return MetaColumn.class;
+ }
+}
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
index cd260838154..82be2738778 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
@@ -90,13 +90,140 @@
public class CalciteMetaImpl extends MetaImpl {
static final Driver DRIVER = new Driver();
+ private final CalciteMetaTableFactory metaTableFactory;
+ private final CalciteMetaColumnFactory metaColumnFactory;
+
+ /** The columns returned by {@link DatabaseMetaData#getCatalogs()}. */
+ public static final List CATALOG_COLUMNS =
+ ImmutableList.of("TABLE_CAT");
+
+ /** Column names returned by {@link DatabaseMetaData#getColumns}. */
+ public static final List COLUMN_COLUMNS =
+ ImmutableList.of("TABLE_CAT",
+ "TABLE_SCHEM",
+ "TABLE_NAME",
+ "COLUMN_NAME",
+ "DATA_TYPE",
+ "TYPE_NAME",
+ "COLUMN_SIZE",
+ "BUFFER_LENGTH",
+ "DECIMAL_DIGITS",
+ "NUM_PREC_RADIX",
+ "NULLABLE",
+ "REMARKS",
+ "COLUMN_DEF",
+ "SQL_DATA_TYPE",
+ "SQL_DATETIME_SUB",
+ "CHAR_OCTET_LENGTH",
+ "ORDINAL_POSITION",
+ "IS_NULLABLE",
+ "SCOPE_CATALOG",
+ "SCOPE_SCHEMA",
+ "SCOPE_TABLE",
+ "SOURCE_DATA_TYPE",
+ "IS_AUTOINCREMENT",
+ "IS_GENERATEDCOLUMN");
+
+ /** The columns returned by {@link DatabaseMetaData#getFunctions}. */
+ public static final List FUNCTION_COLUMNS =
+ ImmutableList.of("FUNCTION_CAT",
+ "FUNCTION_SCHEM",
+ "FUNCTION_NAME",
+ "REMARKS",
+ "FUNCTION_TYPE",
+ "SPECIFIC_NAME");
+
+ /** The columns returned by {@link DatabaseMetaData#getSchemas()}. */
+ public static final List SCHEMA_COLUMNS =
+ ImmutableList.of("TABLE_SCHEM",
+ "TABLE_CATALOG");
+
+ /** The columns returned by {@link DatabaseMetaData#getTables}. */
+ public static final List TABLE_COLUMNS =
+ ImmutableList.of("TABLE_CAT",
+ "TABLE_SCHEM",
+ "TABLE_NAME",
+ "TABLE_TYPE",
+ "REMARKS",
+ "TYPE_CAT",
+ "TYPE_SCHEM",
+ "TYPE_NAME",
+ "SELF_REFERENCING_COL_NAME",
+ "REF_GENERATION");
+
+ /** The columns returned by {@link DatabaseMetaData#getTableTypes()}. */
+ public static final List TABLE_TYPE_COLUMNS =
+ ImmutableList.of("TABLE_TYPE");
+
+ /** The columns returned by {@link DatabaseMetaData#getTypeInfo()}. */
+ public static final List TYPE_INFO_COLUMNS =
+ ImmutableList.of("TYPE_NAME",
+ "DATA_TYPE",
+ "PRECISION",
+ "LITERAL_PREFIX",
+ "LITERAL_SUFFIX",
+ "CREATE_PARAMS",
+ "NULLABLE",
+ "CASE_SENSITIVE",
+ "SEARCHABLE",
+ "UNSIGNED_ATTRIBUTE",
+ "FIXED_PREC_SCALE",
+ "AUTO_INCREMENT",
+ "LOCAL_TYPE_NAME",
+ "MINIMUM_SCALE",
+ "MAXIMUM_SCALE",
+ "SQL_DATA_TYPE",
+ "SQL_DATETIME_SUB",
+ "NUM_PREC_RADIX");
+
+ /** Creates a CalciteMetaImpl.
+ *
+ * @deprecated Use {@link #create(CalciteConnection)} instead.
+ */
+ @Deprecated // to be removed before 2.0
public CalciteMetaImpl(CalciteConnectionImpl connection) {
+ this(connection, CalciteMetaTableFactoryImpl.INSTANCE,
+ CalciteMetaColumnFactoryImpl.INSTANCE);
+ }
+
+ /** Internal constructor. Protected to allow subclassing. */
+ protected CalciteMetaImpl(CalciteConnectionImpl connection,
+ CalciteMetaTableFactory metaTableFactory,
+ CalciteMetaColumnFactory metaColumnFactory) {
super(connection);
this.connProps
.setAutoCommit(false)
.setReadOnly(false)
.setTransactionIsolation(Connection.TRANSACTION_NONE);
this.connProps.setDirty(false);
+ this.metaTableFactory =
+ requireNonNull(metaTableFactory, "metaTableFactory");
+ this.metaColumnFactory =
+ requireNonNull(metaColumnFactory, "metaColumnFactory");
+ }
+
+ /**
+ * Creates a CalciteMetaImpl.
+ *
+ * @param connection Calcite connection
+ */
+ public static CalciteMetaImpl create(CalciteConnection connection) {
+ return create(connection, CalciteMetaTableFactoryImpl.INSTANCE,
+ CalciteMetaColumnFactoryImpl.INSTANCE);
+ }
+
+ /**
+ * Creates a CalciteMetaImpl.
+ *
+ * @param connection Calcite connection
+ * @param metaTableFactory Factory for creating MetaTable (or subclass)
+ * @param metaColumnFactory Factory for creating MetaColumn (or subclass)
+ */
+ public static CalciteMetaImpl create(CalciteConnection connection,
+ CalciteMetaTableFactory metaTableFactory,
+ CalciteMetaColumnFactory metaColumnFactory) {
+ return new CalciteMetaImpl((CalciteConnectionImpl) connection,
+ metaTableFactory, metaColumnFactory);
}
static Predicate1 namedMatcher(final Pat pattern) {
@@ -170,19 +297,24 @@ public static Pattern likeToRegex(Pat pattern) {
}
private MetaResultSet createResultSet(Enumerable enumerable,
- Class clazz, String... names) {
- requireNonNull(names, "names");
- final List columns = new ArrayList<>(names.length);
- final List fields = new ArrayList<>(names.length);
- final List fieldNames = new ArrayList<>(names.length);
+ Class clazz, List names) {
+ assert names.size() > 0;
+ final List columns = new ArrayList<>(names.size());
+ final List fields = new ArrayList<>(names.size());
+ final List fieldNames = new ArrayList<>(names.size());
for (String name : names) {
final int index = fields.size();
final String fieldName = AvaticaUtils.toCamelCase(name);
- final Field field;
+ Field field;
try {
field = clazz.getField(fieldName);
} catch (NoSuchFieldException e) {
- throw new RuntimeException(e);
+ try {
+ // Check if subclass contains the desired field.
+ field = clazz.getDeclaredField(fieldName);
+ } catch (NoSuchFieldException e2) {
+ throw new RuntimeException(e2);
+ }
}
columns.add(columnMetaData(name, index, field.getType(), false));
fields.add(field);
@@ -263,44 +395,18 @@ private static ImmutableMap.Builder addProperty(
typeFilter = v1 -> typeList.contains(v1.tableType);
}
final Predicate1 schemaMatcher = namedMatcher(schemaPattern);
- return createResultSet(schemas(catalog)
- .where(schemaMatcher)
- .selectMany(schema -> tables(schema, matcher(tableNamePattern)))
- .where(typeFilter),
- MetaTable.class,
- "TABLE_CAT",
- "TABLE_SCHEM",
- "TABLE_NAME",
- "TABLE_TYPE",
- "REMARKS",
- "TYPE_CAT",
- "TYPE_SCHEM",
- "TYPE_NAME",
- "SELF_REFERENCING_COL_NAME",
- "REF_GENERATION");
+ Enumerable tables = schemas(catalog)
+ .where(schemaMatcher)
+ .selectMany(schema -> tables(schema, matcher(tableNamePattern)))
+ .where(typeFilter);
+ return createResultSet(tables,
+ metaTableFactory.getMetaTableClass(),
+ metaTableFactory.getColumnNames());
}
@Override public MetaResultSet getTypeInfo(ConnectionHandle ch) {
return createResultSet(allTypeInfo(),
- MetaTypeInfo.class,
- "TYPE_NAME",
- "DATA_TYPE",
- "PRECISION",
- "LITERAL_PREFIX",
- "LITERAL_SUFFIX",
- "CREATE_PARAMS",
- "NULLABLE",
- "CASE_SENSITIVE",
- "SEARCHABLE",
- "UNSIGNED_ATTRIBUTE",
- "FIXED_PREC_SCALE",
- "AUTO_INCREMENT",
- "LOCAL_TYPE_NAME",
- "MINIMUM_SCALE",
- "MAXIMUM_SCALE",
- "SQL_DATA_TYPE",
- "SQL_DATETIME_SUB",
- "NUM_PREC_RADIX");
+ MetaTypeInfo.class, TYPE_INFO_COLUMNS);
}
@Override public MetaResultSet getColumns(ConnectionHandle ch,
@@ -317,31 +423,8 @@ private static ImmutableMap.Builder addProperty(
.selectMany(schema -> tables(schema, tableNameMatcher))
.selectMany(this::columns)
.where(columnMatcher),
- MetaColumn.class,
- "TABLE_CAT",
- "TABLE_SCHEM",
- "TABLE_NAME",
- "COLUMN_NAME",
- "DATA_TYPE",
- "TYPE_NAME",
- "COLUMN_SIZE",
- "BUFFER_LENGTH",
- "DECIMAL_DIGITS",
- "NUM_PREC_RADIX",
- "NULLABLE",
- "REMARKS",
- "COLUMN_DEF",
- "SQL_DATA_TYPE",
- "SQL_DATETIME_SUB",
- "CHAR_OCTET_LENGTH",
- "ORDINAL_POSITION",
- "IS_NULLABLE",
- "SCOPE_CATALOG",
- "SCOPE_SCHEMA",
- "SCOPE_TABLE",
- "SOURCE_DATA_TYPE",
- "IS_AUTOINCREMENT",
- "IS_GENERATEDCOLUMN");
+ metaColumnFactory.getMetaColumnClass(),
+ metaColumnFactory.getColumnNames());
}
Enumerable catalogs() {
@@ -386,10 +469,8 @@ Enumerable tables(final MetaSchema schema_) {
requireNonNull(schema.calciteSchema.getTable(name, true),
() -> "table " + name + " is not found (case sensitive)")
.getTable();
- return new CalciteMetaTable(table,
- schema.tableCatalog,
- schema.tableSchem,
- name);
+ return metaTableFactory.createTable(table, schema.tableCatalog,
+ schema.tableSchem, name);
})
.concat(
Linq4j.asEnumerable(
@@ -397,7 +478,7 @@ Enumerable tables(final MetaSchema schema_) {
.entrySet())
.select(pair -> {
final Table table = pair.getValue();
- return new CalciteMetaTable(table,
+ return metaTableFactory.createTable(table,
schema.tableCatalog,
schema.tableSchem,
pair.getKey());
@@ -467,7 +548,8 @@ public Enumerable columns(final MetaTable table_) {
.map(RelDataType::getSqlTypeName)
.map(SqlTypeName::getJdbcOrdinal)
.orElse(field.getType().getSqlTypeName().getJdbcOrdinal());
- return new MetaColumn(
+ return metaColumnFactory.createColumn(
+ table.calciteTable,
table.tableCat,
table.tableSchem,
table.tableName,
@@ -492,21 +574,17 @@ public Enumerable columns(final MetaTable table_) {
Pat schemaPattern) {
final Predicate1 schemaMatcher = namedMatcher(schemaPattern);
return createResultSet(schemas(catalog).where(schemaMatcher),
- MetaSchema.class,
- "TABLE_SCHEM",
- "TABLE_CATALOG");
+ MetaSchema.class, SCHEMA_COLUMNS);
}
@Override public MetaResultSet getCatalogs(ConnectionHandle ch) {
return createResultSet(catalogs(),
- MetaCatalog.class,
- "TABLE_CAT");
+ MetaCatalog.class, CATALOG_COLUMNS);
}
@Override public MetaResultSet getTableTypes(ConnectionHandle ch) {
return createResultSet(tableTypes(),
- MetaTableType.class,
- "TABLE_TYPE");
+ MetaTableType.class, TABLE_TYPE_COLUMNS);
}
@Override public MetaResultSet getFunctions(ConnectionHandle ch,
@@ -520,13 +598,7 @@ public Enumerable columns(final MetaTable table_) {
.orderBy(x ->
(Comparable) FlatLists.of(
x.functionCat, x.functionSchem, x.functionName, x.specificName)),
- MetaFunction.class,
- "FUNCTION_CAT",
- "FUNCTION_SCHEM",
- "FUNCTION_NAME",
- "REMARKS",
- "FUNCTION_TYPE",
- "SPECIFIC_NAME");
+ MetaFunction.class, FUNCTION_COLUMNS);
}
Enumerable functions(final MetaSchema schema_, final String catalog) {
@@ -816,10 +888,18 @@ public static CalciteConnection connect(CalciteSchema schema,
}
/** Metadata describing a Calcite table. */
- private static class CalciteMetaTable extends MetaTable {
+ public static class CalciteMetaTable extends MetaTable {
private final Table calciteTable;
- CalciteMetaTable(Table calciteTable, String tableCat,
+ /**
+ * Creates a CalciteMetaTable.
+ *
+ * @param calciteTable Table
+ * @param tableCat Table catalog, or null
+ * @param tableSchem Table schema, or null
+ * @param tableName Table name
+ */
+ public CalciteMetaTable(Table calciteTable, String tableCat,
String tableSchem, String tableName) {
super(tableCat, tableSchem, tableName,
calciteTable.getJdbcTableType().jdbcName);
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaTableFactory.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaTableFactory.java
new file mode 100644
index 00000000000..16556d68a57
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaTableFactory.java
@@ -0,0 +1,42 @@
+/*
+ * 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.jdbc;
+
+import org.apache.calcite.avatica.MetaImpl.MetaTable;
+import org.apache.calcite.schema.Table;
+
+import java.util.List;
+
+/** Factory for creating instances of {@link MetaTable}.
+ *
+ * @see java.sql.DatabaseMetaData#getTables */
+public interface CalciteMetaTableFactory {
+ /** Instantiates a MetaTable. */
+ MetaTable createTable(Table table, String tableCat, String tableSchem,
+ String tableName);
+
+ /** Returns the list of expected column names.
+ *
+ * The default implementation returns the columns described in the JDBC
+ * specification. */
+ default List getColumnNames() {
+ return CalciteMetaImpl.TABLE_COLUMNS;
+ }
+
+ /** Returns the type of object created. Must be a subclass of MetaTable. */
+ Class extends MetaTable> getMetaTableClass();
+}
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaTableFactoryImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaTableFactoryImpl.java
new file mode 100644
index 00000000000..7b3709ac531
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaTableFactoryImpl.java
@@ -0,0 +1,45 @@
+/*
+ * 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.jdbc;
+
+import org.apache.calcite.avatica.MetaImpl.MetaTable;
+import org.apache.calcite.jdbc.CalciteMetaImpl.CalciteMetaTable;
+import org.apache.calcite.schema.Table;
+
+/** Default implementation of CalciteMetaTableFactory. */
+public class CalciteMetaTableFactoryImpl
+ implements CalciteMetaTableFactory {
+
+ /** Singleton instance. */
+ public static final CalciteMetaTableFactoryImpl INSTANCE =
+ new CalciteMetaTableFactoryImpl();
+
+ /** Internal constructor; protected to allow subclassing. */
+ protected CalciteMetaTableFactoryImpl() {}
+
+ @Override public CalciteMetaTable createTable(
+ Table table,
+ String tableCat,
+ String tableSchem,
+ String tableName) {
+ return new CalciteMetaTable(table, tableCat, tableSchem, tableName);
+ }
+
+ @Override public Class extends MetaTable> getMetaTableClass() {
+ return CalciteMetaTable.class;
+ }
+}
diff --git a/core/src/main/java/org/apache/calcite/jdbc/Driver.java b/core/src/main/java/org/apache/calcite/jdbc/Driver.java
index 20753ebd821..c5d2c0e206c 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/Driver.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/Driver.java
@@ -26,6 +26,7 @@
import org.apache.calcite.avatica.HandlerImpl;
import org.apache.calcite.avatica.Meta;
import org.apache.calcite.avatica.UnregisteredDriver;
+import org.apache.calcite.config.CalciteConnectionConfig;
import org.apache.calcite.config.CalciteConnectionProperty;
import org.apache.calcite.linq4j.function.Function0;
import org.apache.calcite.model.JsonSchema;
@@ -211,7 +212,16 @@ protected Function0 createPrepareFactory() {
}
@Override public Meta createMeta(AvaticaConnection connection) {
- return new CalciteMetaImpl((CalciteConnectionImpl) connection);
+ final CalciteConnectionConfig config =
+ (CalciteConnectionConfig) connection.config();
+ CalciteMetaTableFactory metaTableFactory =
+ config.metaTableFactory(CalciteMetaTableFactory.class,
+ CalciteMetaTableFactoryImpl.INSTANCE);
+ CalciteMetaColumnFactory metaColumnFactory =
+ config.metaColumnFactory(CalciteMetaColumnFactory.class,
+ CalciteMetaColumnFactoryImpl.INSTANCE);
+ return CalciteMetaImpl.create((CalciteConnectionImpl) connection,
+ metaTableFactory, metaColumnFactory);
}
/** Creates an internal connection. */
diff --git a/core/src/main/java/org/apache/calcite/rel/core/TableFunctionScan.java b/core/src/main/java/org/apache/calcite/rel/core/TableFunctionScan.java
index 87854e77cec..baeee2c19ec 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/TableFunctionScan.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/TableFunctionScan.java
@@ -53,8 +53,8 @@
*
* @see org.apache.calcite.rel.logical.LogicalTableFunctionScan
*/
-public abstract class TableFunctionScan extends AbstractRelNode implements
- Hintable {
+public abstract class TableFunctionScan extends AbstractRelNode
+ implements Hintable {
//~ Instance fields --------------------------------------------------------
private final RexNode rexCall;
diff --git a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
index 8415fcedc0c..e0dce8bebec 100644
--- a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
+++ b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
@@ -73,7 +73,6 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.function.Function;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
@@ -102,51 +101,6 @@ class CalciteRemoteDriverTest {
CalciteSystemProperty.DEBUG.value() ? Util.printWriter(System.out)
: new PrintWriter(new StringWriter());
- private static final Function GET_SCHEMAS =
- connection -> {
- try {
- return connection.getMetaData().getSchemas();
- } catch (SQLException e) {
- throw TestUtil.rethrow(e);
- }
- };
-
- private static final Function GET_CATALOGS =
- connection -> {
- try {
- return connection.getMetaData().getCatalogs();
- } catch (SQLException e) {
- throw TestUtil.rethrow(e);
- }
- };
-
- private static final Function GET_COLUMNS =
- connection -> {
- try {
- return connection.getMetaData().getColumns(null, null, null, null);
- } catch (SQLException e) {
- throw TestUtil.rethrow(e);
- }
- };
-
- private static final Function GET_TYPEINFO =
- connection -> {
- try {
- return connection.getMetaData().getTypeInfo();
- } catch (SQLException e) {
- throw TestUtil.rethrow(e);
- }
- };
-
- private static final Function GET_TABLE_TYPES =
- connection -> {
- try {
- return connection.getMetaData().getTableTypes();
- } catch (SQLException e) {
- throw TestUtil.rethrow(e);
- }
- };
-
private static @Nullable Connection localConnection;
private static @Nullable HttpServer start;
@@ -175,6 +129,54 @@ protected static Connection getRemoteConnection() throws SQLException {
}
}
+ private static ResultSet getSchemas(Connection connection) {
+ try {
+ return connection.getMetaData().getSchemas();
+ } catch (SQLException e) {
+ throw TestUtil.rethrow(e);
+ }
+ }
+
+ private static ResultSet getCatalogs(Connection connection) {
+ try {
+ return connection.getMetaData().getCatalogs();
+ } catch (SQLException e) {
+ throw TestUtil.rethrow(e);
+ }
+ }
+
+ private static ResultSet getColumns(Connection connection) {
+ try {
+ return connection.getMetaData().getColumns(null, null, null, null);
+ } catch (SQLException e) {
+ throw TestUtil.rethrow(e);
+ }
+ }
+
+ private static ResultSet getTables(Connection connection) {
+ try {
+ return connection.getMetaData().getTables(null, null, null, null);
+ } catch (SQLException e) {
+ throw TestUtil.rethrow(e);
+ }
+ }
+
+ private static ResultSet getTypeInfo(Connection connection) {
+ try {
+ return connection.getMetaData().getTypeInfo();
+ } catch (SQLException e) {
+ throw TestUtil.rethrow(e);
+ }
+ }
+
+ private static ResultSet getTableTypes(Connection connection) {
+ try {
+ return connection.getMetaData().getTableTypes();
+ } catch (SQLException e) {
+ throw TestUtil.rethrow(e);
+ }
+ }
+
@Test void testCatalogsLocal() throws Exception {
final Connection connection =
DriverManager.getConnection("jdbc:avatica:remote:factory=" + LJS);
@@ -263,39 +265,67 @@ protected static Connection getRemoteConnection() throws SQLException {
@Test void testRemoteCatalogs() {
CalciteAssert.hr()
.with(CalciteRemoteDriverTest::getRemoteConnection)
- .metaData(GET_CATALOGS)
+ .metaData(CalciteRemoteDriverTest::getCatalogs)
.returns("TABLE_CAT=null\n");
}
@Test void testRemoteSchemas() {
CalciteAssert.hr()
.with(CalciteRemoteDriverTest::getRemoteConnection)
- .metaData(GET_SCHEMAS)
+ .metaData(CalciteRemoteDriverTest::getSchemas)
.returns("TABLE_SCHEM=POST; TABLE_CATALOG=null\n"
+ "TABLE_SCHEM=foodmart; TABLE_CATALOG=null\n"
+ "TABLE_SCHEM=hr; TABLE_CATALOG=null\n"
+ "TABLE_SCHEM=metadata; TABLE_CATALOG=null\n");
}
+ /** Checks that the default {@code getColumns()} response
+ * contains the 24 standard columns specified in the JDBC specification
+ * and in the correct order. */
@Test void testRemoteColumns() {
CalciteAssert.hr()
.with(CalciteRemoteDriverTest::getRemoteConnection)
- .metaData(GET_COLUMNS)
- .returns(CalciteAssert.checkResultContains("COLUMN_NAME=EMPNO"));
+ .metaData(CalciteRemoteDriverTest::getColumns)
+ .returns(
+ CalciteAssert.checkResultContains("TABLE_CAT=null; "
+ + "TABLE_SCHEM=POST; TABLE_NAME=EMPS; COLUMN_NAME=EMPNO; "
+ + "DATA_TYPE=4; TYPE_NAME=INTEGER NOT NULL; COLUMN_SIZE=-1; "
+ + "BUFFER_LENGTH=null; DECIMAL_DIGITS=null; NUM_PREC_RADIX=10; "
+ + "NULLABLE=0; REMARKS=null; COLUMN_DEF=null; "
+ + "SQL_DATA_TYPE=null; SQL_DATETIME_SUB=null; "
+ + "CHAR_OCTET_LENGTH=-1; ORDINAL_POSITION=1; IS_NULLABLE=NO; "
+ + "SCOPE_CATALOG=null; SCOPE_SCHEMA=null; SCOPE_TABLE=null; "
+ + "SOURCE_DATA_TYPE=null; IS_AUTOINCREMENT=; "
+ + "IS_GENERATEDCOLUMN="));
+ }
+
+ /** Checks that the default {@code getTables()} response contains the 10
+ * standard columns specified in the JDBC specification and in the correct
+ * order. */
+ @Test void testRemoteTables() {
+ CalciteAssert.hr()
+ .with(CalciteRemoteDriverTest::getRemoteConnection)
+ .metaData(CalciteRemoteDriverTest::getTables)
+ .returns(
+ CalciteAssert.checkResultContains("TABLE_CAT=null; "
+ + "TABLE_SCHEM=POST; TABLE_NAME=DEPT; TABLE_TYPE=VIEW; "
+ + "REMARKS=null; TYPE_CAT=null; TYPE_SCHEM=null; "
+ + "TYPE_NAME=null; SELF_REFERENCING_COL_NAME=null; "
+ + "REF_GENERATION=null"));
}
@Test void testRemoteTypeInfo() {
// TypeInfo does not include internal types (NULL, SYMBOL, ANY, etc.)
CalciteAssert.hr()
.with(CalciteRemoteDriverTest::getRemoteConnection)
- .metaData(GET_TYPEINFO)
+ .metaData(CalciteRemoteDriverTest::getTypeInfo)
.returns(CalciteAssert.checkResultCount(is(41)));
}
@Test void testRemoteTableTypes() {
CalciteAssert.hr()
.with(CalciteRemoteDriverTest::getRemoteConnection)
- .metaData(GET_TABLE_TYPES)
+ .metaData(CalciteRemoteDriverTest::getTableTypes)
.returns("TABLE_TYPE=TABLE\n"
+ "TABLE_TYPE=VIEW\n");
}
@@ -553,7 +583,7 @@ private String pad(String x) {
public static Connection makeConnection(boolean withMeasures)
throws Exception {
- List employees = new ArrayList();
+ List employees = new ArrayList<>();
for (int i = 1; i <= 101; i++) {
employees.add(new Employee(i, 0, "first", 0f, null));
}
@@ -661,7 +691,7 @@ public static class LocalServiceMoreFactory implements Service.Factory {
try {
Connection conn = makeConnection();
final CalciteMetaImpl meta =
- new CalciteMetaImpl(conn.unwrap(CalciteConnectionImpl.class));
+ CalciteMetaImpl.create(conn.unwrap(CalciteConnection.class));
return new LocalService(meta);
} catch (Exception e) {
throw TestUtil.rethrow(e);
@@ -818,7 +848,7 @@ public static class Factory implements Meta.Factory {
public Meta create(List args) {
try {
final Connection connection = CalciteAssert.hr().connect();
- return new CalciteMetaImpl((CalciteConnectionImpl) connection);
+ return CalciteMetaImpl.create((CalciteConnection) connection);
} catch (Exception e) {
throw TestUtil.rethrow(e);
}
@@ -845,8 +875,7 @@ public static class LocalServiceModifiableFactory implements Service.Factory {
try {
Connection conn = JdbcFrontLinqBackTest.makeConnection();
final CalciteMetaImpl meta =
- new CalciteMetaImpl(
- conn.unwrap(CalciteConnectionImpl.class));
+ CalciteMetaImpl.create(conn.unwrap(CalciteConnection.class));
return new LocalService(meta);
} catch (Exception e) {
throw TestUtil.rethrow(e);
@@ -956,6 +985,6 @@ public static class LocalServiceModifiableFactory implements Service.Factory {
/**
* Remote PreparedStatement insert WITH bind variables.
*/
- @Test void testRemotePreparedStatementInsert2() throws Exception {
+ @Test void testRemotePreparedStatementInsert2() {
}
}
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcFrontJdbcBackTest.java b/core/src/test/java/org/apache/calcite/test/JdbcFrontJdbcBackTest.java
index 4bb84046b6f..4293e57c0f2 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcFrontJdbcBackTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcFrontJdbcBackTest.java
@@ -16,14 +16,23 @@
*/
package org.apache.calcite.test;
+import org.apache.calcite.avatica.MetaImpl.MetaTable;
+import org.apache.calcite.config.CalciteConnectionProperty;
+import org.apache.calcite.jdbc.CalciteMetaImpl;
+import org.apache.calcite.jdbc.CalciteMetaImpl.CalciteMetaTable;
+import org.apache.calcite.jdbc.CalciteMetaTableFactory;
+import org.apache.calcite.schema.Table;
import org.apache.calcite.util.TestUtil;
+import com.google.common.collect.ImmutableList;
+
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.List;
import static org.apache.calcite.test.CalciteAssert.that;
@@ -32,6 +41,7 @@
import static org.hamcrest.Matchers.hasToString;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Tests for a JDBC front-end and JDBC back-end.
@@ -73,6 +83,28 @@ class JdbcFrontJdbcBackTest {
});
}
+ @Test void testTablesExtraColumn() throws Exception {
+ that()
+ .with(CalciteAssert.Config.JDBC_FOODMART)
+ .with(
+ CalciteConnectionProperty.META_TABLE_FACTORY.camelName(),
+ MetaExtraTableFactoryImpl.class.getName())
+ .doWithConnection(connection -> {
+ try {
+ ResultSet rset =
+ connection.getMetaData().getTables(
+ null, null, null, null);
+ assertTrue(rset.next());
+ // Asserts that the number of columns in the result set equals
+ // MetaExtraTableFactoryImpl's expected number of columns.
+ assertEquals(rset.getMetaData().getColumnCount(), 11);
+ assertEquals(rset.getMetaData().getColumnName(11), "EXTRA_LABEL");
+ } catch (SQLException e) {
+ throw TestUtil.rethrow(e);
+ }
+ });
+ }
+
@Test void testTablesByType() throws Exception {
// check with the form recommended by JDBC
checkTablesByType("SYSTEM TABLE", is("COLUMNS;TABLES;"));
@@ -150,4 +182,43 @@ private void checkTablesByType(final String tableType,
.returns2("c0=11.4\n"
+ "c0=8.55\n");
}
+
+ /** Mock implementation of {@link CalciteMetaTable}. */
+ private static class MetaExtraTable extends CalciteMetaTable {
+ final String extraLabel;
+
+ MetaExtraTable(Table calciteTable, String tableCat,
+ String tableSchem, String tableName) {
+ super(calciteTable, tableCat, tableSchem, tableName);
+ this.extraLabel = "extraLabel1";
+ }
+ }
+
+ /** Mock implementation of {@link CalciteMetaTableFactory} that creates
+ * instances of {@link MetaExtraTable}. Must be public, otherwise it is
+ * inaccessible from {@link org.apache.calcite.jdbc.Driver}. */
+ public static class MetaExtraTableFactoryImpl
+ implements CalciteMetaTableFactory {
+ public static final MetaExtraTableFactoryImpl INSTANCE =
+ new MetaExtraTableFactoryImpl();
+
+ MetaExtraTableFactoryImpl() {}
+
+ @Override public MetaTable createTable(Table table, String tableCat,
+ String tableSchem, String tableName) {
+ return new MetaExtraTable(table, tableCat, tableSchem, tableName);
+ }
+
+ @Override public List getColumnNames() {
+ // 11 columns total.
+ return ImmutableList.builder()
+ .addAll(CalciteMetaImpl.TABLE_COLUMNS)
+ .add("EXTRA_LABEL")
+ .build();
+ }
+
+ @Override public Class extends MetaTable> getMetaTableClass() {
+ return MetaExtraTable.class;
+ }
+ }
}