in java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/ObjectMetadataBuilder.java [223:349]
private int buildTables(int rowIndex, String catalogName, String dbSchemaName)
throws AdbcException, SQLException {
int tableCount = 0;
try (final ResultSet rs =
dbmd.getTables(catalogName, dbSchemaName, tableNamePattern, tableTypesFilter)) {
while (rs.next()) {
final @Nullable String tableName = rs.getString(3);
final @Nullable String tableType = rs.getString(4);
if (tableName == null || tableType == null) {
throw new AdbcException(
JdbcDriverUtil.prefixExceptionMessage("JDBC driver returned null table name/type"),
null,
AdbcStatusCode.INTERNAL,
null,
0);
}
tables.setIndexDefined(rowIndex + tableCount);
tableNames.setSafe(rowIndex + tableCount, tableName.getBytes(StandardCharsets.UTF_8));
tableTypes.setSafe(rowIndex + tableCount, tableType.getBytes(StandardCharsets.UTF_8));
tableConstraintsWriter.setPosition(rowIndex + tableCount);
tableConstraintsWriter.startList();
// JDBC doesn't directly expose constraints. Merge various info methods:
// 1. Primary keys
try (final ResultSet pk = dbmd.getPrimaryKeys(catalogName, dbSchemaName, tableName)) {
String constraintName = null;
List<@Nullable String> constraintColumns = new ArrayList<>();
while (pk.next()) {
constraintName = pk.getString(6);
String columnName = pk.getString(4);
int columnIndex = pk.getInt(5);
while (constraintColumns.size() < columnIndex) constraintColumns.add(null);
constraintColumns.set(columnIndex - 1, columnName);
}
if (!constraintColumns.isEmpty()) {
addConstraint(
constraintName, "PRIMARY KEY", constraintColumns, Collections.emptyList());
}
}
// 2. Foreign keys ("imported" keys)
try (final ResultSet fk = dbmd.getImportedKeys(catalogName, dbSchemaName, tableName)) {
List<@Nullable String> names = new ArrayList<>();
List<List<@Nullable String>> columns = new ArrayList<>();
List<List<ReferencedColumn>> references = new ArrayList<>();
while (fk.next()) {
String keyName = fk.getString(12);
String keyColumn = fk.getString(8);
int keySeq = fk.getInt(9);
if (keySeq == 1) {
names.add(keyName);
columns.add(new ArrayList<>());
references.add(new ArrayList<>());
}
columns.get(columns.size() - 1).add(keyColumn);
final @Nullable String fkTableName = fk.getString(3);
final @Nullable String fkColumnName = fk.getString(4);
if (fkTableName == null || fkColumnName == null) {
throw new AdbcException(
JdbcDriverUtil.prefixExceptionMessage(
"JDBC driver returned null table/column name"),
null,
AdbcStatusCode.INTERNAL,
null,
0);
}
final ReferencedColumn reference =
new ReferencedColumn(fk.getString(1), fk.getString(2), fkTableName, fkColumnName);
references.get(references.size() - 1).add(reference);
}
for (int i = 0; i < names.size(); i++) {
addConstraint(names.get(i), "FOREIGN KEY", columns.get(i), references.get(i));
}
}
// 3. UNIQUE constraints
try (final ResultSet uq =
dbmd.getIndexInfo(catalogName, dbSchemaName, tableName, true, false)) {
Map<String, ArrayList<@Nullable String>> uniqueConstraints = new HashMap<>();
while (uq.next()) {
@Nullable String constraintName = uq.getString(6);
@Nullable String columnName = uq.getString(9);
int columnIndex = uq.getInt(8);
if (constraintName == null || columnName == null) {
throw new AdbcException(
JdbcDriverUtil.prefixExceptionMessage(
"JDBC driver returned null constraint/column name"),
null,
AdbcStatusCode.INTERNAL,
null,
0);
}
if (!uniqueConstraints.containsKey(constraintName)) {
uniqueConstraints.put(constraintName, new ArrayList<>());
}
ArrayList<@Nullable String> uniqueColumns = uniqueConstraints.get(constraintName);
while (uniqueColumns.size() < columnIndex) uniqueColumns.add(null);
uniqueColumns.set(columnIndex - 1, columnName);
}
uniqueConstraints.forEach(
(name, columns) -> {
addConstraint(name, "UNIQUE", columns, Collections.emptyList());
});
}
// TODO: how to get CHECK constraints?
tableConstraintsWriter.endList();
if (depth == AdbcConnection.GetObjectsDepth.TABLES) {
tableColumns.setNull(rowIndex + tableCount);
} else {
int columnBaseIndex = tableColumns.startNewValue(rowIndex + tableCount);
final int columnCount =
buildColumns(columnBaseIndex, catalogName, dbSchemaName, tableName);
tableColumns.endValue(rowIndex + tableCount, columnCount);
}
tableCount++;
}
}
return tableCount;
}