fix(oracle): serialize RAW values with HEXTORAW

This commit is contained in:
t8y2 2026-07-31 00:47:23 +08:00
parent 1e7b3f3dec
commit 5ad5b4fcc3
No known key found for this signature in database
1 changed files with 68 additions and 0 deletions

View File

@ -1787,6 +1787,11 @@ pub fn format_grid_sql_literal(
return literal;
}
}
if is_oracle_raw_literal_column(database_type, column_info) {
if let Some(literal) = format_oracle_raw_literal_text(&text) {
return literal;
}
}
if column_info.map(|column| is_numeric_type(&column.data_type)).unwrap_or(false) && is_numeric_literal(&text) {
// BigDecimal/BigInteger cells cross JSON-RPC as strings so browsers cannot round them.
return text;
@ -2082,6 +2087,24 @@ fn format_mysql_binary_literal_text(text: &str) -> Option<String> {
}
}
fn is_oracle_raw_literal_column(database_type: Option<DatabaseType>, column_info: Option<&DataGridColumnInfo>) -> bool {
is_oracle_temporal_literal_database(database_type)
&& column_info.map(|column| is_oracle_raw_column_type(&column.data_type)).unwrap_or(false)
}
fn is_oracle_raw_column_type(data_type: &str) -> bool {
data_type.trim().split(['(', ':', ' ']).next().is_some_and(|base| base.eq_ignore_ascii_case("raw"))
}
fn format_oracle_raw_literal_text(text: &str) -> Option<String> {
let hex = text.strip_prefix("0x")?;
if hex.len() % 2 == 0 && hex.chars().all(|ch| ch.is_ascii_hexdigit()) {
Some(format!("HEXTORAW('{hex}')"))
} else {
None
}
}
fn is_geometry_column_type(data_type: &str) -> bool {
let lower = data_type.to_ascii_lowercase();
let base = lower.split('(').next().unwrap_or(&lower).trim();
@ -4749,6 +4772,51 @@ mod tests {
);
}
#[test]
fn prepares_oracle_raw_update_with_hex_literals() {
let result = prepare_data_grid_save(DataGridSaveStatementOptions {
database_type: Some(DatabaseType::Oracle),
identifier_quote: None,
table_meta: DataGridTableMeta {
catalog: None,
database: None,
schema: Some("APP".to_string()),
table_name: "RAW_VALUES".to_string(),
primary_keys: vec!["ID".to_string()],
columns: Some(vec![column("ID", "RAW(16)", false, None), column("PAYLOAD", "RAW(16)", true, None)]),
},
columns: vec!["ID".to_string(), "PAYLOAD".to_string()],
source_columns: None,
rows: vec![vec![json!("0x00112233445566778899aabbccddeeff"), json!("0xaabb")]],
dirty_rows: vec![(0, vec![(1, json!("0xccdd"))])],
deleted_rows: vec![],
new_rows: vec![],
});
assert_eq!(result.validation_error, None);
assert_eq!(
result.statements,
vec![
"UPDATE \"APP\".\"RAW_VALUES\" SET \"PAYLOAD\" = HEXTORAW('ccdd') WHERE \"ID\" = HEXTORAW('00112233445566778899aabbccddeeff');"
]
);
}
#[test]
fn oracle_raw_literals_require_valid_even_length_hex() {
let raw = column("ID", "RAW(16)", false, None);
let text = column("ID", "VARCHAR2(64)", false, None);
let blob = column("ID", "BLOB", false, None);
for database_type in [DatabaseType::Oracle, DatabaseType::OceanbaseOracle] {
assert_eq!(format_grid_sql_literal(&json!("0x00aB"), Some(database_type), Some(&raw)), "HEXTORAW('00aB')");
assert_eq!(format_grid_sql_literal(&json!("0xabc"), Some(database_type), Some(&raw)), "'0xabc'");
assert_eq!(format_grid_sql_literal(&json!("0x00gg"), Some(database_type), Some(&raw)), "'0x00gg'");
assert_eq!(format_grid_sql_literal(&json!("0x00ab"), Some(database_type), Some(&text)), "'0x00ab'");
assert_eq!(format_grid_sql_literal(&json!("0x00ab"), Some(database_type), Some(&blob)), "'0x00ab'");
}
}
#[test]
fn prepares_oceanbase_oracle_lob_deletes_with_synthetic_rowid() {
let result = prepare_data_grid_save(DataGridSaveStatementOptions {