Search in sources :

Example 1 with RowDescriptorBuilder

use of org.firebirdsql.gds.ng.fields.RowDescriptorBuilder in project jaybird by FirebirdSQL.

the class FBNullFieldTest method setUp.

@Before
public void setUp() throws Exception {
    fieldData = context.mock(FieldDataProvider.class);
    FieldDescriptor fieldDescriptor = new RowDescriptorBuilder(1, defaultDatatypeCoder).toFieldDescriptor();
    field = new FBNullField(fieldDescriptor, fieldData, Types.NULL);
}
Also used : RowDescriptorBuilder(org.firebirdsql.gds.ng.fields.RowDescriptorBuilder) FieldDescriptor(org.firebirdsql.gds.ng.fields.FieldDescriptor) Before(org.junit.Before)

Example 2 with RowDescriptorBuilder

use of org.firebirdsql.gds.ng.fields.RowDescriptorBuilder in project jaybird by FirebirdSQL.

the class StatementInfoProcessor method handleDescriptors.

/**
 * Handles a bind description (for <tt>isc_info_sql_select</tt> or <tt>isc_info_sql_bind</tt>.
 *
 * @param info
 *         StatementInfo
 */
private void handleDescriptors(final StatementInfo info) throws SQLException {
    // Skipping isc_info_sql_num_variables/isc_info_sql_describe_vars item
    info.currentIndex++;
    int descriptorCount = readIntValue(info);
    if (descriptorCount == 0) {
        return;
    }
    switch(info.currentItem) {
        case ISCConstants.isc_info_sql_select:
            if (info.fieldBuilder == null) {
                info.fieldBuilder = new RowDescriptorBuilder(descriptorCount, database.getDatatypeCoder());
            }
            processDescriptors(info, info.fieldBuilder);
            break;
        case ISCConstants.isc_info_sql_bind:
            if (info.parameterBuilder == null) {
                info.parameterBuilder = new RowDescriptorBuilder(descriptorCount, database.getDatatypeCoder());
            }
            processDescriptors(info, info.parameterBuilder);
            break;
    }
}
Also used : RowDescriptorBuilder(org.firebirdsql.gds.ng.fields.RowDescriptorBuilder)

Example 3 with RowDescriptorBuilder

use of org.firebirdsql.gds.ng.fields.RowDescriptorBuilder in project jaybird by FirebirdSQL.

the class FBDatabaseMetaData method getTypeInfo.

/**
 * Gets a description of all the standard SQL types supported by
 * this database. They are ordered by DATA_TYPE and then by how
 * closely the data type maps to the corresponding JDBC SQL type.
 *
 * <P>Each type description has the following columns:
 *  <OL>
 *  <LI><B>TYPE_NAME</B> String => Type name
 *  <LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
 *  <LI><B>PRECISION</B> int => maximum precision
 *  <LI><B>LITERAL_PREFIX</B> String => prefix used to quote a literal
 *      (may be null)
 *  <LI><B>LITERAL_SUFFIX</B> String => suffix used to quote a literal
 *            (may be null)
 *  <LI><B>CREATE_PARAMS</B> String => parameters used in creating
 *      the type (may be null)
 *  <LI><B>NULLABLE</B> short => can you use NULL for this type?
 *      <UL>
 *      <LI> typeNoNulls - does not allow NULL values
 *      <LI> typeNullable - allows NULL values
 *      <LI> typeNullableUnknown - nullability unknown
 *      </UL>
 *  <LI><B>CASE_SENSITIVE</B> boolean=> is it case sensitive?
 *  <LI><B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
 *      <UL>
 *      <LI> typePredNone - No support
 *      <LI> typePredChar - Only supported with WHERE .. LIKE
 *      <LI> typePredBasic - Supported except for WHERE .. LIKE
 *      <LI> typeSearchable - Supported for all WHERE ..
 *      </UL>
 *  <LI><B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned?
 *  <LI><B>FIXED_PREC_SCALE</B> boolean => can it be a money value?
 *  <LI><B>AUTO_INCREMENT</B> boolean => can it be used for an
 *      auto-increment value?
 *  <LI><B>LOCAL_TYPE_NAME</B> String => localized version of type name
 *      (may be null)
 *  <LI><B>MINIMUM_SCALE</B> short => minimum scale supported
 *  <LI><B>MAXIMUM_SCALE</B> short => maximum scale supported
 *  <LI><B>SQL_DATA_TYPE</B> int => unused
 *  <LI><B>SQL_DATETIME_SUB</B> int => unused
 *  <LI><B>NUM_PREC_RADIX</B> int => usually 2 or 10
 *  </OL>
 *
 * @return <code>ResultSet</code> - each row is an SQL type description
 * @exception SQLException if a database access error occurs
 */
