fix(kingbase): load V8R6 column metadata
This commit is contained in:
parent
378674253c
commit
e40ce9336f
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue