use of org.firebirdsql.gds.ng.fields.RowDescriptor in project jaybird by FirebirdSQL.
the class FBDatabaseMetaData method getPrimaryKeys.
/**
* Gets a description of a table's primary key columns. They
* are ordered by COLUMN_NAME.
*
* <P>Each primary key column description has the following columns:
* <OL>
* <LI><B>TABLE_CAT</B> String => table catalog (may be null)
* <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
* <LI><B>TABLE_NAME</B> String => table name
* <LI><B>COLUMN_NAME</B> String => column name
* <LI><B>KEY_SEQ</B> short => sequence number within primary key
* <LI><B>PK_NAME</B> String => primary key name (may be null)
* </OL>
*
* @param catalog a catalog name; "" retrieves those without a
* catalog; null means drop catalog name from the selection criteria
* @param schema a schema name; "" retrieves those
* without a schema
* @param table a table name
* @return <code>ResultSet</code> - each row is a primary key column description
* @exception SQLException if a database access error occurs
*/
public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException {
RowDescriptor rowDescriptor = new RowDescriptorBuilder(6, 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_SHORT, 0, "KEY_SEQ", "COLUMNINFO").addField().at(5).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "PK_NAME", "COLUMNINFO").addField().toRowDescriptor();
List<String> params = Collections.singletonList(table);
try (ResultSet rs = doQuery(GET_PRIMARY_KEYS, params)) {
// if nothing found, return empty result set
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("TABLE_NAME"))).at(3).set(getBytes(rs.getString("COLUMN_NAME"))).at(4).set(createShort(rs.getShort("KEY_SEQ"))).at(5).set(getBytes(rs.getString("PK_NAME"))).toRowValue(true));
} while (rs.next());
return new FBResultSet(rowDescriptor, rows);
}
}
use of org.firebirdsql.gds.ng.fields.RowDescriptor in project jaybird by FirebirdSQL.
the class FBDatabaseMetaData method getProcedureColumns.
/**
* Retrieves a description of the given catalog's stored procedure parameter
* and result columns.
*
* <P>Only descriptions matching the schema, procedure and
* parameter name criteria are returned. They are ordered by
* PROCEDURE_CAT, PROCEDURE_SCHEM, PROCEDURE_NAME and 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.
*
* <P>Each row in the <code>ResultSet</code> is a parameter description or
* column description with the following fields:
* <OL>
* <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be <code>null</code>)
* <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be <code>null</code>)
* <LI><B>PROCEDURE_NAME</B> String => procedure name
* <LI><B>COLUMN_NAME</B> String => column/parameter name
* <LI><B>COLUMN_TYPE</B> Short => kind of column/parameter:
* <UL>
* <LI> procedureColumnUnknown - nobody knows
* <LI> procedureColumnIn - IN parameter
* <LI> procedureColumnInOut - INOUT parameter
* <LI> procedureColumnOut - OUT parameter
* <LI> procedureColumnReturn - procedure return value
* <LI> procedureColumnResult - result column in <code>ResultSet</code>
* </UL>
* <LI><B>DATA_TYPE</B> int => SQL type from java.sql.Types
* <LI><B>TYPE_NAME</B> String => SQL type name, for a UDT type the
* type name is fully qualified
* <LI><B>PRECISION</B> int => precision
* <LI><B>LENGTH</B> int => length in bytes of data
* <LI><B>SCALE</B> short => scale - null is returned for data types where
* SCALE is not applicable.
* <LI><B>RADIX</B> short => radix
* <LI><B>NULLABLE</B> short => can it contain NULL.
* <UL>
* <LI> procedureNoNulls - does not allow NULL values
* <LI> procedureNullable - allows NULL values
* <LI> procedureNullableUnknown - nullability unknown
* </UL>
* <LI><B>REMARKS</B> String => comment describing parameter/column
* <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>)
* <UL>
* <LI> The string NULL (not enclosed in quotes) - if NULL was specified as the default value
* <LI> TRUNCATE (not enclosed in quotes) - if the specified default value cannot be represented without truncation
* <LI> NULL - if a default value was not specified
* </UL>
* <LI><B>SQL_DATA_TYPE</B> int => reserved for future use
* <LI><B>SQL_DATETIME_SUB</B> int => reserved for future use
* <LI><B>CHAR_OCTET_LENGTH</B> int => the maximum length of binary and character based columns. For any other datatype the returned value is a
* NULL
* <LI><B>ORDINAL_POSITION</B> int => the ordinal position, starting from 1, for the input and output parameters for a procedure. A value of 0
*is returned if this row describes the procedure's return value. For result set columns, it is the
*ordinal position of the column in the result set starting from 1. If there are
*multiple result sets, the column ordinal positions are implementation
* defined.
* <LI><B>IS_NULLABLE</B> String => ISO rules are used to determine the nullability for a column.
* <UL>
* <LI> YES --- if the parameter can include NULLs
* <LI> NO --- if the parameter cannot include NULLs
* <LI> empty string --- if the nullability for the
* parameter is unknown
* </UL>
* <LI><B>SPECIFIC_NAME</B> String => the name which uniquely identifies this procedure within its schema.
* </OL>
*
* <P><B>Note:</B> Some databases may not return the column
* descriptions for a procedure.
*
* <p>The PRECISION column represents the specified 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 procedureNamePattern a procedure name pattern; must match the
* procedure 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 describes a stored procedure parameter or
* column
* @exception SQLException if a database access error occurs
* @see #getSearchStringEscape
*/
public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException {
final RowDescriptor rowDescriptor = new RowDescriptorBuilder(20, datatypeCoder).at(0).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "PROCEDURE_CAT", "COLUMNINFO").addField().at(1).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "PROCEDURE_SCHEM", "COLUMNINFO").addField().at(2).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "PROCEDURE_NAME", "COLUMNINFO").addField().at(3).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "COLUMN_NAME", "COLUMNINFO").addField().at(4).simple(SQL_SHORT, 0, "COLUMN_TYPE", "COLUMNINFO").addField().at(5).simple(SQL_LONG, 0, "DATA_TYPE", "COLUMNINFO").addField().at(6).simple(SQL_VARYING, 31, "TYPE_NAME", "COLUMNINFO").addField().at(7).simple(SQL_LONG, 0, "PRECISION", "COLUMNINFO").addField().at(8).simple(SQL_LONG, 0, "LENGTH", "COLUMNINFO").addField().at(9).simple(SQL_SHORT, 0, "SCALE", "COLUMNINFO").addField().at(10).simple(SQL_SHORT, 0, "RADIX", "COLUMNINFO").addField().at(11).simple(SQL_SHORT, 0, "NULLABLE", "COLUMNINFO").addField().at(12).simple(SQL_VARYING, Integer.MAX_VALUE, "REMARKS", "COLUMNINFO").addField().at(13).simple(SQL_VARYING, 31, "COLUMN_DEF", "COLUMNINFO").addField().at(14).simple(SQL_LONG, 0, "SQL_DATA_TYPE", "COLUMNINFO").addField().at(15).simple(SQL_LONG, 0, "SQL_DATETIME_SUB", "COLUMNINFO").addField().at(16).simple(SQL_LONG, 0, "CHAR_OCTET_LENGTH", "COLUMNINFO").addField().at(17).simple(SQL_LONG, 0, "ORDINAL_POSITION", "COLUMNINFO").addField().at(18).simple(SQL_VARYING, 3, "IS_NULLABLE", "COLUMNINFO").addField().at(19).simple(SQL_VARYING, OBJECT_NAME_LENGTH, "SPECIFIC_NAME", "COLUMNINFO").addField().toRowDescriptor();
Clause procedureClause = new Clause("PP.RDB$PROCEDURE_NAME", procedureNamePattern);
Clause columnClause = new Clause("PP.RDB$PARAMETER_NAME", columnNamePattern);
String sql = GET_PROCEDURE_COLUMNS_START;
sql += procedureClause.getCondition();
sql += columnClause.getCondition();
sql += GET_PROCEDURE_COLUMNS_END;
List<String> params = new ArrayList<>(2);
if (procedureClause.hasCondition()) {
params.add(procedureClause.getValue());
}
if (columnClause.hasCondition()) {
params.add(columnClause.getValue());
}
try (ResultSet rs = doQuery(sql, params)) {
// if nothing found, return an empty result set
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 columnType = rs.getShort("COLUMN_TYPE");
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");
// TODO: Find out what the difference is with NULL_FLAG in RDB$PROCEDURE_PARAMETERS (might be ODS dependent)
final short nullFlag = rs.getShort("NULL_FLAG");
final int dataType = getDataType(fieldType, fieldSubType, fieldScale, characterSetId);
valueBuilder.at(2).set(getBytes(rs.getString("PROCEDURE_NAME"))).at(3).set(getBytes(rs.getString("COLUMN_NAME"))).at(4).set(columnType == 0 ? PROCEDURE_COLUMN_IN : PROCEDURE_COLUMN_OUT).at(5).set(createInt(dataType)).at(6).set(getBytes(getDataTypeName(fieldType, fieldSubType, fieldScale))).at(8).set(createInt(rs.getShort("FIELD_LENGTH"))).at(10).set(RADIX_TEN_SHORT).at(11).set(nullFlag == 1 ? PROCEDURE_NO_NULLS : PROCEDURE_NULLABLE).at(12).set(getBytes(rs.getString("REMARKS"))).at(17).set(createInt(rs.getInt("PARAMETER_NUMBER"))).at(18).set(nullFlag == 1 ? NO_BYTES : YES_BYTES).at(19).set(valueBuilder.get(2));
switch(dataType) {
case Types.DECIMAL:
case Types.NUMERIC:
valueBuilder.at(7).set(createInt(rs.getShort("FIELD_PRECISION"))).at(9).set(createShort(-1 * fieldScale));
break;
case Types.CHAR:
case Types.VARCHAR:
case Types.BINARY:
case Types.VARBINARY:
short charLen = rs.getShort("CHAR_LEN");
if (!rs.wasNull()) {
valueBuilder.at(7).set(createInt(charLen));
} else {
valueBuilder.at(8).set(valueBuilder.get(8));
}
valueBuilder.at(16).set(valueBuilder.get(8));
break;
case Types.FLOAT:
valueBuilder.at(7).set(FLOAT_PRECISION);
break;
case Types.DOUBLE:
valueBuilder.at(7).set(DOUBLE_PRECISION);
break;
case Types.BIGINT:
valueBuilder.at(7).set(BIGINT_PRECISION).at(9).set(SHORT_ZERO);
break;
case Types.INTEGER:
valueBuilder.at(7).set(INTEGER_PRECISION).at(9).set(SHORT_ZERO);
break;
case Types.SMALLINT:
valueBuilder.at(7).set(SMALLINT_PRECISION).at(9).set(SHORT_ZERO);
break;
case Types.DATE:
valueBuilder.at(7).set(DATE_PRECISION);
break;
case Types.TIME:
valueBuilder.at(7).set(TIME_PRECISION);
break;
case Types.TIMESTAMP:
valueBuilder.at(7).set(TIMESTAMP_PRECISION);
break;
case Types.BOOLEAN:
valueBuilder.at(7).set(BOOLEAN_PRECISION).at(10).set(RADIX_BINARY_SHORT);
break;
case JaybirdTypeCodes.DECFLOAT:
switch(fieldType) {
case dec16_type:
valueBuilder.at(7).set(DECFLOAT_16_PRECISION);
break;
case dec34_type:
valueBuilder.at(7).set(DECFLOAT_34_PRECISION);
break;
}
break;
}
rows.add(valueBuilder.toRowValue(true));
} while (rs.next());
return new FBResultSet(rowDescriptor, rows);
}
}
use of org.firebirdsql.gds.ng.fields.RowDescriptor in project jaybird by FirebirdSQL.
the class AbstractFbStatement method validateParameters.
/**
* Validates if the number of parameters matches the expected number and types, and if all values have been set.
*
* @param parameters
* Parameter values to validate
* @throws SQLException
* When the number or type of parameters does not match {@link #getParameterDescriptor()}, or when a parameter has not been set.
*/
protected void validateParameters(final RowValue parameters) throws SQLException {
final RowDescriptor parameterDescriptor = getParameterDescriptor();
final int expectedSize = parameterDescriptor != null ? parameterDescriptor.getCount() : 0;
final int actualSize = parameters.getCount();
// TODO Externalize sqlstates
if (actualSize != expectedSize) {
// TODO use HY021 (inconsistent descriptor information) instead?
throw new SQLNonTransientException(String.format("Invalid number of parameters, expected %d, got %d", expectedSize, actualSize), // invalid descriptor count
"07008");
}
for (int fieldIndex = 0; fieldIndex < actualSize; fieldIndex++) {
FieldValue fieldValue = parameters.getFieldValue(fieldIndex);
if (fieldValue == null || !fieldValue.isInitialized()) {
// TODO use HY000 (dynamic parameter value needed) instead?
throw new SQLTransientException(String.format("Parameter with index %d was not set", fieldIndex + 1), // undefined DATA value
"0700C");
}
}
}
use of org.firebirdsql.gds.ng.fields.RowDescriptor in project jaybird by FirebirdSQL.
the class AbstractStatementTest method test_PrepareSelectableStoredProcedure.
@Test
public void test_PrepareSelectableStoredProcedure() throws Exception {
allocateStatement();
statement.prepare(EXECUTE_SELECTABLE_STORED_PROCEDURE);
assertEquals("Unexpected StatementType", StatementType.SELECT, statement.getType());
final RowDescriptor fields = statement.getFieldDescriptor();
assertNotNull("Fields", fields);
List<FieldDescriptor> expectedFields = Collections.singletonList(new FieldDescriptor(0, db.getDatatypeCoder(), ISCConstants.SQL_LONG | 1, 0, 0, 4, "OUTVALUE", null, "OUTVALUE", "RANGE", "SYSDBA"));
assertEquals("Unexpected values for fields", expectedFields, fields.getFieldDescriptors());
final RowDescriptor parameters = statement.getParameterDescriptor();
assertNotNull("Parameters", parameters);
List<FieldDescriptor> expectedParameters = Arrays.asList(new FieldDescriptor(0, db.getDatatypeCoder(), ISCConstants.SQL_LONG | 1, 0, 0, 4, null, null, null, null, null), new FieldDescriptor(1, db.getDatatypeCoder(), ISCConstants.SQL_LONG | 1, 0, 0, 4, null, null, null, null, null));
assertEquals("Unexpected values for parameters", expectedParameters, parameters.getFieldDescriptors());
}
use of org.firebirdsql.gds.ng.fields.RowDescriptor in project jaybird by FirebirdSQL.
the class AbstractStatementTest method test_PrepareExecutableStoredProcedure.
@Test
public void test_PrepareExecutableStoredProcedure() throws Exception {
allocateStatement();
statement.prepare(EXECUTE_EXECUTABLE_STORED_PROCEDURE);
assertEquals("Unexpected StatementType", StatementType.STORED_PROCEDURE, statement.getType());
final RowDescriptor fields = statement.getFieldDescriptor();
assertNotNull("Fields", fields);
List<FieldDescriptor> expectedFields = Collections.singletonList(new FieldDescriptor(0, db.getDatatypeCoder(), ISCConstants.SQL_LONG | 1, 0, 0, 4, "OUTVALUE", null, "OUTVALUE", "INCREMENT", "SYSDBA"));
assertEquals("Unexpected values for fields", expectedFields, fields.getFieldDescriptors());
final RowDescriptor parameters = statement.getParameterDescriptor();
assertNotNull("Parameters", parameters);
List<FieldDescriptor> expectedParameters = Collections.singletonList(new FieldDescriptor(0, db.getDatatypeCoder(), ISCConstants.SQL_LONG | 1, 0, 0, 4, null, null, null, null, null));
assertEquals("Unexpected values for parameters", expectedParameters, parameters.getFieldDescriptors());
}
Aggregations