public ResultSet getTypeInfo() throws SQLException {
    final RowDescriptor rowDescriptor = new RowDescriptorBuilder(18, datatypeCoder).at(0).simple(SQL_VARYING, 31, "TYPE_NAME", "TYPEINFO").addField().at(1).simple(SQL_SHORT, 0, "DATA_TYPE", "TYPEINFO").addField().at(2).simple(SQL_LONG, 0, "PRECISION", "TYPEINFO").addField().at(3).simple(SQL_VARYING, 1, "LITERAL_PREFIX", "TYPEINFO").addField().at(4).simple(SQL_VARYING, 1, "LITERAL_SUFFIX", "TYPEINFO").addField().at(5).simple(SQL_VARYING, 31, "CREATE_PARAMS", "TYPEINFO").addField().at(6).simple(SQL_SHORT, 0, "NULLABLE", "TYPEINFO").addField().at(7).simple(SQL_TEXT, 1, "CASE_SENSITIVE", "TYPEINFO").addField().at(8).simple(SQL_SHORT, 0, "SEARCHABLE", "TYPEINFO").addField().at(9).simple(SQL_TEXT, 1, "UNSIGNED_ATTRIBUTE", "TYPEINFO").addField().at(10).simple(SQL_TEXT, 1, "FIXED_PREC_SCALE", "TYPEINFO").addField().at(11).simple(SQL_TEXT, 1, "AUTO_INCREMENT", "TYPEINFO").addField().at(12).simple(SQL_VARYING, 31, "LOCAL_TYPE_NAME", "TYPEINFO").addField().at(13).simple(SQL_SHORT, 0, "MINIMUM_SCALE", "TYPEINFO").addField().at(14).simple(SQL_SHORT, 0, "MAXIMUM_SCALE", "TYPEINFO").addField().at(15).simple(SQL_LONG, 0, "SQL_DATA_TYPE", "TYPEINFO").addField().at(16).simple(SQL_LONG, 0, "SQL_DATETIME_SUB", "TYPEINFO").addField().at(17).simple(SQL_LONG, 0, "NUM_PREC_RADIX", "TYPEINFO").addField().toRowDescriptor();
    final byte[] blobTypePred = firebirdSupportInfo.supportsFullSearchableBlobs() ? TYPE_SEARCHABLE : TYPE_PRED_BASIC;
    // dialect 3 only
    final List<RowValue> rows = new ArrayList<>(20);
    // DECFLOAT=-6001 (TODO Change when standardized)
    if (getDatabaseMajorVersion() >= 4) {
        rows.add(RowValue.of(rowDescriptor, getBytes("DECFLOAT"), createShort(JaybirdTypeCodes.DECFLOAT), DECFLOAT_34_PRECISION, null, null, getBytes("precision"), TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, SIGNED, VARIABLESCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_DEC34), null, RADIX_TEN));
    }
    // BIGINT=-5
    rows.add(RowValue.of(rowDescriptor, getBytes("BIGINT"), createShort(Types.BIGINT), BIGINT_PRECISION, null, null, null, TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, SIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_INT64), null, RADIX_TEN));
    // LONGVARBINARY=-4
    rows.add(RowValue.of(rowDescriptor, getBytes("BLOB SUB_TYPE BINARY"), createShort(Types.LONGVARBINARY), INT_ZERO, null, null, null, TYPE_NULLABLE, CASESENSITIVE, blobTypePred, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_BLOB), null, RADIX_TEN));
    // VARBINARY=-3
    rows.add(RowValue.of(rowDescriptor, getBytes("VARCHAR"), createShort(Types.VARBINARY), createInt(32765), null, null, getBytes("length"), TYPE_NULLABLE, CASESENSITIVE, TYPE_SEARCHABLE, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_VARYING), null, RADIX_TEN));
    // BINARY=-2
    rows.add(RowValue.of(rowDescriptor, getBytes("CHAR"), createShort(Types.BINARY), createInt(32767), null, null, getBytes("length"), TYPE_NULLABLE, CASESENSITIVE, TYPE_SEARCHABLE, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_TEXT), null, RADIX_TEN));
    // LONGVARCHAR=-1
    rows.add(RowValue.of(rowDescriptor, getBytes("BLOB SUB_TYPE TEXT"), createShort(Types.LONGVARCHAR), INT_ZERO, getBytes("'"), getBytes("'"), null, TYPE_NULLABLE, CASESENSITIVE, blobTypePred, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_BLOB), null, RADIX_TEN));
    // CHAR=1
    rows.add(RowValue.of(rowDescriptor, getBytes("CHAR"), createShort(Types.CHAR), createInt(32767), getBytes("'"), getBytes("'"), getBytes("length"), TYPE_NULLABLE, CASESENSITIVE, TYPE_SEARCHABLE, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_TEXT), null, RADIX_TEN));
    // NUMERIC=2
    // TODO Handle DEC_FIXED
    rows.add(RowValue.of(rowDescriptor, getBytes("NUMERIC"), createShort(Types.NUMERIC), NUMERIC_PRECISION, null, null, getBytes("precision,scale"), TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, SIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, NUMERIC_PRECISION, createInt(SQL_INT64), null, RADIX_TEN));
    // DECIMAL=3
    // TODO Handle DEC_FIXED
    rows.add(RowValue.of(rowDescriptor, getBytes("DECIMAL"), createShort(Types.DECIMAL), DECIMAL_PRECISION, null, null, getBytes("precision,scale"), TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, SIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, DECIMAL_PRECISION, createInt(SQL_INT64), null, RADIX_TEN));
    // INTEGER=4
    rows.add(RowValue.of(rowDescriptor, getBytes("INTEGER"), createShort(Types.INTEGER), INTEGER_PRECISION, null, null, null, TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, SIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_LONG), null, RADIX_TEN));
    // SMALLINT=5
    rows.add(RowValue.of(rowDescriptor, getBytes("SMALLINT"), createShort(Types.SMALLINT), SMALLINT_PRECISION, null, null, null, TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, SIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_SHORT), null, RADIX_TEN));
    // FLOAT=6
    rows.add(RowValue.of(rowDescriptor, getBytes("FLOAT"), createShort(Types.FLOAT), FLOAT_PRECISION, null, null, null, TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, SIGNED, VARIABLESCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_FLOAT), null, RADIX_TEN));
    // DOUBLE=8
    rows.add(RowValue.of(rowDescriptor, getBytes("DOUBLE PRECISION"), createShort(Types.DOUBLE), DOUBLE_PRECISION, null, null, null, TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, SIGNED, VARIABLESCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_DOUBLE), null, RADIX_TEN));
    // VARCHAR=12
    rows.add(RowValue.of(rowDescriptor, getBytes("VARCHAR"), createShort(Types.VARCHAR), createInt(32765), getBytes("'"), getBytes("'"), getBytes("length"), TYPE_NULLABLE, CASESENSITIVE, TYPE_SEARCHABLE, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_VARYING), null, RADIX_TEN));
    // BOOLEAN=16
    if (getDatabaseMajorVersion() >= 3) {
        rows.add(RowValue.of(rowDescriptor, getBytes("BOOLEAN"), createShort(Types.BOOLEAN), BOOLEAN_PRECISION, null, null, null, TYPE_NULLABLE, CASEINSENSITIVE, TYPE_PRED_BASIC, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_BOOLEAN), null, RADIX_BINARY));
    }
    // DATE=91
    rows.add(RowValue.of(rowDescriptor, getBytes("DATE"), createShort(Types.DATE), DATE_PRECISION, getBytes("date'"), getBytes("'"), null, TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_TYPE_DATE), null, RADIX_TEN));
    // TIME=92
    rows.add(RowValue.of(rowDescriptor, getBytes("TIME"), createShort(Types.TIME), TIME_PRECISION, getBytes("time'"), getBytes("'"), null, TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_TYPE_TIME), null, RADIX_TEN));
    // TIMESTAMP=93
    rows.add(RowValue.of(rowDescriptor, getBytes("TIMESTAMP"), createShort(Types.TIMESTAMP), TIMESTAMP_PRECISION, getBytes("timestamp'"), getBytes("'"), null, TYPE_NULLABLE, CASEINSENSITIVE, TYPE_SEARCHABLE, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_TIMESTAMP), null, RADIX_TEN));
    // OTHER=1111
    rows.add(RowValue.of(rowDescriptor, getBytes("ARRAY"), createShort(Types.OTHER), INT_ZERO, null, null, null, TYPE_NULLABLE, CASESENSITIVE, TYPE_PRED_NONE, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_ARRAY), null, RADIX_TEN));
    // BLOB=2004
    // Should we split this into all negative blob types currently known in the DB?
    // Blob is potentially searchable with like, etc, acting as if it isn't.
    rows.add(RowValue.of(rowDescriptor, getBytes("BLOB SUB_TYPE <0 "), createShort(Types.BLOB), INT_ZERO, null, null, null, TYPE_NULLABLE, CASESENSITIVE, TYPE_PRED_NONE, UNSIGNED, FIXEDSCALE, NOTAUTOINC, null, SHORT_ZERO, SHORT_ZERO, createInt(SQL_BLOB), null, RADIX_TEN));
    return new FBResultSet(rowDescriptor, rows);
}
Also used : RowDescriptorBuilder(org.firebirdsql.gds.ng.fields.RowDescriptorBuilder) RowValue(org.firebirdsql.gds.ng.fields.RowValue) RowDescriptor(org.firebirdsql.gds.ng.fields.RowDescriptor)

