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

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

The 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.CqlIdentifier;
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 java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import static com.ing.data.cassandra.jdbc.ColumnDefinitions.Definition.buildDefinitionInAnonymousTable;
import static com.ing.data.cassandra.jdbc.types.TypesMap.getTypeForComparator;
import static java.sql.DatabaseMetaData.functionColumnIn;
import static java.sql.DatabaseMetaData.functionNoTable;
import static java.sql.DatabaseMetaData.functionReturn;
import static java.sql.DatabaseMetaData.typeNullable;

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

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

    /**
     * Builds a valid result set of the system and user functions available in the given catalog (Cassandra cluster).
     * This method is used to implement the method {@link DatabaseMetaData#getFunctions(String, String, String)}.
     * 

* Only system and user function descriptions matching the schema and function name criteria are returned. They are * ordered by {@code FUNCTION_CAT}, {@code FUNCTION_SCHEM}, {@code FUNCTION_NAME} and {@code SPECIFIC_NAME}. *

*

* The columns of this result set are: *

    *
  1. FUNCTION_CAT String => function catalog, may be {@code null}: here is the Cassandra cluster * name (if available).
  2. *
  3. FUNCTION_SCHEM String => function schema, may be {@code null}: here is the keyspace the table * is member of.
  4. *
  5. FUNCTION_NAME String => function name. This is the name used to invoke the function.
  6. *
  7. REMARKS String => explanatory comment on the function (always empty, Cassandra does not * allow to describe functions with a comment).
  8. *
  9. FUNCTION_TYPE short => kind of function: *
      *
    • {@link DatabaseMetaData#functionResultUnknown} - cannot determine if a return value or table * will be returned
    • *
    • {@link DatabaseMetaData#functionNoTable} - does not return a table (Cassandra user-defined * functions only return CQL types, so never a table)
    • *
    • {@link DatabaseMetaData#functionReturnsTable} - returns a table
    • *
    *
  10. *
  11. SPECIFIC_NAME String => the name which uniquely identifies this function within its schema. * This is a user specified, or DBMS generated, name that may be different then the {@code FUNCTION_NAME} * for example with overload functions.
  12. *
*

*

* A user may not have permission to execute any of the functions that are returned by {@code getFunctions}. *

* * @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 down the search. * @param functionNamePattern A function name pattern; must match the function name as it is stored in the * database. * @return A valid result set for implementation of {@link DatabaseMetaData#getFunctions(String, String, String)}. * @throws SQLException when something went wrong during the creation of the result set. */ public CassandraMetadataResultSet buildFunctions(final String schemaPattern, final String functionNamePattern) throws SQLException { final String catalog = this.connection.getCatalog(); final ArrayList functionsRows = new ArrayList<>(); final MetadataRow.MetadataRowTemplate rowTemplate = new MetadataRow.MetadataRowTemplate( buildDefinitionInAnonymousTable(FUNCTION_CATALOG, DataTypes.TEXT), buildDefinitionInAnonymousTable(FUNCTION_SCHEMA, DataTypes.TEXT), buildDefinitionInAnonymousTable(FUNCTION_NAME, DataTypes.TEXT), buildDefinitionInAnonymousTable(REMARKS, DataTypes.TEXT), buildDefinitionInAnonymousTable(FUNCTION_TYPE, DataTypes.SMALLINT), buildDefinitionInAnonymousTable(SPECIFIC_NAME, DataTypes.TEXT) ); filterBySchemaNamePattern(schemaPattern, keyspaceMetadata -> filterByFunctionNamePattern(functionNamePattern, keyspaceMetadata, (functionSignature, functionMetadata) -> { final MetadataRow row = new MetadataRow().withTemplate(rowTemplate, catalog, // FUNCTION_CAT keyspaceMetadata.getName().asInternal(), // FUNCTION_SCHEM functionSignature.getName().asInternal(), // FUNCTION_NAME StringUtils.EMPTY, // REMARKS (short) functionNoTable, // FUNCTION_TYPE functionSignature.getName().asInternal()); // SPECIFIC_NAME functionsRows.add(row); }), null); // Results should all have the same FUNCTION_CAT, so just sort them by FUNCTION_SCHEM then FUNCTION_NAME (since // here SPECIFIC_NAME is equal to FUNCTION_NAME). functionsRows.sort(Comparator.comparing(row -> ((MetadataRow) row).getString(FUNCTION_SCHEMA)) .thenComparing(row -> ((MetadataRow) row).getString(FUNCTION_NAME))); return CassandraMetadataResultSet.buildFrom(this.statement, new MetadataResultSet(rowTemplate).setRows(functionsRows)); } /** * Builds a valid result set of the given catalog's system or user function parameters and return type. * This method is used to implement the method * {@link DatabaseMetaData#getFunctionColumns(String, String, String, String)}. *

* Only descriptions matching the schema, function and parameter name criteria are returned. They are ordered by * {@code FUNCTION_CAT}, {@code FUNCTION_SCHEM}, {@code FUNCTION_NAME} and {@code SPECIFIC_NAME}. Within this, the * return value, if any, is first. Next are the parameter descriptions in call order. The column descriptions * follow in column number order. *

*

* The columns of this result set are: *

    *
  1. FUNCTION_CAT String => function catalog, may be {@code null}: here is the Cassandra cluster * name (if available).
  2. *
  3. FUNCTION_SCHEM String => function schema, may be {@code null}: here is the keyspace the table * is member of.
  4. *
  5. FUNCTION_NAME String => function name. This is the name used to invoke the function.
  6. *
  7. COLUMN_NAME String => column/parameter name.
  8. *
  9. COLUMN_TYPE short => kind of column/parameter: *
      *
    • {@link DatabaseMetaData#functionColumnUnknown} - unknown type
    • *
    • {@link DatabaseMetaData#functionColumnIn} - {@code IN} parameter
    • *
    • {@link DatabaseMetaData#functionColumnInOut} - {@code INOUT} parameter
    • *
    • {@link DatabaseMetaData#functionColumnOut} - {@code OUT} parameter
    • *
    • {@link DatabaseMetaData#functionReturn} - function return value
    • *
    • {@link DatabaseMetaData#functionColumnResult} - indicates that the parameter or column is a * column in the {@code ResultSet}
    • *
    *
  10. *
  11. DATA_TYPE int => SQL data type from {@link Types}.
  12. *
  13. TYPE_NAME String => SQL type name, for a UDT type the type name is fully qualified.
  14. *
  15. PRECISION int => maximum precision.
  16. *
  17. LENGTH int => length in bytes of data.
  18. *
  19. SCALE int => scale, {@code null} is returned for data types where SCALE is not * applicable.
  20. *
  21. RADIX short => precision radix.
  22. *
  23. NULLABLE short => can you use {@code NULL} for this type: *
      *
    • {@link DatabaseMetaData#typeNoNulls} - does not allow {@code NULL} values
    • *
    • {@link DatabaseMetaData#typeNullable} - allows {@code NULL} values
    • *
    • {@link DatabaseMetaData#typeNullableUnknown} - nullability unknown
    • *
    *
  24. *
  25. REMARKS String => comment describing column/parameter (always empty, Cassandra does not * allow to describe columns with a comment).
  26. *
  27. CHAR_OCTET_LENGTH int => the maximum length of binary and character based parameters or * columns. For any other datatype the returned value is a {@code NULL}.
  28. *
  29. ORDINAL_POSITION int => the ordinal position, starting from 1, for the input and output * parameters. A value of 0 is returned if this row describes the function's return value. For result set * columns, it is the ordinal position of the column in the result set starting from 1.
  30. *
  31. IS_NULLABLE String => "YES" if a parameter or column accepts {@code NULL} values, "NO" * if not and empty if the nullability is unknown.
  32. *
  33. SPECIFIC_NAME String => the name which uniquely identifies this function within its schema. * This is a user specified, or DBMS generated, name that may be different then the {@code FUNCTION_NAME} * for example with overload functions.
  34. *
*

*

* The {@code PRECISION} column represents the maximum column size that the server supports for the given datatype. * For numeric data, this is the maximum precision. For character data, this is the length in characters. For * datetime data types, this is the length in characters of the {@code String} representation (assuming the maximum * allowed precision of the fractional seconds component). For binary data, this is the length in bytes. * For the {@code ROWID} datatype (not supported by Cassandra), this is the length in bytes. The value {@code null} * is returned for data types where the column size is not applicable. *

* * @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 down the search. * @param functionNamePattern A function name pattern; must match the function name as it is stored in the * database. * @param columnNamePattern A parameter name pattern; must match the parameter or column name as it is stored * in the database. * @return A valid result set for implementation of * {@link DatabaseMetaData#getFunctionColumns(String, String, String, String)}. * @throws SQLException when something went wrong during the creation of the result set. */ public CassandraMetadataResultSet buildFunctionColumns(final String schemaPattern, final String functionNamePattern, final String columnNamePattern) throws SQLException { final String catalog = this.connection.getCatalog(); final ArrayList functionParamsRows = new ArrayList<>(); final MetadataRow.MetadataRowTemplate rowTemplate = new MetadataRow.MetadataRowTemplate( buildDefinitionInAnonymousTable(FUNCTION_CATALOG, DataTypes.TEXT), buildDefinitionInAnonymousTable(FUNCTION_SCHEMA, DataTypes.TEXT), buildDefinitionInAnonymousTable(FUNCTION_NAME, DataTypes.TEXT), buildDefinitionInAnonymousTable(COLUMN_NAME, DataTypes.TEXT), buildDefinitionInAnonymousTable(COLUMN_TYPE, DataTypes.SMALLINT), buildDefinitionInAnonymousTable(DATA_TYPE, DataTypes.INT), buildDefinitionInAnonymousTable(TYPE_NAME, DataTypes.TEXT), buildDefinitionInAnonymousTable(PRECISION, DataTypes.INT), buildDefinitionInAnonymousTable(LENGTH, DataTypes.INT), buildDefinitionInAnonymousTable(SCALE, DataTypes.INT), buildDefinitionInAnonymousTable(RADIX, DataTypes.SMALLINT), buildDefinitionInAnonymousTable(NULLABLE, DataTypes.SMALLINT), buildDefinitionInAnonymousTable(REMARKS, DataTypes.TEXT), buildDefinitionInAnonymousTable(CHAR_OCTET_LENGTH, DataTypes.INT), buildDefinitionInAnonymousTable(ORDINAL_POSITION, DataTypes.INT), buildDefinitionInAnonymousTable(IS_NULLABLE, DataTypes.TEXT), buildDefinitionInAnonymousTable(SPECIFIC_NAME, DataTypes.TEXT) ); filterBySchemaNamePattern(schemaPattern, keyspaceMetadata -> filterByFunctionNamePattern(functionNamePattern, keyspaceMetadata, (functionSignature, functionMetadata) -> { // Function return type. final AbstractJdbcType returnJdbcType = getTypeForComparator(functionMetadata.getReturnType().asCql(false, true)); final MetadataRow row = new MetadataRow().withTemplate(rowTemplate, catalog, // FUNCTION_CAT keyspaceMetadata.getName().asInternal(), // FUNCTION_SCHEM functionSignature.getName().asInternal(), // FUNCTION_NAME StringUtils.EMPTY, // COLUMN_NAME (short) functionReturn, // COLUMN_TYPE returnJdbcType.getJdbcType(), // DATA_TYPE functionMetadata.getReturnType().toString(), // TYPE_NAME returnJdbcType.getPrecision(null), // PRECISION Integer.MAX_VALUE, // LENGTH returnJdbcType.getScale(null), // SCALE (short) returnJdbcType.getPrecision(null), // RADIX (short) typeNullable, // NULLABLE StringUtils.EMPTY, // REMARKS null, // CHAR_OCTET_LENGTH 0, // ORDINAL_POSITION YES_VALUE, // IS_NULLABLE functionSignature.getName().asInternal()); // SPECIFIC_NAME functionParamsRows.add(row); // Function input parameters. final List paramNames = functionMetadata.getParameterNames(); for (int i = 0; i < paramNames.size(); i++) { if (columnNamePattern == null || matchesPattern(columnNamePattern, paramNames.get(i).asInternal())) { final AbstractJdbcType paramJdbcType = getTypeForComparator( functionSignature.getParameterTypes().get(i).asCql(false, true)); final MetadataRow paramRow = new MetadataRow().withTemplate(rowTemplate, catalog, // FUNCTION_CAT keyspaceMetadata.getName().asInternal(), // FUNCTION_SCHEM functionSignature.getName().asInternal(), // FUNCTION_NAME paramNames.get(i).asInternal(), // COLUMN_NAME (short) functionColumnIn, // COLUMN_TYPE paramJdbcType.getJdbcType(), // DATA_TYPE functionSignature.getParameterTypes().get(i).toString(), // TYPE_NAME paramJdbcType.getPrecision(null), // PRECISION Integer.MAX_VALUE, // LENGTH paramJdbcType.getScale(null), // SCALE (short) paramJdbcType.getPrecision(null), // RADIX (short) typeNullable, // NULLABLE StringUtils.EMPTY, // REMARKS null, // CHAR_OCTET_LENGTH i + 1, // ORDINAL_POSITION YES_VALUE, // IS_NULLABLE functionSignature.getName().asInternal()); // SPECIFIC_NAME functionParamsRows.add(paramRow); } } }), null); // Results should all have the same FUNCTION_CAT, so just sort them by FUNCTION_SCHEM then FUNCTION_NAME (since // here SPECIFIC_NAME is equal to FUNCTION_NAME), and finally by ORDINAL_POSITION. functionParamsRows.sort(Comparator.comparing(row -> ((MetadataRow) row).getString(FUNCTION_SCHEMA)) .thenComparing(row -> ((MetadataRow) row).getString(FUNCTION_NAME)) .thenComparing(row -> ((MetadataRow) row).getString(SPECIFIC_NAME)) .thenComparing(row -> ((MetadataRow) row).getInt(ORDINAL_POSITION))); return CassandraMetadataResultSet.buildFrom(this.statement, new MetadataResultSet(rowTemplate).setRows(functionParamsRows)); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy