fix(kingbase): load V8R6 column metadata

This commit is contained in:
zipg 2026-07-20 18:16:28 +08:00 committed by GitHub
parent 378674253c
commit e40ce9336f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 102 additions and 1 deletions

View File

@ -56,6 +56,7 @@ public final class KingbaseAgent extends PostgresLikeAgent {
);
private boolean postgresCatalogMode;
private boolean sqlServerIdentityCatalogMode;
private volatile boolean usePgDefaultExpressionFunction;
public static final PostgresLikeAgentProfile KINGBASE_PROFILE = new PostgresLikeAgentProfile(
"com.kingbase8.Driver",
@ -70,6 +71,7 @@ public final class KingbaseAgent extends PostgresLikeAgent {
protected void afterConnect(ConnectParams params, Connection connection) {
postgresCatalogMode = false;
sqlServerIdentityCatalogMode = false;
usePgDefaultExpressionFunction = false;
setMysqlCompatMode(params.isMysql_compat_mode());
if (params.isMysql_compat_mode()) {
return;
@ -489,12 +491,30 @@ public final class KingbaseAgent extends PostgresLikeAgent {
}
private List<ColumnInfo> getRegularColumns(String schema, String table, Set<String> primaryKeys) {
boolean usePgFunction = usePgDefaultExpressionFunction;
try {
return queryRegularColumns(schema, table, primaryKeys, usePgFunction ? "pg_get_expr" : "sys_get_expr");
} catch (RuntimeException error) {
if (usePgFunction || !isUndefinedFunction(error, "sys_get_expr")) {
throw error;
}
usePgDefaultExpressionFunction = true;
return queryRegularColumns(schema, table, primaryKeys, "pg_get_expr");
}
}
private List<ColumnInfo> queryRegularColumns(
String schema,
String table,
Set<String> primaryKeys,
String defaultExpressionFunction
) {
return unchecked(() -> {
List<ColumnInfo> result = new ArrayList<>();
String sql = "SELECT a.attname AS column_name, " +
"format_type(a.atttypid, a.atttypmod) AS data_type, " +
"NOT a.attnotnull AS is_nullable, " +
"sys_get_expr(ad.adbin, ad.adrelid) AS column_default, " +
defaultExpressionFunction + "(ad.adbin, ad.adrelid) AS column_default, " +
"d.description AS column_comment, " +
"CASE WHEN t.typname = 'numeric' AND a.atttypmod > 0 " +
"THEN ((a.atttypmod - 4) >> 16) & 65535 ELSE NULL END AS numeric_precision, " +
@ -988,6 +1008,23 @@ public final class KingbaseAgent extends PostgresLikeAgent {
return insufficientPrivilege && mentionsSysFreespace;
}
private static boolean isUndefinedFunction(Throwable error, String functionName) {
boolean undefinedFunction = false;
boolean mentionsFunction = false;
for (Throwable current = error; current != null; current = current.getCause()) {
if (current instanceof SQLException && "42883".equals(((SQLException) current).getSQLState())) {
undefinedFunction = true;
}
String message = current.getMessage();
if (message != null) {
String normalized = message.toLowerCase(Locale.ROOT);
mentionsFunction |= normalized.contains(functionName.toLowerCase(Locale.ROOT));
undefinedFunction |= normalized.contains("does not exist") || normalized.contains("不存在");
}
}
return undefinedFunction && mentionsFunction;
}
private static void appendRoutineKindPredicate(StringBuilder sql, List<Object> args, MetadataListConstraints constraints) {
if (!constraints.hasObjectTypes()) {
return;

View File

@ -598,6 +598,21 @@ class KingbaseAgentTest extends JdbcFakeExecutionBehaviorTest {
Assertions.assertNull(columns.get(0).getExtra());
}
@Test
void regularGetColumnsFallsBackToPgGetExprAndCachesTheChoice() {
List<String> sql = new ArrayList<>();
KingbaseAgent agent = new KingbaseAgent();
TestSupport.setPrivateConnection(agent, defaultExpressionFallbackConnection(sql));
List<ColumnInfo> first = agent.getColumns("public", "orders");
List<ColumnInfo> second = agent.getColumns("public", "orders");
Assertions.assertEquals("nextval('orders_id_seq'::regclass)", first.get(0).getColumn_default());
Assertions.assertEquals("nextval('orders_id_seq'::regclass)", second.get(0).getColumn_default());
Assertions.assertEquals(1, sql.stream().filter(query -> query.contains("sys_get_expr(")).count(), sql.toString());
Assertions.assertEquals(2, sql.stream().filter(query -> query.contains("pg_get_expr(")).count(), sql.toString());
}
@Test
void mysqlCompatGetColumnsRestoresBoundedCatalogCharacterTypes() {
List<String> sql = new ArrayList<>();
@ -902,6 +917,55 @@ class KingbaseAgentTest extends JdbcFakeExecutionBehaviorTest {
});
}
private static Connection defaultExpressionFallbackConnection(List<String> sql) {
return proxy(Connection.class, (method, args) -> {
if ("prepareStatement".equals(method.getName())) {
String query = String.valueOf(args[0]);
sql.add(query);
return proxy(PreparedStatement.class, (statementMethod, statementArgs) -> {
if ("executeQuery".equals(statementMethod.getName())) {
return resultSet(new String[]{"column_name"}, new Object[][]{{"id"}});
}
if ("close".equals(statementMethod.getName())) return null;
return defaultValue(statementMethod.getReturnType());
});
}
if ("createStatement".equals(method.getName())) {
return proxy(Statement.class, (statementMethod, statementArgs) -> {
if ("executeQuery".equals(statementMethod.getName())) {
String query = String.valueOf(statementArgs[0]);
sql.add(query);
if (query.contains("sys_get_expr(")) {
throw new SQLException(
"ERROR: function sys_get_expr(pg_node_tree, oid) does not exist",
"42883"
);
}
return resultSet(
new String[]{
"column_name",
"data_type",
"is_nullable",
"column_default",
"column_comment",
"numeric_precision",
"numeric_scale",
"character_maximum_length"
},
new Object[][]{
{"id", "integer", false, "nextval('orders_id_seq'::regclass)", null, 32, 0, null}
}
);
}
if ("close".equals(statementMethod.getName())) return null;
return defaultValue(statementMethod.getReturnType());
});
}
if ("isClosed".equals(method.getName())) return false;
return defaultValue(method.getReturnType());
});
}
private static Connection preparedConnectionWithMetadataFailure(
List<String> sql,
String message,