Example 4 with RowDescriptorBuilder

use of org.firebirdsql.gds.ng.fields.RowDescriptorBuilder in project jaybird by FirebirdSQL.

the class FBDatabaseMetaData method getCrossReference.

/**
 * Gets a description of the foreign key columns in the foreign key
 * table that reference the primary key columns of the primary key
 * table (describe how one table imports another's key). This
 * should normally return a single foreign key/primary key pair
 * (most tables only import a foreign key from a table once.)  They
 * are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and
 * KEY_SEQ.
 *
 * <P>Each foreign key column description has the following columns:
 *  <OL>
 *  <LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
 *  <LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
 *  <LI><B>PKTABLE_NAME</B> String => primary key table name
 *  <LI><B>PKCOLUMN_NAME</B> String => primary key column name
 *  <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
 *      being exported (may be null)
 *  <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
 *      being exported (may be null)
 *  <LI><B>FKTABLE_NAME</B> String => foreign key table name
 *      being exported
 *  <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
 *      being exported
 *  <LI><B>KEY_SEQ</B> short => sequence number within foreign key
 *  <LI><B>UPDATE_RULE</B> short => What happens to
 *       foreign key when primary is updated:
 *      <UL>
 *      <LI> importedNoAction - do not allow update of primary
 *               key if it has been imported
 *      <LI> importedKeyCascade - change imported key to agree
 *               with primary key update
 *      <LI> importedKeySetNull - change imported key to NULL if
 *               its primary key has been updated
 *      <LI> importedKeySetDefault - change imported key to default values
 *               if its primary key has been updated
 *      <LI> importedKeyRestrict - same as importedKeyNoAction
 *                                 (for ODBC 2.x compatibility)
 *      </UL>
 *  <LI><B>DELETE_RULE</B> short => What happens to
 *      the foreign key when primary is deleted.
 *      <UL>
 *      <LI> importedKeyNoAction - do not allow delete of primary
 *               key if it has been imported
 *      <LI> importedKeyCascade - delete rows that import a deleted key
 *      <LI> importedKeySetNull - change imported key to NULL if
 *               its primary key has been deleted
 *      <LI> importedKeyRestrict - same as importedKeyNoAction
 *                                 (for ODBC 2.x compatibility)
 *      <LI> importedKeySetDefault - change imported key to default if
 *               its primary key has been deleted
 *      </UL>
 *  <LI><B>FK_NAME</B> String => foreign key name (may be null)
 *  <LI><B>PK_NAME</B> String => primary key name (may be null)
 *  <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
 *      constraints be deferred until commit
 *      <UL>
 *      <LI> importedKeyInitiallyDeferred - see SQL92 for definition
 *      <LI> importedKeyInitiallyImmediate - see SQL92 for definition
 *      <LI> importedKeyNotDeferrable - see SQL92 for definition
 *      </UL>
 *  </OL>
 *
 * @param primaryCatalog a catalog name; "" retrieves those without a
 * catalog; null means drop catalog name from the selection criteria
 * @param primarySchema a schema name; "" retrieves those
 * without a schema
 * @param primaryTable the table name that exports the key
 * @param foreignCatalog a catalog name; "" retrieves those without a
 * catalog; null means drop catalog name from the selection criteria
 * @param foreignSchema a schema name; "" retrieves those
 * without a schema
 * @param foreignTable the table name that imports the key
 * @return <code>ResultSet</code> - each row is a foreign key column description
 * @exception SQLException if a database access error occurs
 * @see #getImportedKeys
 */
