fix(sqlserver): skip TOP when SQL already has OFFSET FETCH NEXT

This commit is contained in:
t8y2 2026-06-12 10:59:24 +08:00
parent 4e0cb1d288
commit 9574c44d75
1 changed files with 21 additions and 1 deletions

View File

@ -357,7 +357,7 @@ fn has_top_level_select_into(sql: &str) -> bool {
}
fn add_sql_server_top(sql: &str, limit: usize) -> String {
if has_top_level_select_top(sql) {
if has_top_level_select_top(sql) || has_top_level_offset_fetch_next(sql) {
return sql.to_string();
}
if sql.len() >= 6 && sql[..6].eq_ignore_ascii_case("SELECT") {
@ -415,6 +415,13 @@ fn has_top_level_fetch_first(sql: &str) -> bool {
tokens.windows(2).any(|w| w[0].text == "FETCH" && w[1].text == "FIRST")
}
fn has_top_level_offset_fetch_next(sql: &str) -> bool {
let tokens = top_level_sql_tokens(sql);
let has_offset = tokens.iter().any(|token| token.text == "OFFSET");
let has_fetch_next = tokens.windows(2).any(|w| w[0].text == "FETCH" && w[1].text == "NEXT");
has_offset && has_fetch_next
}
fn add_fetch_first_limit(statement: &str, limit: usize, offset: usize) -> String {
if has_top_level_fetch_first(statement) {
return format!("{statement};");
@ -787,6 +794,19 @@ mod tests {
assert_eq!(result, err("unsupported"));
}
#[test]
fn keeps_sqlserver_offset_fetch_next_when_offset_is_zero() {
let result = build_paginated_query_sql(PaginatedQuerySqlOptions {
original_sql: "SELECT * FROM TABLE_NAME ORDER BY id OFFSET 1 ROWS FETCH NEXT 10 ROWS ONLY".to_string(),
database_type: Some(DatabaseType::SqlServer),
limit: 100,
offset: 0,
});
assert!(result.ok);
assert_eq!(result.sql.unwrap(), "SELECT * FROM TABLE_NAME ORDER BY id OFFSET 1 ROWS FETCH NEXT 10 ROWS ONLY");
}
#[test]
fn oracle_pagination_skips_sql_clause() {
let result = build_paginated_query_sql(PaginatedQuerySqlOptions {