use crate::models::connection::DatabaseType; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TablePaginationStrategy { LimitOffset, FetchFirst, Db2FetchFirst, SqlServerTop, IrisTop, InformixFirst, FirebirdRows, Rownum, QuestDbLimit, Unbounded, AgentMaxRows, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PaginationContext { TablePreview, BoundedRead, UserQuery, } pub fn is_schema_aware(database_type: DatabaseType) -> bool { matches!( database_type, DatabaseType::Postgres | DatabaseType::SqlServer | DatabaseType::Oracle | DatabaseType::Redshift | DatabaseType::Dameng | DatabaseType::Gaussdb | DatabaseType::Kwdb | DatabaseType::Kingbase | DatabaseType::Highgo | DatabaseType::Uxdb | DatabaseType::Vastbase | DatabaseType::Yashandb | DatabaseType::Oscar | DatabaseType::Databricks | DatabaseType::SapHana | DatabaseType::Teradata | DatabaseType::Vertica | DatabaseType::Exasol | DatabaseType::OpenGauss | DatabaseType::OceanbaseOracle | DatabaseType::Gbase | DatabaseType::Databend | DatabaseType::Jdbc | DatabaseType::H2 | DatabaseType::Snowflake | DatabaseType::Trino | DatabaseType::PrestoSql | DatabaseType::Hive | DatabaseType::Kyuubi | DatabaseType::Impala | DatabaseType::Argo | DatabaseType::Spark | DatabaseType::Db2 | DatabaseType::Informix | DatabaseType::Tdengine | DatabaseType::Xugu | DatabaseType::Sqlite | DatabaseType::DuckDb | DatabaseType::Iris // Spanner supports named schemas; the PostgreSQL dialect defaults to `public`. // GoogleSQL's default schema is the empty string, which the blank-schema filters // in `qualified_table_name` / `table_data_qualified_table_name` drop along with // the dot separator (`` `s`.`t` `` with an empty `s` is a Spanner syntax error). | DatabaseType::Spanner ) } pub fn uses_fetch_first(database_type: DatabaseType) -> bool { matches!(database_type, DatabaseType::Oracle | DatabaseType::Dameng | DatabaseType::Db2) } pub fn uses_oracle_row_id(database_type: Option) -> bool { matches!(database_type, Some(DatabaseType::Oracle | DatabaseType::OceanbaseOracle)) } /// Xugu exposes an unqualified ROWID pseudo-column for base, partitioned and /// temporary tables. It is intentionally separate from Oracle's ROWIDTOCHAR /// representation because qualified ROWID and ROWIDTOCHAR are not supported /// by Xugu. pub fn uses_xugu_row_id(database_type: Option) -> bool { database_type == Some(DatabaseType::Xugu) } pub fn uses_synthetic_row_id(database_type: Option) -> bool { uses_oracle_row_id(database_type) || uses_xugu_row_id(database_type) } /// Oracle 系方言不支持 `INSERT ... VALUES (...), (...)` 多行语法, /// 复制为 INSERT 与导出 INSERT 都需按行生成单条语句。 pub fn uses_single_row_insert_statements(database_type: DatabaseType) -> bool { matches!(database_type, DatabaseType::Oracle | DatabaseType::OceanbaseOracle) } pub fn pagination_strategy(database_type: Option, context: PaginationContext) -> TablePaginationStrategy { match database_type { Some(DatabaseType::Jdbc) => TablePaginationStrategy::AgentMaxRows, Some(DatabaseType::Oracle) if matches!(context, PaginationContext::TablePreview) => { TablePaginationStrategy::Rownum } // Oracle's row-limiting clause (`FETCH FIRST`/`OFFSET ... FETCH`) was // introduced in 12c. ROWNUM remains compatible with the supported 11g // baseline while still providing a bounded read for newer servers. Some(DatabaseType::Oracle) if matches!(context, PaginationContext::BoundedRead) => { TablePaginationStrategy::Rownum } Some(DatabaseType::Oracle) => TablePaginationStrategy::Unbounded, Some(DatabaseType::Oscar) if matches!(context, PaginationContext::TablePreview | PaginationContext::BoundedRead) => { TablePaginationStrategy::Rownum } Some(DatabaseType::Oscar) => TablePaginationStrategy::Unbounded, Some(DatabaseType::Dameng) => TablePaginationStrategy::Rownum, Some(DatabaseType::Db2) => TablePaginationStrategy::Db2FetchFirst, 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, } } pub fn table_pagination_strategy(database_type: Option) -> TablePaginationStrategy { pagination_strategy(database_type, PaginationContext::TablePreview) } pub(super) fn is_simple_informix_identifier(name: &str) -> bool { let mut chars = name.chars(); let Some(first) = chars.next() else { return false; }; (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}") } }