public ResultSet getCrossReference(String primaryCatalog, String primarySchema, String primaryTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException {
    final RowDescriptor rowDescriptor = new RowDescriptorBuilder(14, datatypeCoder).at(0).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "PKTABLE_CAT", "COLUMNINFO").addField().at(1).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "PKTABLE_SCHEM", "COLUMNINFO").addField().at(2).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "PKTABLE_NAME", "COLUMNINFO").addField().at(3).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "PKCOLUMN_NAME", "COLUMNINFO").addField().at(4).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "FKTABLE_CAT", "COLUMNINFO").addField().at(5).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "FKTABLE_SCHEM", "COLUMNINFO").addField().at(6).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "FKTABLE_NAME", "COLUMNINFO").addField().at(7).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "FKCOLUMN_NAME", "COLUMNINFO").addField().at(8).simple(SQL_SHORT, 0, "KEY_SEQ", "COLUMNINFO").addField().at(9).simple(SQL_SHORT, 0, "UPDATE_RULE", "COLUMNINFO").addField().at(10).simple(SQL_SHORT, 0, "DELETE_RULE", "COLUMNINFO").addField().at(11).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "FK_NAME", "COLUMNINFO").addField().at(12).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "PK_NAME", "COLUMNINFO").addField().at(13).simple(SQL_SHORT, 0, "DEFERRABILITY", "COLUMNINFO").addField().toRowDescriptor();
    final List<String> params = Arrays.asList(primaryTable, foreignTable);
    try (ResultSet rs = doQuery(GET_CROSS_KEYS, params)) {
        // return empty result set if nothing found
        if (!rs.next()) {
            return new FBResultSet(rowDescriptor, Collections.<RowValue>emptyList());
        }
        final List<RowValue> rows = new ArrayList<>();
        final RowValueBuilder valueBuilder = new RowValueBuilder(rowDescriptor);
        do {
            rows.add(valueBuilder.at(2).set(getBytes(rs.getString("PKTABLE_NAME"))).at(3).set(getBytes(rs.getString("PKCOLUMN_NAME"))).at(6).set(getBytes(rs.getString("FKTABLE_NAME"))).at(7).set(getBytes(rs.getString("FKCOLUMN_NAME"))).at(8).set(createShort(rs.getShort("KEY_SEQ"))).at(9).set(mapAction(rs.getString("UPDATE_RULE"))).at(10).set(mapAction(rs.getString("DELETE_RULE"))).at(11).set(getBytes(rs.getString("FK_NAME"))).at(12).set(getBytes(rs.getString("PK_NAME"))).at(13).set(IMPORTED_KEY_NOT_DEFERRABLE).toRowValue(true));
        } while (rs.next());
        return new FBResultSet(rowDescriptor, rows);
    }
}
Also used : RowDescriptorBuilder(org.firebirdsql.gds.ng.fields.RowDescriptorBuilder) RowValueBuilder(org.firebirdsql.gds.ng.fields.RowValueBuilder) RowValue(org.firebirdsql.gds.ng.fields.RowValue) RowDescriptor(org.firebirdsql.gds.ng.fields.RowDescriptor)

