blob: c2e555a2d10c5c55bc5820cd756d1e83e9555bc6 [file] [log] [blame]
/*
* 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.asterix.jdbc.core;
import java.sql.DatabaseMetaData;
import java.sql.JDBCType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class ADBMetaStatement extends ADBStatement {
public static final String SCHEMALESS = "SCHEMALESS";
public static final String TABLE = "TABLE";
public static final String VIEW = "VIEW";
private static final String PK_NAME_SUFFIX = "_pk";
private static final String FK_NAME_SUFFIX = "_fk";
public ADBMetaStatement(ADBConnection connection) {
super(connection);
}
protected void populateQueryProlog(StringBuilder sql, String comment) {
if (comment != null) {
sql.append("/* ").append(comment).append(" */\n");
}
//sql.append("set `compiler.min.memory.allocation` 'false';\n");
}
protected ADBResultSet executeGetCatalogsQuery() throws SQLException {
checkClosed();
StringBuilder sql = new StringBuilder(256);
populateQueryProlog(sql, "JDBC-GetCatalogs");
sql.append("select TABLE_CAT ");
sql.append("from Metadata.`Dataverse` ");
switch (connection.catalogDataverseMode) {
case CATALOG:
if (connection.isDatabaseEntitySupported()) {
sql.append("let TABLE_CAT = DatabaseName || '/' || DataverseName ");
} else {
sql.append("let TABLE_CAT = DataverseName ");
}
break;
case CATALOG_SCHEMA:
if (connection.isDatabaseEntitySupported()) {
sql.append("let TABLE_CAT = DatabaseName ");
} else {
sql.append("let name = decode_dataverse_name(DataverseName), ");
sql.append("TABLE_CAT = name[0] ");
sql.append("where (array_length(name) between 1 and 2) ");
}
sql.append("group by TABLE_CAT ");
break;
default:
throw new IllegalStateException();
}
sql.append("order by TABLE_CAT");
return executeQueryImpl(sql.toString(), null);
}
protected ADBResultSet executeGetSchemasQuery() throws SQLException {
String catalog;
switch (connection.catalogDataverseMode) {
case CATALOG:
catalog = connection.getDataverseCanonicalName();
break;
case CATALOG_SCHEMA:
catalog = connection.getCatalog();
break;
default:
throw new IllegalStateException();
}
return executeGetSchemasQuery(catalog, null, "0");
}
protected ADBResultSet executeGetSchemasQuery(String catalog, String schemaPattern) throws SQLException {
return executeGetSchemasQuery(catalog, schemaPattern, "1");
}
protected ADBResultSet executeGetSchemasQuery(String catalog, String schemaPattern, String tag)
throws SQLException {
checkClosed();
StringBuilder sql = new StringBuilder(512);
populateQueryProlog(sql, "JDBC-GetSchemas-" + tag);
sql.append("select TABLE_SCHEM, TABLE_CATALOG ");
sql.append("from Metadata.`Dataverse` ");
sql.append("let ");
switch (connection.catalogDataverseMode) {
case CATALOG:
if (connection.isDatabaseEntitySupported()) {
sql.append("TABLE_CATALOG = DatabaseName || '/' || DataverseName, ");
} else {
sql.append("TABLE_CATALOG = DataverseName, ");
}
sql.append("TABLE_SCHEM = null ");
sql.append("where true ");
break;
case CATALOG_SCHEMA:
if (connection.isDatabaseEntitySupported()) {
sql.append("TABLE_CATALOG = DatabaseName, ");
sql.append("TABLE_SCHEM = DataverseName ");
} else {
sql.append("name = decode_dataverse_name(DataverseName), ");
sql.append("TABLE_CATALOG = name[0], ");
sql.append("TABLE_SCHEM = case array_length(name) when 1 then null else name[1] end ");
sql.append("where (array_length(name) between 1 and 2) ");
}
break;
default:
throw new IllegalStateException();
}
if (catalog != null) {
sql.append("and (TABLE_CATALOG = $1) ");
}
if (schemaPattern != null) {
sql.append("and (if_null(TABLE_SCHEM, '') like $2) ");
}
sql.append("order by TABLE_CATALOG, TABLE_SCHEM");
return executeQueryImpl(sql.toString(), Arrays.asList(catalog, schemaPattern));
}
protected ADBResultSet executeGetTablesQuery(String catalog, String schemaPattern, String tableNamePattern,
String[] types) throws SQLException {
checkClosed();
String datasetTermTabular = getDatasetTerm(true);
String datasetTermNonTabular = getDatasetTerm(false);
String viewTermTabular = getViewTerm(true);
String viewTermNonTabular = getViewTerm(false);
StringBuilder sql = new StringBuilder(1024);
populateQueryProlog(sql, "JDBC-GetTables");
sql.append("select TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, null REMARKS, null TYPE_CAT, ");
sql.append("null TYPE_SCHEM, null TYPE_NAME, null SELF_REFERENCING_COL_NAME, null REF_GENERATION ");
sql.append("from Metadata.`Dataset` ds join Metadata.`Datatype` dt ");
sql.append("on ds.DatatypeDataverseName = dt.DataverseName and ds.DatatypeName = dt.DatatypeName ");
if (connection.isDatabaseEntitySupported()) {
sql.append("and ds.DatatypeDatabaseName = dt.DatabaseName ");
}
sql.append("let ");
switch (connection.catalogDataverseMode) {
case CATALOG:
if (connection.isDatabaseEntitySupported()) {
sql.append("TABLE_CAT = ds.DatabaseName || '/' || ds.DataverseName, ");
} else {
sql.append("TABLE_CAT = ds.DataverseName, ");
}
sql.append("TABLE_SCHEM = null, ");
break;
case CATALOG_SCHEMA:
if (connection.isDatabaseEntitySupported()) {
sql.append("TABLE_CAT = ds.DatabaseName, ");
sql.append("TABLE_SCHEM = ds.DataverseName, ");
} else {
sql.append("dvname = decode_dataverse_name(ds.DataverseName), ");
sql.append("TABLE_CAT = dvname[0], ");
sql.append("TABLE_SCHEM = case array_length(dvname) when 1 then null else dvname[1] end, ");
}
break;
default:
throw new IllegalStateException();
}
sql.append("TABLE_NAME = ds.DatasetName, ");
sql.append("isDataset = (ds.DatasetType = 'INTERNAL' or ds.DatasetType = 'EXTERNAL'), ");
sql.append("isView = ds.DatasetType = 'VIEW', ");
sql.append("hasFields = array_length(dt.Derived.Record.Fields) > 0, ");
sql.append("TABLE_TYPE = case ");
sql.append("when isDataset then (case when hasFields then '").append(datasetTermTabular).append("' else '")
.append(datasetTermNonTabular).append("' end) ");
sql.append("when isView then (case when hasFields then '").append(viewTermTabular).append("' else '")
.append(viewTermNonTabular).append("' end) ");
sql.append("else null end ");
sql.append("where ");
sql.append("(TABLE_TYPE ").append(types != null ? "in $1" : "is not null").append(") ");
if (catalog != null) {
sql.append("and (TABLE_CAT = $2) ");
}
if (schemaPattern != null) {
sql.append("and (if_null(TABLE_SCHEM, '') like $3) ");
}
if (tableNamePattern != null) {
sql.append("and (TABLE_NAME like $4) ");
}
switch (connection.catalogDataverseMode) {
case CATALOG:
break;
case CATALOG_SCHEMA:
if (!connection.isDatabaseEntitySupported()) {
sql.append("and (array_length(dvname) between 1 and 2) ");
}
break;
default:
throw new IllegalStateException();
}
if (!connection.catalogIncludesSchemaless) {
sql.append("and hasFields ");
}
sql.append("order by TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, TABLE_NAME");
List<String> typesList = types != null ? Arrays.asList(types) : null;
return executeQueryImpl(sql.toString(), Arrays.asList(typesList, catalog, schemaPattern, tableNamePattern));
}
protected ADBResultSet executeGetColumnsQuery(String catalog, String schemaPattern, String tableNamePattern,
String columnNamePattern) throws SQLException {
checkClosed();
StringBuilder sql = new StringBuilder(2048);
populateQueryProlog(sql, "JDBC-GetColumns");
sql.append("select TABLE_CAT, TABLE_SCHEM, TABLE_NAME, COLUMN_NAME, DATA_TYPE, TYPE_NAME, COLUMN_SIZE, ");
sql.append("1 BUFFER_LENGTH, null DECIMAL_DIGITS, 2 NUM_PREC_RADIX, NULLABLE, ");
sql.append("null REMARKS, null COLUMN_DEF, DATA_TYPE SQL_DATA_TYPE,");
sql.append("0 SQL_DATETIME_SUB, COLUMN_SIZE CHAR_OCTET_LENGTH, ORDINAL_POSITION, ");
sql.append("case NULLABLE when 0 then 'NO' else 'YES' end IS_NULLABLE, ");
sql.append("null SCOPE_CATALOG, null SCOPE_SCHEMA, null SCOPE_TABLE, null SOURCE_DATA_TYPE, ");
sql.append("'NO' IS_AUTOINCREMENT, 'NO' IS_GENERATEDCOLUMN ");
sql.append("from Metadata.`Dataset` ds ");
sql.append("join Metadata.`Datatype` dt ");
sql.append("on ds.DatatypeDataverseName = dt.DataverseName and ds.DatatypeName = dt.DatatypeName ");
if (connection.isDatabaseEntitySupported()) {
sql.append("and ds.DatatypeDatabaseName = dt.DatabaseName ");
}
sql.append("unnest dt.Derived.Record.Fields as field at fieldpos ");
sql.append("left join Metadata.`Datatype` dt2 ");
sql.append(
"on field.FieldType = dt2.DatatypeName and ds.DataverseName = dt2.DataverseName and dt2.Derived is known ");
if (connection.isDatabaseEntitySupported()) {
sql.append("and ds.DatabaseName = dt2.DatabaseName ");
}
sql.append("let ");
switch (connection.catalogDataverseMode) {
case CATALOG:
if (connection.isDatabaseEntitySupported()) {
sql.append("TABLE_CAT = ds.DatabaseName || '/' || ds.DataverseName, ");
} else {
sql.append("TABLE_CAT = ds.DataverseName, ");
}
sql.append("TABLE_SCHEM = null, ");
break;
case CATALOG_SCHEMA:
if (connection.isDatabaseEntitySupported()) {
sql.append("TABLE_CAT = ds.DatabaseName, ");
sql.append("TABLE_SCHEM = ds.DataverseName, ");
} else {
sql.append("dvname = decode_dataverse_name(ds.DataverseName), ");
sql.append("TABLE_CAT = dvname[0], ");
sql.append("TABLE_SCHEM = case array_length(dvname) when 1 then null else dvname[1] end, ");
}
break;
default:
throw new IllegalStateException();
}
sql.append("TABLE_NAME = ds.DatasetName, ");
sql.append("COLUMN_NAME = field.FieldName, ");
sql.append("TYPE_NAME = case ");
for (ADBDatatype nestedType : new ADBDatatype[] { ADBDatatype.OBJECT, ADBDatatype.ARRAY,
ADBDatatype.MULTISET }) {
sql.append(String.format("when dt2.Derived.%s is known then '%s' ",
ADBDatatype.getDerivedRecordName(nestedType), nestedType.getTypeName()));
}
sql.append("else field.FieldType end, ");
sql.append("DATA_TYPE = ");
sql.append("case TYPE_NAME ");
for (ADBDatatype type : ADBDatatype.values()) {
JDBCType jdbcType = type.getJdbcType();
if (type.isNullOrMissing() || jdbcType.equals(JDBCType.OTHER)) {
// will be handled by the 'else' clause
continue;
}
sql.append("when '").append(type.getTypeName()).append("' ");
sql.append("then ").append(jdbcType.getVendorTypeNumber()).append(" ");
}
sql.append("else ").append(JDBCType.OTHER.getVendorTypeNumber()).append(" end, ");
sql.append("COLUMN_SIZE = case field.FieldType when 'string' then 32767 else 8 end, "); // TODO:based on type
sql.append("ORDINAL_POSITION = fieldpos, ");
sql.append("NULLABLE = case when field.IsNullable or field.IsMissable then 1 else 0 end ");
sql.append("where (array_length(dt.Derived.Record.Fields) > 0) ");
if (catalog != null) {
sql.append("and (TABLE_CAT = $1) ");
}
if (schemaPattern != null) {
sql.append("and (if_null(TABLE_SCHEM, '') like $2) ");
}
if (tableNamePattern != null) {
sql.append("and (TABLE_NAME like $3) ");
}
if (columnNamePattern != null) {
sql.append("and (COLUMN_NAME like $4) ");
}
switch (connection.catalogDataverseMode) {
case CATALOG:
break;
case CATALOG_SCHEMA:
if (!connection.isDatabaseEntitySupported()) {
sql.append("and (array_length(dvname) between 1 and 2) ");
}
break;
default:
throw new IllegalStateException();
}
sql.append("order by TABLE_CAT, TABLE_SCHEM, TABLE_NAME, ORDINAL_POSITION");
return executeQueryImpl(sql.toString(),
Arrays.asList(catalog, schemaPattern, tableNamePattern, columnNamePattern));
}
protected ADBResultSet executeGetPrimaryKeysQuery(String catalog, String schema, String table) throws SQLException {
checkClosed();
StringBuilder sql = new StringBuilder(1024);
populateQueryProlog(sql, "JDBC-GetPrimaryKeys");
sql.append("select TABLE_CAT, TABLE_SCHEM, TABLE_NAME, COLUMN_NAME, KEY_SEQ, PK_NAME ");
sql.append("from Metadata.`Dataset` ds ");
sql.append("join Metadata.`Datatype` dt ");
sql.append("on ds.DatatypeDataverseName = dt.DataverseName and ds.DatatypeName = dt.DatatypeName ");
if (connection.isDatabaseEntitySupported()) {
sql.append("and ds.DatatypeDatabaseName = dt.DatabaseName ");
}
sql.append("unnest coalesce(ds.InternalDetails, ds.ExternalDetails, ds.ViewDetails).PrimaryKey pki at pkipos ");
sql.append("let ");
sql.append("hasFields = array_length(dt.Derived.Record.Fields) > 0, ");
switch (connection.catalogDataverseMode) {
case CATALOG:
if (connection.isDatabaseEntitySupported()) {
sql.append("TABLE_CAT = ds.DatabaseName || '/' || ds.DataverseName, ");
} else {
sql.append("TABLE_CAT = ds.DataverseName, ");
}
sql.append("TABLE_SCHEM = null, ");
break;
case CATALOG_SCHEMA:
if (connection.isDatabaseEntitySupported()) {
sql.append("TABLE_CAT = ds.DatabaseName, ");
sql.append("TABLE_SCHEM = ds.DataverseName, ");
} else {
sql.append("dvname = decode_dataverse_name(ds.DataverseName), ");
sql.append("TABLE_CAT = dvname[0], ");
sql.append("TABLE_SCHEM = case array_length(dvname) when 1 then null else dvname[1] end, ");
}
break;
default:
throw new IllegalStateException();
}
sql.append("TABLE_NAME = ds.DatasetName, ");
sql.append("COLUMN_NAME = pki[0], ");
sql.append("KEY_SEQ = pkipos, ");
sql.append("PK_NAME = TABLE_NAME || '").append(PK_NAME_SUFFIX).append("', ");
sql.append("dsDetails = coalesce(ds.InternalDetails, ds.ExternalDetails, ds.ViewDetails) ");
sql.append("where (every pk in dsDetails.PrimaryKey satisfies array_length(pk) = 1 end) ");
sql.append("and (every si in dsDetails.KeySourceIndicator satisfies si = 0 end ) ");
if (catalog != null) {
sql.append("and (TABLE_CAT = $1) ");
}
if (schema != null) {
sql.append("and (if_null(TABLE_SCHEM, '') like $2) ");
}
if (table != null) {
sql.append("and (TABLE_NAME like $3) ");
}
switch (connection.catalogDataverseMode) {
case CATALOG:
break;
case CATALOG_SCHEMA:
if (!connection.isDatabaseEntitySupported()) {
sql.append("and (array_length(dvname) between 1 and 2) ");
}
break;
default:
throw new IllegalStateException();
}
if (!connection.catalogIncludesSchemaless) {
sql.append("and hasFields ");
}
sql.append("order by COLUMN_NAME");
return executeQueryImpl(sql.toString(), Arrays.asList(catalog, schema, table));
}
protected ADBResultSet executeGetImportedKeysQuery(String catalog, String schema, String table)
throws SQLException {
return executeGetImportedExportedKeysQuery("JDBC-GetImportedKeys", null, null, null, catalog, schema, table,
false);
}
protected ADBResultSet executeGetExportedKeysQuery(String catalog, String schema, String table)
throws SQLException {
return executeGetImportedExportedKeysQuery("JDBC-GetExportedKeys", catalog, schema, table, null, null, null,
true);
}
protected ADBResultSet executeCrossReferenceQuery(String parentCatalog, String parentSchema, String parentTable,
String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException {
return executeGetImportedExportedKeysQuery("JDBC-CrossReference", parentCatalog, parentSchema, parentTable,
foreignCatalog, foreignSchema, foreignTable, true);
}
protected ADBResultSet executeGetImportedExportedKeysQuery(String comment, String pkCatalog, String pkSchema,
String pkTable, String fkCatalog, String fkSchema, String fkTable, boolean orderByFk) throws SQLException {
StringBuilder sql = new StringBuilder(2048);
populateQueryProlog(sql, comment);
sql.append("select PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, PKCOLUMN_NAME, ");
sql.append("FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, FKCOLUMN_NAME, KEY_SEQ, ");
sql.append(DatabaseMetaData.importedKeyNoAction).append(" UPDATE_RULE, ");
sql.append(DatabaseMetaData.importedKeyNoAction).append(" DELETE_RULE, ");
sql.append("FK_NAME, PK_NAME, ");
sql.append(DatabaseMetaData.importedKeyInitiallyDeferred).append(" DEFERRABILITY ");
sql.append("from Metadata.`Dataset` ds ");
sql.append("join Metadata.`Datatype` dt ");
sql.append("on ds.DatatypeDataverseName = dt.DataverseName and ds.DatatypeName = dt.DatatypeName ");
if (connection.isDatabaseEntitySupported()) {
sql.append("and ds.DatatypeDatabaseName = dt.DatabaseName ");
}
sql.append("unnest coalesce(ds.InternalDetails, ds.ExternalDetails, ds.ViewDetails).ForeignKeys fk at fkpos ");
sql.append("join Metadata.`Dataset` ds2 ");
sql.append("on fk.RefDataverseName = ds2.DataverseName and fk.RefDatasetName = ds2.DatasetName ");
if (connection.isDatabaseEntitySupported()) {
sql.append("and fk.RefDatabaseName = ds2.DatabaseName ");
}
sql.append("unnest fk.ForeignKey fki at fkipos ");
sql.append("let ");
sql.append("hasFields = array_length(dt.Derived.Record.Fields) > 0, ");
switch (connection.catalogDataverseMode) {
case CATALOG:
if (connection.isDatabaseEntitySupported()) {
sql.append("FKTABLE_CAT = ds.DatabaseName || '/' || ds.DataverseName, ");
sql.append("PKTABLE_CAT = ds2.DatabaseName || '/' || ds2.DataverseName, ");
} else {
sql.append("FKTABLE_CAT = ds.DataverseName, ");
sql.append("PKTABLE_CAT = ds2.DataverseName, ");
}
sql.append("FKTABLE_SCHEM = null, ");
sql.append("PKTABLE_SCHEM = null, ");
break;
case CATALOG_SCHEMA:
if (connection.isDatabaseEntitySupported()) {
sql.append("FKTABLE_CAT = ds.DatabaseName, ");
sql.append("FKTABLE_SCHEM = ds.DataverseName, ");
sql.append("PKTABLE_CAT = ds2.DatabaseName, ");
sql.append("PKTABLE_SCHEM = ds2.DataverseName, ");
} else {
sql.append("dvname = decode_dataverse_name(ds.DataverseName), ");
sql.append("FKTABLE_CAT = dvname[0], ");
sql.append("FKTABLE_SCHEM = case array_length(dvname) when 1 then null else dvname[1] end, ");
sql.append("dvname2 = decode_dataverse_name(ds2.DataverseName), ");
sql.append("PKTABLE_CAT = dvname2[0], ");
sql.append("PKTABLE_SCHEM = case array_length(dvname2) when 1 then null else dvname2[1] end, ");
}
break;
default:
throw new IllegalStateException();
}
sql.append("ds2Details = coalesce(ds2.InternalDetails, ds2.ExternalDetails, ds2.ViewDetails), ");
sql.append("FKTABLE_NAME = ds.DatasetName, ");
sql.append("PKTABLE_NAME = ds2.DatasetName, ");
sql.append("FKCOLUMN_NAME = fki[0], ");
sql.append("PKCOLUMN_NAME = ds2Details.PrimaryKey[fkipos-1][0], ");
sql.append("KEY_SEQ = fkipos, ");
sql.append("PK_NAME = PKTABLE_NAME || '").append(PK_NAME_SUFFIX).append("', ");
sql.append("FK_NAME = FKTABLE_NAME || '").append(FK_NAME_SUFFIX).append("_' || string(fkpos) ");
sql.append("where (every fki2 in fk.ForeignKey satisfies array_length(fki2) = 1 end) ");
sql.append("and (every fksi in fk.KeySourceIndicator satisfies fksi = 0 end ) ");
sql.append("and (every pki in ds2Details.PrimaryKey satisfies array_length(pki) = 1 end) ");
sql.append("and (every pksi in ds2Details.KeySourceIndicator satisfies pksi = 0 end) ");
if (pkCatalog != null) {
sql.append("and (").append("PKTABLE_CAT").append(" = $1) ");
}
if (pkSchema != null) {
sql.append("and (if_null(").append("PKTABLE_SCHEM").append(", '') like $2) ");
}
if (pkTable != null) {
sql.append("and (").append("PKTABLE_NAME").append(" like $3) ");
}
if (fkCatalog != null) {
sql.append("and (").append("FKTABLE_CAT").append(" = $4) ");
}
if (fkSchema != null) {
sql.append("and (if_null(").append("FKTABLE_SCHEM").append(", '') like $5) ");
}
if (fkTable != null) {
sql.append("and (").append("FKTABLE_NAME").append(" like $6) ");
}
switch (connection.catalogDataverseMode) {
case CATALOG:
break;
case CATALOG_SCHEMA:
if (!connection.isDatabaseEntitySupported()) {
sql.append("and (array_length(dvname) between 1 and 2) ");
sql.append("and (array_length(dvname2) between 1 and 2) ");
}
break;
default:
throw new IllegalStateException();
}
if (!connection.catalogIncludesSchemaless) {
sql.append("and hasFields ");
}
sql.append("order by ").append(
orderByFk ? "FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME" : "PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME")
.append(", KEY_SEQ");
return executeQueryImpl(sql.toString(),
Arrays.asList(pkCatalog, pkSchema, pkTable, fkCatalog, fkSchema, fkTable));
}
protected ADBResultSet executeGetTableTypesQuery() throws SQLException {
checkClosed();
LinkedHashSet<String> tableTypes = new LinkedHashSet<>();
tableTypes.add(getDatasetTerm(true));
tableTypes.add(getViewTerm(true));
if (connection.catalogIncludesSchemaless) {
tableTypes.add(getDatasetTerm(false));
tableTypes.add(getViewTerm(false));
}
List<ADBColumn> columns = Collections.singletonList(new ADBColumn("TABLE_TYPE", ADBDatatype.STRING, false));
AbstractValueSerializer stringSer = getADMFormatSerializer(String.class);
ArrayNode result =
(ArrayNode) connection.protocol.getDriverContext().getGenericObjectReader().createArrayNode();
for (String tableType : tableTypes) {
result.addObject().put("TABLE_TYPE", stringSer.serializeToString(tableType));
}
return createSystemResultSet(columns, result);
}
protected ADBResultSet executeGetTypeInfoQuery() throws SQLException {
checkClosed();
AbstractValueSerializer int16Ser = getADMFormatSerializer(Short.class);
AbstractValueSerializer int32Ser = getADMFormatSerializer(Integer.class);
AbstractValueSerializer stringSer = getADMFormatSerializer(String.class);
List<ADBColumn> columns = new ArrayList<>();
columns.add(new ADBColumn("TYPE_NAME", ADBDatatype.STRING, false));
columns.add(new ADBColumn("DATA_TYPE", ADBDatatype.INTEGER, false));
columns.add(new ADBColumn("PRECISION", ADBDatatype.INTEGER, true));
columns.add(new ADBColumn("LITERAL_PREFIX", ADBDatatype.STRING, true));
columns.add(new ADBColumn("LITERAL_SUFFIX", ADBDatatype.STRING, true));
columns.add(new ADBColumn("CREATE_PARAMS", ADBDatatype.STRING, true));
columns.add(new ADBColumn("NULLABLE", ADBDatatype.SMALLINT, true));
columns.add(new ADBColumn("CASE_SENSITIVE", ADBDatatype.BOOLEAN, true));
columns.add(new ADBColumn("SEARCHABLE", ADBDatatype.SMALLINT, true));
columns.add(new ADBColumn("UNSIGNED_ATTRIBUTE", ADBDatatype.BOOLEAN, true));
columns.add(new ADBColumn("FIXED_PREC_SCALE", ADBDatatype.BOOLEAN, true));
columns.add(new ADBColumn("AUTO_INCREMENT", ADBDatatype.BOOLEAN, true));
columns.add(new ADBColumn("LOCAL_TYPE_NAME", ADBDatatype.STRING, true));
columns.add(new ADBColumn("MINIMUM_SCALE", ADBDatatype.SMALLINT, true));
columns.add(new ADBColumn("MAXIMUM_SCALE", ADBDatatype.SMALLINT, true));
columns.add(new ADBColumn("SQL_DATA_TYPE", ADBDatatype.INTEGER, true));
columns.add(new ADBColumn("SQL_DATETIME_SUB", ADBDatatype.INTEGER, true));
columns.add(new ADBColumn("NUM_PREC_RADIX", ADBDatatype.INTEGER, true));
ArrayNode result =
(ArrayNode) connection.protocol.getDriverContext().getGenericObjectReader().createArrayNode();
populateTypeInfo(result.addObject(), ADBDatatype.BOOLEAN, 1, null, null, null, null, null, null, int16Ser,
int32Ser, stringSer);
populateTypeInfo(result.addObject(), ADBDatatype.TINYINT, 3, 10, 0, 0, false, null, null, int16Ser, int32Ser,
stringSer);
populateTypeInfo(result.addObject(), ADBDatatype.SMALLINT, 5, 10, 0, 0, false, null, null, int16Ser, int32Ser,
stringSer);
populateTypeInfo(result.addObject(), ADBDatatype.INTEGER, 10, 10, 0, 0, false, null, null, int16Ser, int32Ser,
stringSer);
populateTypeInfo(result.addObject(), ADBDatatype.BIGINT, 19, 10, 0, 0, false, null, null, int16Ser, int32Ser,
stringSer);
populateTypeInfo(result.addObject(), ADBDatatype.FLOAT, 7, 2, 0, 0, false, null, null, int16Ser, int32Ser,
stringSer);
populateTypeInfo(result.addObject(), ADBDatatype.DOUBLE, 15, 2, 0, 0, false, null, null, int16Ser, int32Ser,
stringSer);
populateTypeInfo(result.addObject(), ADBDatatype.DATE, 32, null, 0, 0, false, null, null, int16Ser, int32Ser,
stringSer); // TODO:precision
populateTypeInfo(result.addObject(), ADBDatatype.TIME, 32, null, 0, 0, false, null, null, int16Ser, int32Ser,
stringSer); // TODO:precision
populateTypeInfo(result.addObject(), ADBDatatype.DATETIME, 32, null, 0, 0, false, null, null, int16Ser,
int32Ser, stringSer); // TODO:precision
populateTypeInfo(result.addObject(), ADBDatatype.YEARMONTHDURATION, 32, null, 0, 0, false, null, null, int16Ser,
int32Ser, stringSer); // TODO:precision
populateTypeInfo(result.addObject(), ADBDatatype.DAYTIMEDURATION, 32, null, 0, 0, false, null, null, int16Ser,
int32Ser, stringSer); // TODO:precision
populateTypeInfo(result.addObject(), ADBDatatype.DURATION, 32, null, 0, 0, false, null, null, int16Ser,
int32Ser, stringSer); // TODO:precision
populateTypeInfo(result.addObject(), ADBDatatype.STRING, 32767, null, null, null, true, "'", "'", int16Ser,
int32Ser, stringSer);
populateTypeInfo(result.addObject(), ADBDatatype.ARRAY, 32767, null, 0, 0, false, null, null, int16Ser,
int32Ser, stringSer);
populateTypeInfo(result.addObject(), ADBDatatype.OBJECT, 32767, null, 0, 0, false, null, null, int16Ser,
int32Ser, stringSer);
return createSystemResultSet(columns, result);
}
protected void populateTypeInfo(ObjectNode typeInfo, ADBDatatype type, int precision, Integer precisionRadix,
Integer minScale, Integer maxScale, Boolean searchable, String literalPrefix, String literalSuffix,
ADBPreparedStatement.AbstractValueSerializer int16Ser,
ADBPreparedStatement.AbstractValueSerializer int32Ser,
ADBPreparedStatement.AbstractValueSerializer stringSer) {
typeInfo.put("TYPE_NAME", stringSer.serializeToString(type.getTypeName()));
typeInfo.put("DATA_TYPE", int32Ser.serializeToString(type.getJdbcType().getVendorTypeNumber()));
typeInfo.put("PRECISION", int32Ser.serializeToString(precision));
typeInfo.put("LITERAL_PREFIX", literalPrefix != null ? stringSer.serializeToString(literalPrefix) : null);
typeInfo.put("LITERAL_SUFFIX", literalSuffix != null ? stringSer.serializeToString(literalSuffix) : null);
typeInfo.putNull("CREATE_PARAMS");
typeInfo.put("NULLABLE", int16Ser.serializeToString((short) DatabaseMetaData.typeNullable));
typeInfo.put("CASE_SENSITIVE", false);
typeInfo.put("SEARCHABLE",
int16Ser.serializeToString((short) (searchable == null ? DatabaseMetaData.typePredNone
: searchable ? DatabaseMetaData.typeSearchable : DatabaseMetaData.typePredBasic)));
typeInfo.put("UNSIGNED_ATTRIBUTE", false);
typeInfo.put("FIXED_PREC_SCALE", false);
typeInfo.putNull("AUTO_INCREMENT");
typeInfo.putNull("LOCAL_TYPE_NAME");
typeInfo.put("MINIMUM_SCALE", minScale != null ? int16Ser.serializeToString(minScale.shortValue()) : null);
typeInfo.put("MAXIMUM_SCALE", maxScale != null ? int16Ser.serializeToString(maxScale.shortValue()) : null);
typeInfo.put("SQL_DATA_TYPE", int32Ser.serializeToString(type.getTypeTag()));
typeInfo.putNull("SQL_DATETIME_SUB");
typeInfo.put("NUM_PREC_RADIX", int32Ser.serializeToString(precisionRadix != null ? precisionRadix : 10));
}
protected ADBResultSet executeEmptyResultQuery() throws SQLException {
checkClosed();
return createEmptyResultSet();
}
@Override
protected ADBStatement getResultSetStatement(ADBResultSet rs) {
return null;
}
@Override
protected ADBProtocolBase.SubmitStatementOptions createSubmitStatementOptions() {
ADBProtocolBase.SubmitStatementOptions options = super.createSubmitStatementOptions();
// Metadata queries are always executed in SQL++ mode
options.sqlCompatMode = false;
return options;
}
protected String getDatasetTerm(boolean tabular) {
return tabular ? TABLE : SCHEMALESS + " " + TABLE;
}
protected String getViewTerm(boolean tabular) {
return tabular ? VIEW : SCHEMALESS + " " + VIEW;
}
}