All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ing.data.cassandra.jdbc.metadata.ColumnMetadataResultSetBuilder Maven / Gradle / Ivy

There is a newer version: 4.13.1
Show newest version
/*
 *
 *   Licensed 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 com.ing.data.cassandra.jdbc.metadata;

import com.datastax.oss.driver.api.core.type.DataTypes;
import com.ing.data.cassandra.jdbc.CassandraMetadataResultSet;
import com.ing.data.cassandra.jdbc.CassandraStatement;
import com.ing.data.cassandra.jdbc.types.AbstractJdbcType;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.concurrent.atomic.AtomicInteger;

import static com.ing.data.cassandra.jdbc.ColumnDefinitions.Definition.buildDefinitionInAnonymousTable;
import static com.ing.data.cassandra.jdbc.types.AbstractJdbcType.DEFAULT_PRECISION;
import static com.ing.data.cassandra.jdbc.types.TypesMap.getTypeForComparator;

/**
 * Utility class building metadata result sets ({@link CassandraMetadataResultSet} objects) related to columns.
 */
public class ColumnMetadataResultSetBuilder extends AbstractMetadataResultSetBuilder {

    private static final Logger LOG = LoggerFactory.getLogger(ColumnMetadataResultSetBuilder.class);

    /**
     * Constructor.
     *
     * @param statement The statement.
     * @throws SQLException if a database access error occurs or this statement is closed.
     */
    public ColumnMetadataResultSetBuilder(final CassandraStatement statement) throws SQLException {
        super(statement);
    }

