mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-20 00:17:44 +00:00
@@ -11096,6 +11096,69 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn oracle_jdbc_import_maps_xls_rows_to_insert_all() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let storage = Storage::open(&dir.path().join("storage.db")).await.unwrap();
|
||||
let state = AppState::new(storage);
|
||||
let connection_id = "oracle-jdbc-import";
|
||||
let config: ConnectionConfig = serde_json::from_value(serde_json::json!({
|
||||
"id": connection_id,
|
||||
"name": "Oracle over JDBC",
|
||||
"db_type": "jdbc",
|
||||
"host": "",
|
||||
"port": 0,
|
||||
"username": "",
|
||||
"password": "",
|
||||
"connection_string": "jdbc:oracle:thin:@localhost:1521:ORCL",
|
||||
"jdbc_driver_class": "oracle.jdbc.driver.OracleDriver"
|
||||
}))
|
||||
.unwrap();
|
||||
state.configs.write().await.insert(connection_id.to_string(), config);
|
||||
|
||||
let db_type = crate::transfer::get_db_type(&state, connection_id).await.unwrap();
|
||||
assert_eq!(db_type, DatabaseType::Oracle);
|
||||
|
||||
let mappings = vec![
|
||||
TableImportColumnMapping {
|
||||
source_column: "id".to_string(),
|
||||
target_column: "id".to_string(),
|
||||
target_data_type: None,
|
||||
},
|
||||
TableImportColumnMapping {
|
||||
source_column: "name".to_string(),
|
||||
target_column: "name".to_string(),
|
||||
target_data_type: None,
|
||||
},
|
||||
];
|
||||
let data = ParsedImportFile {
|
||||
columns: vec!["id".to_string(), "name".to_string()],
|
||||
rows: vec![
|
||||
vec![serde_json::json!(1), serde_json::json!("Ada")],
|
||||
vec![serde_json::json!(2), serde_json::json!("Grace")],
|
||||
],
|
||||
total_rows: 2,
|
||||
effective_encoding: None,
|
||||
};
|
||||
|
||||
let batches = build_import_insert_batches(
|
||||
&data,
|
||||
&mappings,
|
||||
&[("id".to_string(), "NUMBER".to_string()), ("name".to_string(), "VARCHAR2(64)".to_string())],
|
||||
"events",
|
||||
"APP",
|
||||
&db_type,
|
||||
500,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(batches.len(), 1);
|
||||
assert_eq!(batches[0].row_count, 2);
|
||||
assert!(batches[0].sql.starts_with("INSERT ALL\nINTO "));
|
||||
assert!(batches[0].sql.ends_with("SELECT 1 FROM dual"));
|
||||
assert!(!batches[0].sql.contains("),\n("));
|
||||
}
|
||||
|
||||
fn kingbase_date_import_sql(oracle_mode: bool) -> String {
|
||||
let mappings = vec![TableImportColumnMapping {
|
||||
source_column: "created_at".to_string(),
|
||||
|
||||
@@ -5349,6 +5349,16 @@ fn effective_transfer_database_type(config: &ConnectionConfig) -> DatabaseType {
|
||||
return DatabaseType::Jdbc;
|
||||
}
|
||||
|
||||
// Oracle behind a generic JDBC connection: Oracle rejects MySQL-style
|
||||
// multi-row VALUES lists with ORA-00933, so reuse the native Oracle
|
||||
// transfer dialect (INSERT ALL, TO_DATE literals, row-capped batches).
|
||||
let is_oracle =
|
||||
config.connection_string.as_deref().is_some_and(|url| url.to_ascii_lowercase().contains("jdbc:oracle:"))
|
||||
|| config.jdbc_driver_class.as_deref().is_some_and(|class| class.to_ascii_lowercase().contains("oracle"));
|
||||
if is_oracle {
|
||||
return DatabaseType::Oracle;
|
||||
}
|
||||
|
||||
let jdbc_identity = [
|
||||
config.driver_profile.as_deref().unwrap_or(""),
|
||||
config.connection_string.as_deref().unwrap_or(""),
|
||||
@@ -12896,6 +12906,56 @@ SELECT 1 FROM dual"#
|
||||
assert!(statements[0].ends_with("SELECT 1 FROM dual"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oracle_jdbc_url_routes_multi_row_insert_through_insert_all() {
|
||||
let config =
|
||||
jdbc_transfer_config("jdbc:oracle:thin:@localhost:1521:ORCL", "oracle.jdbc.driver.OracleDriver", "");
|
||||
assert_eq!(effective_transfer_database_type(&config), DatabaseType::Oracle);
|
||||
// Mixed-case URL and driver class alone must be recognized too.
|
||||
assert_eq!(
|
||||
effective_transfer_database_type(&jdbc_transfer_config("JDBC:Oracle:thin:@localhost:1521:ORCL", "", "")),
|
||||
DatabaseType::Oracle
|
||||
);
|
||||
assert_eq!(
|
||||
effective_transfer_database_type(&jdbc_transfer_config("", "oracle.jdbc.OracleDriver", "")),
|
||||
DatabaseType::Oracle
|
||||
);
|
||||
|
||||
let sql = generate_insert_typed(
|
||||
&[String::from("id"), String::from("name")],
|
||||
&[Some(String::from("number")), Some(String::from("varchar2(64)"))],
|
||||
&[vec![json!(1), json!("Ada")], vec![json!(2), json!("Grace")]],
|
||||
"INSTR_CATEGORY",
|
||||
"APP",
|
||||
&effective_transfer_database_type(&config),
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(sql.starts_with("INSERT ALL\nINTO "));
|
||||
assert!(sql.ends_with("SELECT 1 FROM dual"));
|
||||
assert!(!sql.contains("),\n("));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_oracle_jdbc_url_keeps_multi_row_values_insert() {
|
||||
let config = jdbc_transfer_config("jdbc:mysql://localhost:3306/dbx_test", "com.mysql.cj.jdbc.Driver", "");
|
||||
assert_eq!(effective_transfer_database_type(&config), DatabaseType::Jdbc);
|
||||
|
||||
let sql = generate_insert_typed(
|
||||
&[String::from("id"), String::from("name")],
|
||||
&[Some(String::from("int")), Some(String::from("varchar(64)"))],
|
||||
&[vec![json!(1), json!("Ada")], vec![json!(2), json!("Grace")]],
|
||||
"instr_category",
|
||||
"",
|
||||
&effective_transfer_database_type(&config),
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(sql.starts_with("INSERT INTO "));
|
||||
assert!(sql.contains("),\n("));
|
||||
assert!(!sql.contains("INSERT ALL"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer_write_sql_batches_split_large_insert_statements() {
|
||||
let rows = (0..4).map(|index| vec![json!(index), json!("x".repeat(180 * 1024))]).collect::<Vec<_>>();
|
||||
|
||||
Reference in New Issue
Block a user