fix(xugu): enable safe row editing without primary keys

This commit is contained in:
Elias authored and GitHub committed 2026-09-07 22:44:30 +08:00
1 parent 39b2d2a6ac
commit 3e75be87eb
17 files changed
+236 -50

No files matched your search

@@ -80,6 +80,18 @@ pub fn uses_oracle_row_id(database_type: Option<DatabaseType>) -> 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<DatabaseType>) -> bool {
database_type == Some(DatabaseType::Xugu)
}
pub fn uses_synthetic_row_id(database_type: Option<DatabaseType>) -> 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 {
@@ -1,7 +1,7 @@
use crate::models::connection::DatabaseType;
use super::capabilities::{
firebird_rows_clause, table_pagination_strategy, uses_oracle_row_id, TablePaginationStrategy,
firebird_rows_clause, table_pagination_strategy, uses_oracle_row_id, uses_xugu_row_id, TablePaginationStrategy,
};
use super::identifiers::{
normalize_where_input, qualified_table_name, qualified_table_name_with_catalog, quote_gaussdb_jdbc_identifier,
@@ -272,6 +272,8 @@ pub fn build_table_data_select_sql_with_database(
let include_oracle_row_id = options.include_row_id
&& uses_oracle_row_id(database_type)
&& !is_view_table_type(options.table_type.as_deref());
let include_xugu_row_id =
options.include_row_id && uses_xugu_row_id(database_type) && !is_view_table_type(options.table_type.as_deref());
let offset = options.offset.unwrap_or(0);
let oracle_view_first_page =
database_type == Some(DatabaseType::Oracle) && is_view_table_type(options.table_type.as_deref()) && offset == 0;
@@ -280,6 +282,15 @@ pub fn build_table_data_select_sql_with_database(
format!("ROWIDTOCHAR(t.ROWID) AS \"{DBX_ROWID_COLUMN}\", t.*")
} else if let Some(preview_columns) = build_large_value_preview_columns(&options) {
preview_columns
} else if include_xugu_row_id {
if options.columns.is_empty() {
format!("ROWID AS \"{DBX_ROWID_COLUMN}\", *")
} else {
format!(
"ROWID AS \"{DBX_ROWID_COLUMN}\", {}",
quoted_table_columns_or_star(database_type, &options.columns)
)
}
} else {
build_select_columns(
database_type,
+54
View File
@@ -1326,6 +1326,60 @@ fn builds_oracle_and_neo4j_table_data_queries() {
}),
"SELECT \"__DBX_ROWID\", \"ID\", \"SMC_RESPONSE\" FROM (SELECT ROWIDTOCHAR(t.ROWID) AS \"__DBX_ROWID\", t.* FROM \"APP\".\"DATA_REPORT_SUB_TASK\" t) WHERE ROWNUM <= 100"
);
assert_eq!(
build_table_data_select_sql(TableDataSelectSqlOptions {
database_type: Some(DatabaseType::Xugu),
schema: Some("DBXTEST".to_string()),
table_name: "DBX_LOAD_TABLE_006".to_string(),
table_type: Some("PARTITIONED TABLE".to_string()),
primary_keys: vec![DBX_ROWID_COLUMN.to_string()],
columns: Vec::new(),
fallback_order_columns: Vec::new(),
order_by: None,
limit: Some(100),
offset: None,
where_input: None,
include_row_id: true,
..Default::default()
}),
"SELECT ROWID AS \"__DBX_ROWID\", * FROM \"DBXTEST\".\"DBX_LOAD_TABLE_006\" LIMIT 100;"
);
assert_eq!(
build_table_data_select_sql(TableDataSelectSqlOptions {
database_type: Some(DatabaseType::Xugu),
schema: Some("DBXTEST".to_string()),
table_name: "DBX_LOAD_TABLE_006".to_string(),
table_type: Some("TEMPORARY TABLE".to_string()),
primary_keys: vec![DBX_ROWID_COLUMN.to_string()],
columns: vec!["ID".to_string(), "NAME".to_string()],
fallback_order_columns: Vec::new(),
order_by: None,
limit: Some(25),
offset: Some(10),
where_input: None,
include_row_id: true,
..Default::default()
}),
"SELECT ROWID AS \"__DBX_ROWID\", \"ID\", \"NAME\" FROM \"DBXTEST\".\"DBX_LOAD_TABLE_006\" LIMIT 25 OFFSET 10;"
);
assert_eq!(
build_table_data_select_sql(TableDataSelectSqlOptions {
database_type: Some(DatabaseType::Xugu),
schema: Some("DBXTEST".to_string()),
table_name: "DBX_JOIN_VIEW".to_string(),
table_type: Some("VIEW".to_string()),
primary_keys: vec![DBX_ROWID_COLUMN.to_string()],
columns: vec!["ID".to_string(), "NAME".to_string()],
fallback_order_columns: Vec::new(),
order_by: None,
limit: Some(100),
offset: None,
where_input: None,
include_row_id: true,
..Default::default()
}),
"SELECT * FROM \"DBXTEST\".\"DBX_JOIN_VIEW\" LIMIT 100;"
);
assert_eq!(
build_table_data_select_sql(TableDataSelectSqlOptions {
database_type: Some(DatabaseType::Oracle),