    /**
     * Builds a valid result set of the description of the table columns available in the given catalog (Cassandra
     * cluster).
     * This method is used to implement the method {@link DatabaseMetaData#getColumns(String, String, String, String)}.
     * 

* Only table descriptions matching the catalog, schema, table and column name criteria are returned. They are * ordered by {@code TABLE_CAT}, {@code TABLE_SCHEM}, {@code TABLE_NAME} and {@code ORDINAL_POSITION}. *

*

* The columns of this result set are: *

    *
  1. TABLE_CAT String => table catalog, may be {@code null}: here is the Cassandra cluster name * (if available).
  2. *
  3. TABLE_SCHEM String => table schema, may be {@code null}: here is the keyspace the table is * member of.
  4. *
  5. TABLE_NAME String => table name.
  6. *
  7. COLUMN_NAME String => column name.
  8. *
  9. DATA_TYPE int => SQL type from {@link Types}.
  10. *
  11. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully * qualified.
  12. *
  13. COLUMN_SIZE int => column size.
  14. *
  15. BUFFER_LENGTH int => not used: always 0 here.
  16. *
  17. DECIMAL_DIGITS int => the number of fractional digits, {@code null} is returned for data * types where it is not applicable. Always {@code null} here.
  18. *
  19. NUM_PREC_RADIX int => Radix (typically either 10 or 2).
  20. *
  21. NULLABLE int => is {@code NULL} allowed: *
      *
    • {@link DatabaseMetaData#columnNoNulls} - might not allow {@code NULL} values
    • *
    • {@link DatabaseMetaData#columnNullable} - definitely allows {@code NULL} values
    • *
    • {@link DatabaseMetaData#columnNullableUnknown} - nullability unknown
    • *
    Always {@link DatabaseMetaData#columnNoNulls} here. *
  22. *
  23. REMARKS String => comment describing column, may be {@code null}: * always {@code null} here since comments on columns does not exist in Cassandra.
  24. *
  25. COLUMN_DEF String => default value for the column, which should be interpreted as a string * when the value is enclosed in single quotes, may be {@code null}. Always {@code null} here.
  26. *
  27. SQL_DATA_TYPE int => is not used: always {@code null} here.
  28. *
  29. SQL_DATETIME_SUB int => is not used: always {@code null} here.
  30. *
  31. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column.
  32. *
  33. ORDINAL_POSITION int => index of column in table (starting at 1).
  34. *
  35. IS_NULLABLE String => ISO rules are used to determine the nullability for a column: *
      *
    • YES - if the column can include {@code NULL}s
    • *
    • NO - if the column cannot include {@code NULL}s
    • *
    • empty string - if the nullability for the column is unknown
    • *
    Always empty here. *
  36. *
  37. SCOPE_CATALOG String => catalog of table that is the scope of a reference attribute * ({@code null} if {@code DATA_TYPE} isn't REF). Always {@code null} here.
  38. *
  39. SCOPE_SCHEMA String => schema of table that is the scope of a reference attribute * ({@code null} if {@code DATA_TYPE} isn't REF). Always {@code null} here.
  40. *
  41. SCOPE_TABLE String => table name that is the scope of a reference attribute * ({@code null} if {@code DATA_TYPE} isn't REF). Always {@code null} here.
  42. *
  43. SOURCE_DATA_TYPE short => source type of a distinct type or user-generated Ref type, SQL type * from {@link Types} ({@code null} if {@code DATA_TYPE} isn't {@code DISTINCT} or user-generated * {@code REF}). Always {@code null} here.
  44. *
  45. IS_AUTOINCREMENT String => Indicates whether this column is auto-incremented: *
      *
    • YES - if the column is auto-incremented
    • *
    • NO - if the column is not auto-incremented
    • *
    • empty string - if it cannot be determined whether the column is auto incremented * parameter is unknown
    • *
    Always {@code NO} here. *
  46. *
  47. IS_GENERATEDCOLUMN String => Indicates whether this is a generated column: *
      *
    • YES - if this is a generated column
    • *
    • NO - if this is not a generated column
    • *
    • empty string - if it cannot be determined whether this is a generated column
    • *
    Always {@code NO} here. *
  48. *
* * @param schemaPattern A schema name pattern. It must match the schema name as it is stored in the database; * {@code ""} retrieves those without a schema and {@code null} means that the schema name * should not be used to narrow the search. Using {@code ""} as the same effect as * {@code null} because here the schema corresponds to the keyspace and Cassandra tables * cannot be defined outside a keyspace. * @param tableNamePattern A table name pattern. It must match the table name as it is stored in the database. * @param columnNamePattern A column name pattern. It must match the column name as it is stored in the database. * @return A valid result set for implementation of * {@link DatabaseMetaData#getColumns(String, String, String, String)}. * @throws SQLException when something went wrong during the creation of the result set. */ public CassandraMetadataResultSet buildColumns(final String schemaPattern, final String tableNamePattern, final String columnNamePattern) throws SQLException { final String catalog = this.connection.getCatalog(); final ArrayList columns = new ArrayList<>(); final MetadataRow.MetadataRowTemplate rowTemplate = new MetadataRow.MetadataRowTemplate( buildDefinitionInAnonymousTable(TABLE_CATALOG_SHORTNAME, DataTypes.TEXT), buildDefinitionInAnonymousTable(TABLE_SCHEMA, DataTypes.TEXT), buildDefinitionInAnonymousTable(TABLE_NAME, DataTypes.TEXT), buildDefinitionInAnonymousTable(COLUMN_NAME, DataTypes.TEXT), buildDefinitionInAnonymousTable(DATA_TYPE, DataTypes.TEXT), buildDefinitionInAnonymousTable(TYPE_NAME, DataTypes.TEXT), buildDefinitionInAnonymousTable(COLUMN_SIZE, DataTypes.TEXT), buildDefinitionInAnonymousTable(BUFFER_LENGTH, DataTypes.TEXT), buildDefinitionInAnonymousTable(DECIMAL_DIGITS, DataTypes.TEXT), buildDefinitionInAnonymousTable(NUM_PRECISION_RADIX, DataTypes.TEXT), buildDefinitionInAnonymousTable(NULLABLE, DataTypes.TEXT), buildDefinitionInAnonymousTable(REMARKS, DataTypes.TEXT), buildDefinitionInAnonymousTable(COLUMN_DEFAULT, DataTypes.TEXT), buildDefinitionInAnonymousTable(SQL_DATA_TYPE, DataTypes.TEXT), buildDefinitionInAnonymousTable(SQL_DATETIME_SUB, DataTypes.TEXT), buildDefinitionInAnonymousTable(CHAR_OCTET_LENGTH, DataTypes.TEXT), buildDefinitionInAnonymousTable(ORDINAL_POSITION, DataTypes.TEXT), buildDefinitionInAnonymousTable(IS_NULLABLE, DataTypes.TEXT), buildDefinitionInAnonymousTable(SCOPE_CATALOG, DataTypes.TEXT), buildDefinitionInAnonymousTable(SCOPE_SCHEMA, DataTypes.TEXT), buildDefinitionInAnonymousTable(SCOPE_TABLE, DataTypes.TEXT), buildDefinitionInAnonymousTable(SOURCE_DATA_TYPE, DataTypes.TEXT), buildDefinitionInAnonymousTable(IS_AUTOINCREMENT, DataTypes.TEXT), buildDefinitionInAnonymousTable(IS_GENERATED_COLUMN, DataTypes.TEXT) ); filterBySchemaNamePattern(schemaPattern, keyspaceMetadata -> filterByTableNamePattern(tableNamePattern, keyspaceMetadata, tableMetadata -> { final AtomicInteger colIndex = new AtomicInteger(1); // The ordinal positions start at 1. filterByColumnNamePattern(columnNamePattern, tableMetadata, columnMetadata -> { final AbstractJdbcType jdbcEquivalentType = getTypeForComparator(columnMetadata.getType().toString()); // Define value of COLUMN_SIZE. int columnSize = DEFAULT_PRECISION; if (jdbcEquivalentType != null) { columnSize = jdbcEquivalentType.getPrecision(null); } // Define value of NUM_PREC_RADIX. int radix = 2; if (jdbcEquivalentType != null && (jdbcEquivalentType.getJdbcType() == Types.DECIMAL || jdbcEquivalentType.getJdbcType() == Types.NUMERIC)) { radix = 10; } // Define value of DATA_TYPE. int jdbcType = Types.OTHER; try { jdbcType = getTypeForComparator(columnMetadata.getType().toString()) .getJdbcType(); } catch (final Exception e) { LOG.warn("Unable to get JDBC type for comparator [{}]: {}", columnMetadata.getType(), e.getMessage()); } final MetadataRow row = new MetadataRow().withTemplate(rowTemplate, catalog, // TABLE_CAT keyspaceMetadata.getName().asInternal(), // TABLE_SCHEM tableMetadata.getName().asInternal(), // TABLE_NAME columnMetadata.getName().asInternal(), // COLUMN_NAME String.valueOf(jdbcType), // DATA_TYPE columnMetadata.getType().toString(), // TYPE_NAME String.valueOf(columnSize), // COLUMN_SIZE String.valueOf(0), // BUFFER_LENGTH null, // DECIMAL_DIGITS String.valueOf(radix), // NUM_PREC_RADIX String.valueOf(DatabaseMetaData.columnNoNulls), // NULLABLE null, // REMARKS null, // COLUMN_DEF null, // SQL_DATA_TYPE null, // SQL_DATETIME_SUB String.valueOf(Integer.MAX_VALUE), // CHAR_OCTET_LENGTH String.valueOf(colIndex.getAndIncrement()), // ORDINAL_POSITION StringUtils.EMPTY, // IS_NULLABLE null, // SCOPE_CATALOG null, // SCOPE_SCHEMA null, // SCOPE_TABLE null, // SOURCE_DATA_TYPE NO_VALUE, // IS_AUTOINCREMENT NO_VALUE); // IS_GENERATED_COLUMN columns.add(row); }, columnMetadata -> colIndex.getAndIncrement()); }, null), null); // Results should all have the same TABLE_CAT, so just sort them by TABLE_SCHEM, TABLE_NAME then // ORDINAL_POSITION. columns.sort(Comparator.comparing(row -> ((MetadataRow) row).getString(TABLE_SCHEMA)) .thenComparing(row -> ((MetadataRow) row).getString(TABLE_NAME)) .thenComparing(row -> ((MetadataRow) row).getString(ORDINAL_POSITION))); return CassandraMetadataResultSet.buildFrom(this.statement, new MetadataResultSet(rowTemplate).setRows(columns)); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy