fix(mysql): respect query page size with existing limit
This commit is contained in:
1 parent
a9e679ec7e
commit
ed9fe57617
1 file changed
+60
-1
@@ -803,6 +803,33 @@ fn has_top_level_limit(sql: &str) -> bool {
|
|||||||
top_level_sql_tokens(sql).iter().any(|token| token.text == "LIMIT")
|
top_level_sql_tokens(sql).iter().any(|token| token.text == "LIMIT")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn top_level_limit_row_count(sql: &str) -> Option<usize> {
|
||||||
|
let token = top_level_sql_tokens(sql).into_iter().find(|token| token.text == "LIMIT")?;
|
||||||
|
parse_standard_limit_row_count(sql, token.start + token.text.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_standard_limit_row_count(sql: &str, start: usize) -> Option<usize> {
|
||||||
|
let mut cursor = skip_sql_whitespace(sql, start);
|
||||||
|
let first = parse_usize_literal(sql, &mut cursor)?;
|
||||||
|
cursor = skip_sql_whitespace(sql, cursor);
|
||||||
|
if sql.get(cursor..)?.starts_with(',') {
|
||||||
|
cursor = skip_sql_whitespace(sql, cursor + 1);
|
||||||
|
return parse_usize_literal(sql, &mut cursor);
|
||||||
|
}
|
||||||
|
Some(first)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_usize_literal(sql: &str, cursor: &mut usize) -> Option<usize> {
|
||||||
|
let start = *cursor;
|
||||||
|
while *cursor < sql.len() && sql.as_bytes()[*cursor].is_ascii_digit() {
|
||||||
|
*cursor += 1;
|
||||||
|
}
|
||||||
|
if *cursor == start {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
sql[start..*cursor].parse().ok()
|
||||||
|
}
|
||||||
|
|
||||||
fn has_top_level_informix_row_limit(sql: &str) -> bool {
|
fn has_top_level_informix_row_limit(sql: &str) -> bool {
|
||||||
if has_top_level_limit(sql) {
|
if has_top_level_limit(sql) {
|
||||||
return true;
|
return true;
|
||||||
@@ -914,7 +941,9 @@ fn add_standard_limit(
|
|||||||
// ordering across pages in distributed databases like Doris.
|
// ordering across pages in distributed databases like Doris.
|
||||||
return add_outer_standard_limit(statement, database_type, limit, offset, &order_sql);
|
return add_outer_standard_limit(statement, database_type, limit, offset, &order_sql);
|
||||||
}
|
}
|
||||||
if offset > 0 {
|
// A user/top-level LIMIT can still be wider than the selected grid page size.
|
||||||
|
// Wrap it so the first page respects the UI page limit while preserving the user's cap.
|
||||||
|
if offset > 0 || top_level_limit_row_count(statement).is_some_and(|row_count| row_count > limit) {
|
||||||
return add_outer_standard_limit(statement, database_type, limit, offset, "");
|
return add_outer_standard_limit(statement, database_type, limit, offset, "");
|
||||||
}
|
}
|
||||||
return format!("{statement};");
|
return format!("{statement};");
|
||||||
@@ -1911,6 +1940,36 @@ WHERE u.id = picked.id;
|
|||||||
assert_eq!(result.sql.unwrap(), "SELECT id FROM users LIMIT 20;");
|
assert_eq!(result.sql.unwrap(), "SELECT id FROM users LIMIT 20;");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mysql_pagination_wraps_wide_existing_limit_on_first_page() {
|
||||||
|
let result = build_paginated_query_sql(PaginatedQuerySqlOptions {
|
||||||
|
original_sql: "SELECT * FROM dy_promotion_item WHERE create_time < '2026-06-01' LIMIT 10000;".to_string(),
|
||||||
|
database_type: Some(DatabaseType::Mysql),
|
||||||
|
limit: 500,
|
||||||
|
offset: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result.sql.unwrap(),
|
||||||
|
"SELECT * FROM (SELECT * FROM dy_promotion_item WHERE create_time < '2026-06-01' LIMIT 10000) `dbx_page` LIMIT 500 OFFSET 0;"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mysql_pagination_wraps_comma_limit_row_count_on_first_page() {
|
||||||
|
let result = build_paginated_query_sql(PaginatedQuerySqlOptions {
|
||||||
|
original_sql: "SELECT * FROM users LIMIT 20, 10000;".to_string(),
|
||||||
|
database_type: Some(DatabaseType::Mysql),
|
||||||
|
limit: 500,
|
||||||
|
offset: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result.sql.unwrap(),
|
||||||
|
"SELECT * FROM (SELECT * FROM users LIMIT 20, 10000) `dbx_page` LIMIT 500 OFFSET 0;"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mysql_pagination_wraps_existing_limit_for_later_pages() {
|
fn mysql_pagination_wraps_existing_limit_for_later_pages() {
|
||||||
let result = build_paginated_query_sql(PaginatedQuerySqlOptions {
|
let result = build_paginated_query_sql(PaginatedQuerySqlOptions {
|
||||||
|
|||||||
Reference in new issue
Block a user