fix(firebird): use rows syntax for pagination

This commit is contained in:
t8y2 committed 2026-07-03 16:22:31 +08:00
1 parent d205f47a8f
commit 0894334764
8 files changed
+157 -8

No files matched your search

@@ -8,6 +8,7 @@ pub enum TablePaginationStrategy {
SqlServerTop,
IrisTop,
InformixFirst,
FirebirdRows,
Rownum,
QuestDbLimit,
Unbounded,
@@ -84,6 +85,7 @@ pub fn pagination_strategy(database_type: Option<DatabaseType>, context: Paginat
Some(DatabaseType::SqlServer) => TablePaginationStrategy::SqlServerTop,
Some(DatabaseType::Iris) => TablePaginationStrategy::IrisTop,
Some(DatabaseType::Informix) => TablePaginationStrategy::InformixFirst,
Some(DatabaseType::Firebird) => TablePaginationStrategy::FirebirdRows,
Some(DatabaseType::OceanbaseOracle) => TablePaginationStrategy::Rownum,
Some(DatabaseType::Questdb) => TablePaginationStrategy::QuestDbLimit,
_ => TablePaginationStrategy::LimitOffset,
@@ -102,3 +104,13 @@ pub(super) fn is_simple_informix_identifier(name: &str) -> bool {
(first.is_ascii_alphabetic() || first == '_')
&& chars.all(|ch| ch.is_ascii_alphanumeric() || ch == '_' || ch == '$')
}
pub fn firebird_rows_clause(limit: usize, offset: usize) -> String {
if offset > 0 {
let start = offset + 1;
let end = offset + limit;
format!("ROWS {start} TO {end}")
} else {
format!("ROWS {limit}")
}
}
@@ -1,6 +1,6 @@
use crate::models::connection::DatabaseType;
use super::capabilities::{table_pagination_strategy, uses_fetch_first, TablePaginationStrategy};
use super::capabilities::{firebird_rows_clause, table_pagination_strategy, uses_fetch_first, TablePaginationStrategy};
use super::identifiers::{normalize_where_input, qualified_table_name, quote_table_identifier};
use super::types::{
TableDataSelectSqlOptions, TableSelectSqlOptions, DBX_NEO4J_ELEMENT_ID_COLUMN, DBX_ROWID_COLUMN,
@@ -63,6 +63,10 @@ pub fn build_table_data_select_sql(options: TableDataSelectSqlOptions) -> String
let row_limit = informix_row_limit_clause(limit, options.offset.unwrap_or(0));
format!("SELECT {row_limit} {select_columns} FROM {table_alias}{where_clause}{order}")
}
TablePaginationStrategy::FirebirdRows => {
let rows = firebird_rows_clause(limit, options.offset.unwrap_or(0));
format!("SELECT {select_columns} FROM {table_alias}{where_clause}{order} {rows}")
}
TablePaginationStrategy::Db2FetchFirst if options.offset.is_some_and(|offset| offset > 0) => {
build_db2_table_select_page_sql(
&table_alias,
@@ -156,6 +160,10 @@ pub fn build_table_select_sql(options: TableSelectSqlOptions<'_>) -> String {
TablePaginationStrategy::InformixFirst => {
format!("SELECT FIRST {limit} {select_columns} FROM {table}{order_by}")
}
TablePaginationStrategy::FirebirdRows => {
let rows = firebird_rows_clause(limit, 0);
format!("SELECT {select_columns} FROM {table}{order_by} {rows}")
}
TablePaginationStrategy::Rownum => {
build_rownum_table_select_sql(&table, "", &order_by, &select_columns, &select_columns, limit, 0)
}
+29
View File
@@ -62,6 +62,7 @@ fn maps_table_pagination_strategy_by_database_type() {
assert_eq!(table_pagination_strategy(Some(DatabaseType::SqlServer)), TablePaginationStrategy::SqlServerTop);
assert_eq!(table_pagination_strategy(Some(DatabaseType::Iris)), TablePaginationStrategy::IrisTop);
assert_eq!(table_pagination_strategy(Some(DatabaseType::Informix)), TablePaginationStrategy::InformixFirst);
assert_eq!(table_pagination_strategy(Some(DatabaseType::Firebird)), TablePaginationStrategy::FirebirdRows);
assert_eq!(table_pagination_strategy(Some(DatabaseType::OceanbaseOracle)), TablePaginationStrategy::Rownum);
assert_eq!(table_pagination_strategy(Some(DatabaseType::Questdb)), TablePaginationStrategy::QuestDbLimit);
assert_eq!(table_pagination_strategy(Some(DatabaseType::Oracle)), TablePaginationStrategy::Rownum);
@@ -124,6 +125,17 @@ fn builds_select_sql_with_limit_syntax_for_database_type() {
}),
"SELECT \"id\", \"name\" FROM \"DB2INST1\".\"USERS\" ORDER BY \"id\" ASC FETCH FIRST 100 ROWS ONLY"
);
assert_eq!(
build_table_select_sql(TableSelectSqlOptions {
database_type: Some(DatabaseType::Firebird),
schema: None,
table_name: "USERS",
columns: &columns,
order_columns: &keys,
limit: 100,
}),
"SELECT \"id\", \"name\" FROM \"USERS\" ORDER BY \"id\" ASC ROWS 100"
);
assert_eq!(
build_table_select_sql(TableSelectSqlOptions {
database_type: Some(DatabaseType::Oracle),
@@ -331,6 +343,23 @@ fn builds_table_data_where_and_schema_queries() {
}),
"SELECT * FROM \"DB2INST1\".\"ORDERS\" WHERE (amount > 10) FETCH FIRST 50 ROWS ONLY"
);
assert_eq!(
build_table_data_select_sql(TableDataSelectSqlOptions {
database_type: Some(DatabaseType::Firebird),
schema: None,
table_name: "ORDERS".to_string(),
table_type: None,
primary_keys: vec!["ID".to_string()],
columns: vec!["ID".to_string(), "AMOUNT".to_string()],
fallback_order_columns: Vec::new(),
order_by: Some("\"ID\" ASC".to_string()),
limit: Some(50),
offset: Some(100),
where_input: Some("WHERE amount > 10".to_string()),
include_row_id: false,
}),
"SELECT * FROM \"ORDERS\" WHERE (amount > 10) ORDER BY \"ID\" ASC ROWS 101 TO 150"
);
assert_eq!(
build_table_data_select_sql(TableDataSelectSqlOptions {
database_type: Some(DatabaseType::Oracle),