ColumnMetaData.java
package org.itsallcode.jdbc.metadata;
import java.sql.*;
import java.util.Arrays;
/**
* Description of a column.
*
* @param tableCatalog table catalog (may be {@code null})
* @param tableSchema table schema (may be {@code null})
* @param tableName table name
* @param columnName column name
* @param dataType SQL type
* @param typeName Data source dependent type name, for a UDT the type
* name is fully qualified
* @param columnSize column size.
* @param decimalDigits the number of fractional digits. {@code null} is
* returned for data types where DECIMAL_DIGITS is not
* applicable.
* @param numPrecisionRadix Radix (typically either 10 or 2)
* @param nullable is {@code NULL} allowed.
* @param remarks comment describing column (may be {@code null})
* @param columnDef default value for the column, which should be
* interpreted as a string when the value is enclosed
* in single quotes (may be {@code null})
* @param charOctetLength for char types the maximum number of bytes in the
* column
* @param ordinalPosition index of column in table (starting at 1)
* @param isNullable ISO rules are used to determine the nullability for
* a column.
* @param scopeCatalog catalog of table that is the scope of a reference
* attribute ({@code null} if DATA_TYPE isn't REF)
* @param scopeSchema schema of table that is the scope of a reference
* attribute ({@code null} if the DATA_TYPE isn't REF)
* @param scopeTable table name that this the scope of a reference
* attribute ({@code null} if the DATA_TYPE isn't REF)
* @param sourceDataType source type of a distinct type or user-generated Ref
* type, SQL type from java.sql.Types ({@code null} if
* DATA_TYPE isn't DISTINCT or user-generated REF)
* @param isAutoIncrement Indicates whether this column is auto incremented
* @param isGeneratedColumn Indicates whether this is a generated column
* @see DatabaseMetaData#getColumns(String, String, String, String)
*/
public record ColumnMetaData(
String tableCatalog,
String tableSchema,
String tableName,
String columnName,
JDBCType dataType,
String typeName,
int columnSize,
int decimalDigits,
int numPrecisionRadix,
Nullability nullable,
String remarks,
String columnDef,
int charOctetLength,
int ordinalPosition,
ISONullability isNullable,
String scopeCatalog,
String scopeSchema,
String scopeTable,
short sourceDataType,
AutoIncrement isAutoIncrement,
Generated isGeneratedColumn) {
static ColumnMetaData create(final ResultSet rs) throws SQLException {
return new ColumnMetaData(
rs.getString("TABLE_CAT"),
rs.getString("TABLE_SCHEM"),
rs.getString("TABLE_NAME"),
rs.getString("COLUMN_NAME"),
JDBCType.valueOf(rs.getInt("DATA_TYPE")),
rs.getString("TYPE_NAME"),
rs.getInt("COLUMN_SIZE"),
rs.getInt("DECIMAL_DIGITS"),
rs.getInt("NUM_PREC_RADIX"),
Nullability.valueOf(rs.getInt("NULLABLE")),
rs.getString("REMARKS"),
rs.getString("COLUMN_DEF"),
rs.getInt("CHAR_OCTET_LENGTH"),
rs.getInt("ORDINAL_POSITION"),
ISONullability.valueOfNullability(rs.getString("IS_NULLABLE")),
rs.getString("SCOPE_CATALOG"),
rs.getString("SCOPE_SCHEMA"),
rs.getString("SCOPE_TABLE"),
rs.getShort("SOURCE_DATA_TYPE"),
AutoIncrement.valueOfAutoIncrement(rs.getString("IS_AUTOINCREMENT")),
Generated.valueOfGenerated(rs.getString("IS_GENERATEDCOLUMN")));
}
/**
* Column nullability.
*/
public enum Nullability {
/** Column might not allow {@code NULL} values. */
NO_NULLS(DatabaseMetaData.columnNoNulls),
/** Column definitely allows {@code NULL} values. */
NULLABLE(DatabaseMetaData.columnNullable),
/** nullability unknown */
NULLABLE_UNKNOWN(DatabaseMetaData.columnNullableUnknown);
private final int value;
Nullability(final int value) {
this.value = value;
}
static Nullability valueOf(final int value) {
return Arrays.stream(Nullability.values())
.filter(n -> n.value == value)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(
"Unknown value %d for nullability".formatted(value)));
}
}
/**
* Column ISO nullability.
*/
public enum ISONullability {
/** Column can include NULLs. */
NO_NULLS("YES"),
/** Column cannot include NULLs. */
NULLABLE("NO"),
/** Nullability for the column is unknown */
NULLABLE_UNKNOWN("");
private final String value;
ISONullability(final String value) {
this.value = value;
}
static ISONullability valueOfNullability(final String value) {
return Arrays.stream(ISONullability.values())
.filter(n -> n.value.equals(value))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(
"Unknown value '%s' for ISO nullability".formatted(value)));
}
}
/**
* Indicates whether a column is auto incremented.
*/
public enum AutoIncrement {
/** Column is auto incremented. */
AUTO_INCREMENT("YES"),
/** Column is not auto incremented. */
NO_AUTO_INCREMENT("NO"),
/** It cannot be determined whether the column is auto incremented. */
UNKNOWN("");
private final String value;
AutoIncrement(final String value) {
this.value = value;
}
static AutoIncrement valueOfAutoIncrement(final String value) {
return Arrays.stream(AutoIncrement.values())
.filter(n -> n.value.equals(value))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(
"Unknown value '%s' for auto increment".formatted(value)));
}
}
/**
* Indicates whether this is a generated column.
*/
public enum Generated {
/** This a generated column. */
GENERATED("YES"),
/** This not a generated column. */
NOT_GENERATED("NO"),
/** It cannot be determined whether this is a generated column. */
UNKNOWN("");
private final String value;
Generated(final String value) {
this.value = value;
}
static Generated valueOfGenerated(final String value) {
return Arrays.stream(Generated.values())
.filter(n -> n.value.equals(value))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(
"Unknown value '%s' for column generated".formatted(value)));
}
}
}