Example 5 with RowDescriptorBuilder

use of org.firebirdsql.gds.ng.fields.RowDescriptorBuilder in project jaybird by FirebirdSQL.

the class FBDatabaseMetaData method getColumns.

// @formatter:on
/**
 * Retrieves a description of table columns available in
 * the specified catalog.
 *
 * <P>Only column descriptions matching the catalog, schema, table
 * and column name criteria are returned.  They are ordered by
 * <code>TABLE_CAT</code>,<code>TABLE_SCHEM</code>,
 * <code>TABLE_NAME</code>, and <code>ORDINAL_POSITION</code>.
 *
 * <P>Each column description has the following columns:
 *  <OL>
 *  <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
 *  <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
 *  <LI><B>TABLE_NAME</B> String => table name
 *  <LI><B>COLUMN_NAME</B> String => column name
 *  <LI><B>DATA_TYPE</B> int => SQL type from java.sql.Types
 *  <LI><B>TYPE_NAME</B> String => Data source dependent type name,
 *  for a UDT the type name is fully qualified
 *  <LI><B>COLUMN_SIZE</B> int => column size.
 *  <LI><B>BUFFER_LENGTH</B> is not used.
 *  <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits. Null is returned for data types where
 * DECIMAL_DIGITS is not applicable.
 *  <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
 *  <LI><B>NULLABLE</B> int => is NULL allowed.
 *      <UL>
 *      <LI> columnNoNulls - might not allow <code>NULL</code> values
 *      <LI> columnNullable - definitely allows <code>NULL</code> values
 *      <LI> columnNullableUnknown - nullability unknown
 *      </UL>
 *  <LI><B>REMARKS</B> String => comment describing column (may be <code>null</code>)
 *  <LI><B>COLUMN_DEF</B> 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</code>)
 *  <LI><B>SQL_DATA_TYPE</B> int => unused
 *  <LI><B>SQL_DATETIME_SUB</B> int => unused
 *  <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
 *       maximum number of bytes in the column
 *  <LI><B>ORDINAL_POSITION</B> int => index of column in table
 *      (starting at 1)
 *  <LI><B>IS_NULLABLE</B> String  => ISO rules are used to determine the nullability for a column.
 *       <UL>
 *       <LI> YES           --- if the column can include NULLs
 *       <LI> NO            --- if the column cannot include NULLs
 *       <LI> empty string  --- if the nullability for the
 * column is unknown
 *       </UL>
 *  <LI><B>SCOPE_CATALOG</B> String => catalog of table that is the scope
 *      of a reference attribute (<code>null</code> if DATA_TYPE isn't REF)
 *  <LI><B>SCOPE_SCHEMA</B> String => schema of table that is the scope
 *      of a reference attribute (<code>null</code> if the DATA_TYPE isn't REF)
 *  <LI><B>SCOPE_TABLE</B> String => table name that this the scope
 *      of a reference attribute (<code>null</code> if the DATA_TYPE isn't REF)
 *  <LI><B>SOURCE_DATA_TYPE</B> short => source type of a distinct type or user-generated
 *      Ref type, SQL type from java.sql.Types (<code>null</code> if DATA_TYPE
 *      isn't DISTINCT or user-generated REF)
 *   <LI><B>IS_AUTOINCREMENT</B> String  => Indicates whether this column is auto incremented
 *       <UL>
 *       <LI> YES           --- if the column is auto incremented
 *       <LI> NO            --- if the column is not auto incremented
 *       <LI> empty string  --- if it cannot be determined whether the column is auto incremented
 *       </UL>
 *   <LI><B>IS_GENERATEDCOLUMN</B> String  => Indicates whether this is a generated column
 *       <UL>
 *       <LI> YES           --- if this a generated column
 *       <LI> NO            --- if this not a generated column
 *       <LI> empty string  --- if it cannot be determined whether this is a generated column
 *       </UL>
 *  <LI><B>JB_IS_IDENTITY</B> String  => Indicates whether this column is an identity column (<b>NOTE: Jaybird specific column; retrieve by name!</b>).
 *      There is subtle difference with the meaning of {@code IS_AUTOINCREMENT}. This column indicates if the column
 *      is a true identity column.
 *       <UL>
 *       <LI> YES           --- if the column is an identity column
 *       <LI> NO            --- if the column is not an identity column
 *       </UL>
 *  <LI><B>JB_IDENTITY_TYPE</B> String  => Type of identity column (<b>NOTE: Jaybird specific column; retrieve by name!</b>)
 *       <UL>
 *       <LI> ALWAYS        --- for a GENERATED ALWAYS AS IDENTITY column (not yet supported in Firebird 3!)
 *       <LI> BY DEFAULT    --- for a GENERATED BY DEFAULT AS IDENTITY column
 *       <LI> null          --- if the column is not an identity type (or the identity type is unknown)
 *       </UL>
 *  </OL>
 *
 * <p>The COLUMN_SIZE column specifies the column size for the given column.
 * For numeric data, this is the maximum precision.  For character data, this is the length in characters.
 * For datetime datatypes, this is the length in characters of the String representation (assuming the
 * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes.  For the ROWID datatype,
 * this is the length in bytes. Null is returned for data types where the
 * column size is not applicable.
 *
 * @param catalog a catalog name; must match the catalog name as it
 *        is stored in the database; "" retrieves those without a catalog;
 *        <code>null</code> means that the catalog name should not be used to narrow
 *        the search
 * @param schemaPattern a schema name pattern; must match the schema name
 *        as it is stored in the database; "" retrieves those without a schema;
 *        <code>null</code> means that the schema name should not be used to narrow
 *        the search
 * @param tableNamePattern a table name pattern; must match the
 *        table name as it is stored in the database
 * @param columnNamePattern a column name pattern; must match the column
 *        name as it is stored in the database
 * @return <code>ResultSet</code> - each row is a column description
 * @exception SQLException if a database access error occurs
 * @see #getSearchStringEscape
 */
