fix(jdbc): recover primary keys via catalog fallback

This commit is contained in:
LRcoding authored and GitHub committed 2026-07-07 14:41:52 +08:00
1 parent c3893bf314
commit f659a74a87
2 files changed
+131 -1

No files matched your search

@@ -168,7 +168,11 @@ public final class StandardJdbcMetadata {
Set<String> primaryKeys = primaryKeys(meta, null, schema, table); Set<String> primaryKeys = primaryKeys(meta, null, schema, table);
List<ColumnInfo> result = new ArrayList<>(); List<ColumnInfo> result = new ArrayList<>();
appendColumns(result, meta, null, schema, table, primaryKeys); appendColumns(result, meta, null, schema, table, primaryKeys);
if (result.isEmpty() && profile.getCatalogFallbackEnabled() && !configuredDatabase.trim().isEmpty()) { if (!result.isEmpty() && primaryKeys.isEmpty() && profile.getCatalogFallbackEnabled() && hasConfiguredDatabase(configuredDatabase)) {
Set<String> fallbackPrimaryKeys = primaryKeys(meta, configuredDatabase, schema, table);
markPrimaryKeys(result, fallbackPrimaryKeys);
}
if (result.isEmpty() && profile.getCatalogFallbackEnabled() && hasConfiguredDatabase(configuredDatabase)) {
Set<String> fallbackPrimaryKeys = primaryKeys(meta, configuredDatabase, schema, table); Set<String> fallbackPrimaryKeys = primaryKeys(meta, configuredDatabase, schema, table);
appendColumns(result, meta, configuredDatabase, schema, table, fallbackPrimaryKeys); appendColumns(result, meta, configuredDatabase, schema, table, fallbackPrimaryKeys);
} }
@@ -522,6 +526,21 @@ public final class StandardJdbcMetadata {
return keys; return keys;
} }
private static boolean hasConfiguredDatabase(String configuredDatabase) {
return configuredDatabase != null && !configuredDatabase.trim().isEmpty();
}
private static void markPrimaryKeys(List<ColumnInfo> columns, Set<String> primaryKeys) {
if (primaryKeys.isEmpty()) {
return;
}
for (ColumnInfo column : columns) {
if (primaryKeys.contains(column.getName())) {
column.setIs_primary_key(true);
}
}
}
private static void appendSchemas(Set<String> names, ResultSet rs) throws Exception { private static void appendSchemas(Set<String> names, ResultSet rs) throws Exception {
try (ResultSet closeable = rs) { try (ResultSet closeable = rs) {
while (closeable.next()) { while (closeable.next()) {
@@ -230,6 +230,64 @@ class StandardJdbcMetadataTest {
assertEquals(Integer.valueOf(64), columns.get(1).getCharacter_maximum_length()); assertEquals(Integer.valueOf(64), columns.get(1).getCharacter_maximum_length());
} }
@Test
void marksPrimaryKeysFromConfiguredCatalogWhenColumnsAlreadyLoaded() {
Connection conn = catalogPrimaryKeyFallbackConnection(
"TENANTDB",
rows(),
rows(row("COLUMN_NAME", "ID")),
orderColumns()
);
List<ColumnInfo> columns = StandardJdbcMetadata.INSTANCE.getColumns(conn, profile, "TENANTDB", "APP", "ORDERS");
assertEquals("ID", columns.get(0).getName());
assertTrue(columns.get(0).getIs_primary_key());
assertFalse(columns.get(0).getIs_nullable());
assertEquals("NAME", columns.get(1).getName());
assertFalse(columns.get(1).getIs_primary_key());
assertEquals(Integer.valueOf(64), columns.get(1).getCharacter_maximum_length());
}
@Test
void doesNotMarkPrimaryKeysFromConfiguredCatalogWhenFallbackUnavailable() {
JdbcAgentProfile fallbackDisabledProfile = new JdbcAgentProfile(
"example.Driver",
"jdbc:example://{host}:{port}/{database}",
0,
false,
Collections.emptySet(),
Collections.singletonList("TABLE"),
"\"",
"SET SCHEMA",
false,
false,
false,
false
);
Connection disabledConn = catalogPrimaryKeyFallbackConnection(
"TENANTDB",
rows(),
rows(row("COLUMN_NAME", "ID")),
orderColumns()
);
List<ColumnInfo> disabledColumns = StandardJdbcMetadata.INSTANCE.getColumns(disabledConn, fallbackDisabledProfile, "TENANTDB", "APP", "ORDERS");
assertFalse(disabledColumns.get(0).getIs_primary_key());
Connection emptyCatalogConn = catalogPrimaryKeyFallbackConnection(
"TENANTDB",
rows(),
rows(row("COLUMN_NAME", "ID")),
orderColumns()
);
List<ColumnInfo> emptyCatalogColumns = StandardJdbcMetadata.INSTANCE.getColumns(emptyCatalogConn, profile, " ", "APP", "ORDERS");
assertFalse(emptyCatalogColumns.get(0).getIs_primary_key());
}
@Test @Test
void groupsIndexColumnsInOrdinalOrder() { void groupsIndexColumnsInOrdinalOrder() {
Connection conn = connection( Connection conn = connection(
@@ -490,6 +548,59 @@ class StandardJdbcMetadataTest {
}); });
} }
private static Connection catalogPrimaryKeyFallbackConnection(
String fallbackCatalog,
ResultSet defaultPrimaryKeys,
ResultSet fallbackPrimaryKeys,
ResultSet columns
) {
DatabaseMetaData meta = proxy(DatabaseMetaData.class, new MethodHandler() {
@Override
public Object handle(Method method, Object[] args) {
String name = method.getName();
if ("getPrimaryKeys".equals(name)) {
return fallbackCatalog.equals(args[0]) ? fallbackPrimaryKeys : defaultPrimaryKeys;
}
if ("getColumns".equals(name)) {
return columns;
}
if ("getCatalogs".equals(name)) {
return rows();
}
return defaultValue(method.getReturnType());
}
});
return proxy(Connection.class, new MethodHandler() {
@Override
public Object handle(Method method, Object[] args) {
if ("getMetaData".equals(method.getName())) {
return meta;
}
return defaultValue(method.getReturnType());
}
});
}
private static ResultSet orderColumns() {
return rows(row(
"COLUMN_NAME", "ID",
"TYPE_NAME", "INTEGER",
"NULLABLE", DatabaseMetaData.columnNoNulls,
"COLUMN_DEF", null,
"REMARKS", "identifier",
"COLUMN_SIZE", 10,
"DECIMAL_DIGITS", 0
), row(
"COLUMN_NAME", "NAME",
"TYPE_NAME", "VARCHAR",
"NULLABLE", DatabaseMetaData.columnNullable,
"COLUMN_DEF", null,
"REMARKS", null,
"COLUMN_SIZE", 64,
"DECIMAL_DIGITS", 0
));
}
private static ResultSet rows(Map<String, Object>... rows) { private static ResultSet rows(Map<String, Object>... rows) {
return proxy(ResultSet.class, new MethodHandler() { return proxy(ResultSet.class, new MethodHandler() {
private int index = -1; private int index = -1;