fix(jdbc): avoid default max rows rewrite

This commit is contained in:
t8y2 2026-06-18 17:00:44 +08:00
parent 46cefabe57
commit ffe535e40e
6 changed files with 43 additions and 9 deletions

View File

@ -787,7 +787,7 @@ fn build_data_compare_select_sql(
);
}
// JDBC connections rely on Statement.setMaxRows() for row limiting.
// JDBC connections avoid SQL-level LIMIT; the agent truncates rows while reading.
if database_type == DatabaseType::Jdbc {
return format!("SELECT {select_columns} FROM {table}{order_by};");
}

View File

@ -112,7 +112,7 @@ pub fn build_database_search_sql(options: DatabaseSearchSqlOptions) -> Option<Da
} else if options.database_type.is_some_and(uses_fetch_first) {
format!("SELECT * FROM {table} WHERE ({where_clause}) FETCH FIRST {limit} ROWS ONLY")
} else if options.database_type == Some(DatabaseType::Jdbc) {
// JDBC connections rely on Statement.setMaxRows() for row limiting.
// JDBC connections avoid SQL-level LIMIT; the agent truncates rows while reading.
format!("SELECT * FROM {table} WHERE ({where_clause});")
} else {
format!("SELECT * FROM {table} WHERE ({where_clause}) LIMIT {limit};")

View File

@ -207,7 +207,7 @@ pub fn build_paginated_query_sql(options: PaginatedQuerySqlOptions) -> QuerySqlB
return ok(add_fetch_first_limit(&statement, safe_limit, safe_offset));
}
// JDBC connections rely on Statement.setMaxRows() for row limiting.
// JDBC connections avoid SQL-level LIMIT; the agent truncates rows while reading.
if options.database_type == Some(DatabaseType::Jdbc) {
return ok(format!("{statement};"));
}

View File

@ -121,8 +121,8 @@ pub fn build_table_data_select_sql(options: TableDataSelectSqlOptions) -> String
let offset =
options.offset.filter(|offset| *offset > 0).map(|offset| format!(" OFFSET {offset}")).unwrap_or_default();
// JDBC connections rely on Statement.setMaxRows() for row limiting instead of
// SQL-level LIMIT, which is not universally supported across all JDBC drivers.
// JDBC connections avoid SQL-level LIMIT because it is not universally
// supported across all JDBC drivers; the agent truncates rows while reading.
if database_type == Some(DatabaseType::Jdbc) {
return format!("SELECT {select_columns} FROM {table_alias}{where_clause}{order};");
}
@ -173,7 +173,7 @@ pub fn build_table_select_sql(options: TableSelectSqlOptions<'_>) -> String {
return format!("SELECT TOP ({limit}) {select_columns} FROM {table}{order_by}");
}
// JDBC connections rely on Statement.setMaxRows() for row limiting.
// JDBC connections avoid SQL-level LIMIT; the agent truncates rows while reading.
if database_type == Some(DatabaseType::Jdbc) {
return format!("SELECT {select_columns} FROM {table}{order_by};");
}

View File

@ -60,7 +60,7 @@ public final class DbxJdbcPlugin {
false,
false,
false,
StatementMaxRowsMode.APPLY_STATEMENT_MAX_ROWS
StatementMaxRowsMode.READ_LOOP_ONLY
);
private static final JdbcDriverQuirks USE_CATALOG_QUIRKS = DEFAULT_QUIRKS.withUseCatalogFallbackSql(true);
private static final JdbcDriverQuirks KINGBASE_QUIRKS = DEFAULT_QUIRKS.withIgnoreCatalogForSchemaMetadata(true);

View File

@ -328,6 +328,11 @@ final class DbxJdbcPluginTest {
"connection_string": "jdbc:h2:mem:dbx_quirks"
}
""");
JsonNode cache = MAPPER.readTree("""
{
"connection_string": "jdbc:Cache://127.0.0.1:1972/USER"
}
""");
JsonNode mysql = MAPPER.readTree("""
{
"connection_string": "jdbc:mysql://127.0.0.1:9030/demo"
@ -363,9 +368,13 @@ final class DbxJdbcPluginTest {
assertEquals(false, DbxJdbcPlugin.driverQuirks(h2).caseInsensitiveSchemaMetadata());
assertEquals(false, DbxJdbcPlugin.driverQuirks(h2).useCatalogFallbackSql());
assertEquals(
DbxJdbcPlugin.StatementMaxRowsMode.APPLY_STATEMENT_MAX_ROWS,
DbxJdbcPlugin.StatementMaxRowsMode.READ_LOOP_ONLY,
DbxJdbcPlugin.driverQuirks(h2).statementMaxRowsMode()
);
assertEquals(
DbxJdbcPlugin.StatementMaxRowsMode.READ_LOOP_ONLY,
DbxJdbcPlugin.driverQuirks(cache).statementMaxRowsMode()
);
assertEquals(true, DbxJdbcPlugin.driverQuirks(mysql).useCatalogFallbackSql());
assertEquals(true, DbxJdbcPlugin.driverQuirks(kingbase).ignoreCatalogForSchemaMetadata());
assertEquals(true, DbxJdbcPlugin.driverQuirks(kyuubi).useCatalogFallbackSql());
@ -398,7 +407,7 @@ final class DbxJdbcPluginTest {
}
@Test
void defaultStatementOptionsApplyDriverMaxRowsProtection() throws Exception {
void defaultStatementOptionsSkipDriverMaxRowsRewrite() throws Exception {
Method method = DbxJdbcPlugin.class.getDeclaredMethod(
"applyStatementOptions",
Statement.class,
@ -417,6 +426,31 @@ final class DbxJdbcPluginTest {
method.invoke(null, recordingStatement(calls), 100, 50, 30, DbxJdbcPlugin.driverQuirks(h2));
assertFalse(calls.contains("setMaxRows"), calls.toString());
assertEquals(true, calls.contains("setFetchSize"));
assertEquals(true, calls.contains("setQueryTimeout"));
}
@Test
void optInStatementOptionsCanApplyDriverMaxRowsProtection() throws Exception {
Method method = DbxJdbcPlugin.class.getDeclaredMethod(
"applyStatementOptions",
Statement.class,
int.class,
int.class,
int.class,
DbxJdbcPlugin.JdbcDriverQuirks.class
);
method.setAccessible(true);
JsonNode yashan = MAPPER.readTree("""
{
"connection_string": "jdbc:yasdb://127.0.0.1:1688/yasdb"
}
""");
List<String> calls = new ArrayList<>();
method.invoke(null, recordingStatement(calls), 100, 50, 30, DbxJdbcPlugin.driverQuirks(yashan));
assertEquals(true, calls.contains("setMaxRows"));
assertEquals(true, calls.contains("setFetchSize"));
assertEquals(true, calls.contains("setQueryTimeout"));