public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException {
    final RowDescriptor rowDescriptor = new RowDescriptorBuilder(26, datatypeCoder).at(0).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "TABLE_CAT", "COLUMNINFO").addField().at(1).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "TABLE_SCHEM", "COLUMNINFO").addField().at(2).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "TABLE_NAME", "COLUMNINFO").addField().at(3).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "COLUMN_NAME", "COLUMNINFO").addField().at(4).simple(SQL_LONG, 0, "DATA_TYPE", "COLUMNINFO").addField().at(5).simple(SQL_VARYING | 1, 31, "TYPE_NAME", "COLUMNINFO").addField().at(6).simple(SQL_LONG, 0, "COLUMN_SIZE", "COLUMNINFO").addField().at(7).simple(SQL_LONG, 0, "BUFFER_LENGTH", "COLUMNINFO").addField().at(8).simple(SQL_LONG, 0, "DECIMAL_DIGITS", "COLUMNINFO").addField().at(9).simple(SQL_LONG, 0, "NUM_PREC_RADIX", "COLUMNINFO").addField().at(10).simple(SQL_LONG, 0, "NULLABLE", "COLUMNINFO").addField().at(11).simple(SQL_VARYING | 1, Integer.MAX_VALUE, "REMARKS", "COLUMNINFO").addField().at(12).simple(SQL_VARYING | 1, 31, "COLUMN_DEF", "COLUMNINFO").addField().at(13).simple(SQL_LONG, 0, "SQL_DATA_TYPE", "COLUMNINFO").addField().at(14).simple(SQL_LONG, 0, "SQL_DATETIME_SUB", "COLUMNINFO").addField().at(15).simple(SQL_LONG, 0, "CHAR_OCTET_LENGTH", "COLUMNINFO").addField().at(16).simple(SQL_LONG, 0, "ORDINAL_POSITION", "COLUMNINFO").addField().at(17).simple(SQL_VARYING, 3, "IS_NULLABLE", "COLUMNINFO").addField().at(18).simple(SQL_VARYING, OBJECT_NAME_LENGTH, getScopeCatalogColumnName(), "COLUMNINFO").addField().at(19).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "SCOPE_SCHEMA", "COLUMNINFO").addField().at(20).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "SCOPE_TABLE", "COLUMNINFO").addField().at(21).simple(SQL_SHORT, 0, "SOURCE_DATA_TYPE", "COLUMNINFO").addField().at(22).simple(SQL_VARYING, 3, "IS_AUTOINCREMENT", "COLUMNINFO").addField().at(23).simple(SQL_VARYING, 3, "IS_GENERATEDCOLUMN", "COLUMNINFO").addField().at(24).simple(SQL_VARYING, 3, "JB_IS_IDENTITY", "COLUMNINFO").addField().at(25).simple(SQL_VARYING, 10, "JB_IDENTITY_TYPE", "COLUMNINFO").addField().toRowDescriptor();
    Clause tableClause = new Clause("RF.RDB$RELATION_NAME", tableNamePattern);
    Clause columnClause = new Clause("RF.RDB$FIELD_NAME", columnNamePattern);
    String sql = hasIdentityColumns() ? GET_COLUMNS_3_0_START : GET_COLUMNS_START;
    sql += tableClause.getCondition();
    sql += columnClause.getCondition();
    sql += GET_COLUMNS_END;
    List<String> params = new ArrayList<>(2);
    if (tableClause.hasCondition()) {
        params.add(tableClause.getValue());
    }
    if (columnClause.hasCondition()) {
        params.add(columnClause.getValue());
    }
    try (ResultSet rs = doQuery(sql, params)) {
        if (!rs.next()) {
            return new FBResultSet(rowDescriptor, Collections.<RowValue>emptyList());
        }
        final List<RowValue> rows = new ArrayList<>();
        final RowValueBuilder valueBuilder = new RowValueBuilder(rowDescriptor);
        do {
            final short fieldType = rs.getShort("FIELD_TYPE");
            final short fieldSubType = rs.getShort("FIELD_SUB_TYPE");
            final short fieldScale = rs.getShort("FIELD_SCALE");
            final int characterSetId = rs.getInt("RDB$CHARACTER_SET_ID");
            final int dataType = getDataType(fieldType, fieldSubType, fieldScale, characterSetId);
            valueBuilder.at(2).set(getBytes(rs.getString("RELATION_NAME"))).at(3).set(getBytes(rs.getString("FIELD_NAME"))).at(4).set(createInt(dataType)).at(5).set(getBytes(getDataTypeName(fieldType, fieldSubType, fieldScale))).at(9).set(RADIX_TEN);
            switch(dataType) {
                case Types.DECIMAL:
                case Types.NUMERIC:
                    valueBuilder.at(6).set(createInt(rs.getShort("FIELD_PRECISION"))).at(8).set(createInt(fieldScale * (-1)));
                    break;
                case Types.CHAR:
                case Types.VARCHAR:
                case Types.BINARY:
                case Types.VARBINARY:
                    valueBuilder.at(15).set(createInt(rs.getShort("FIELD_LENGTH")));
                    short charLen = rs.getShort("CHAR_LEN");
                    if (!rs.wasNull()) {
                        valueBuilder.at(6).set(createInt(charLen));
                    } else {
                        valueBuilder.at(6).set(valueBuilder.get(15));
                    }
                    break;
                case Types.FLOAT:
                    valueBuilder.at(6).set(FLOAT_PRECISION);
                    break;
                case Types.DOUBLE:
                    valueBuilder.at(6).set(DOUBLE_PRECISION);
                    break;
                case Types.BIGINT:
                    valueBuilder.at(6).set(BIGINT_PRECISION).at(8).set(INT_ZERO);
                    break;
                case Types.INTEGER:
                    valueBuilder.at(6).set(INTEGER_PRECISION).at(8).set(INT_ZERO);
                    break;
                case Types.SMALLINT:
                    valueBuilder.at(6).set(SMALLINT_PRECISION).at(8).set(INT_ZERO);
                    break;
                case Types.DATE:
                    valueBuilder.at(6).set(DATE_PRECISION);
                    break;
                case Types.TIME:
                    valueBuilder.at(6).set(TIME_PRECISION);
                    break;
                case Types.TIMESTAMP:
                    valueBuilder.at(6).set(TIMESTAMP_PRECISION);
                    break;
                case Types.BOOLEAN:
                    valueBuilder.at(6).set(BOOLEAN_PRECISION).at(9).set(RADIX_BINARY);
                    break;
                case JaybirdTypeCodes.DECFLOAT:
                    switch(fieldType) {
                        case dec16_type:
                            valueBuilder.at(6).set(DECFLOAT_16_PRECISION);
                            break;
                        case dec34_type:
                            valueBuilder.at(6).set(DECFLOAT_34_PRECISION);
                            break;
                    }
                    break;
            }
            final short nullFlag = rs.getShort("NULL_FLAG");
            final short sourceNullFlag = rs.getShort("SOURCE_NULL_FLAG");
            valueBuilder.at(10).set(nullFlag == 1 || sourceNullFlag == 1 ? COLUMN_NO_NULLS : COLUMN_NULLABLE).at(11).set(getBytes(rs.getString("REMARKS")));
            String column_def = rs.getString("DEFAULT_SOURCE");
            if (column_def == null) {
                column_def = rs.getString("DOMAIN_DEFAULT_SOURCE");
            }
            if (column_def != null) {
                // TODO This looks suspicious (what if it contains default)
                int defaultPos = column_def.toUpperCase().indexOf("DEFAULT");
                if (defaultPos >= 0)
                    column_def = column_def.substring(7).trim();
                valueBuilder.at(12).set(getBytes(column_def));
            }
            valueBuilder.at(16).set(createInt(rs.getInt("FIELD_POSITION"))).at(17).set(nullFlag == 1 || sourceNullFlag == 1 ? NO_BYTES : YES_BYTES);
            final boolean isIdentity = Objects.equals("YES", rs.getString("IS_IDENTITY"));
            if (isIdentity) {
                // identity column is an autoincrement for sure
                valueBuilder.at(22).set(YES_BYTES);
            } else {
                switch(dataType) {
                    case Types.INTEGER:
                    case Types.TINYINT:
                    case Types.BIGINT:
                    case Types.SMALLINT:
                        // Could be autoincrement by trigger, but we simply don't know
                        valueBuilder.at(22).set(EMPTY_STRING_BYTES);
                        break;
                    case Types.NUMERIC:
                    case Types.DECIMAL:
                        if (fieldScale == 0) {
                            // Could be autoincrement by trigger, but we simply don't know
                            valueBuilder.at(22).set(EMPTY_STRING_BYTES);
                        } else {
                            // Scaled NUMERIC/DECIMAL: definitely not autoincrement
                            valueBuilder.at(22).set(NO_BYTES);
                        }
                        break;
                    default:
                        // All other types are never autoincrement
                        valueBuilder.at(22).set(NO_BYTES);
                }
            }
            // Retrieving COMPUTED_BLR to check if it was NULL or not
            rs.getString("COMPUTED_BLR");
            // consider identity columns to be generated columns
            boolean isGenerated = !rs.wasNull() || isIdentity;
            valueBuilder.at(23).set(isGenerated ? YES_BYTES : NO_BYTES);
            valueBuilder.at(24).set(isIdentity ? YES_BYTES : NO_BYTES);
            valueBuilder.at(25).set(getBytes(rs.getString("JB_IDENTITY_TYPE")));
            rows.add(valueBuilder.toRowValue(true));
        } while (rs.next());
        return new FBResultSet(rowDescriptor, rows);
    }
}
Also used : RowValueBuilder(org.firebirdsql.gds.ng.fields.RowValueBuilder) RowDescriptor(org.firebirdsql.gds.ng.fields.RowDescriptor) RowDescriptorBuilder(org.firebirdsql.gds.ng.fields.RowDescriptorBuilder) RowValue(org.firebirdsql.gds.ng.fields.RowValue)

Aggregations

RowDescriptorBuilder (org.firebirdsql.gds.ng.fields.RowDescriptorBuilder)15 RowDescriptor (org.firebirdsql.gds.ng.fields.RowDescriptor)12 RowValue (org.firebirdsql.gds.ng.fields.RowValue)12 RowValueBuilder (org.firebirdsql.gds.ng.fields.RowValueBuilder)10 FieldDescriptor (org.firebirdsql.gds.ng.fields.FieldDescriptor)1 Before (org.junit.Before)1