10 files changed
+745
-65
No files matched your search
@@ -245,7 +245,21 @@ pub(super) fn capabilities_for(database_type: Option<DatabaseType>) -> TableStru
|
||||
index_type: true,
|
||||
..base
|
||||
},
|
||||
Some(DatabaseType::Oracle | DatabaseType::OceanbaseOracle | DatabaseType::Yashandb | DatabaseType::Xugu) => {
|
||||
Some(DatabaseType::Oracle) => TableStructureCapabilities {
|
||||
dialect: StructureDialect::Oracle,
|
||||
add_column: true,
|
||||
drop_column: true,
|
||||
rename_column: true,
|
||||
alter_existing_column: true,
|
||||
comment: true,
|
||||
create_index: true,
|
||||
drop_index: true,
|
||||
rebuild_index: true,
|
||||
index_type: true,
|
||||
foreign_key: true,
|
||||
..base
|
||||
},
|
||||
Some(DatabaseType::OceanbaseOracle | DatabaseType::Yashandb | DatabaseType::Xugu) => {
|
||||
TableStructureCapabilities {
|
||||
dialect: StructureDialect::Oracle,
|
||||
add_column: true,
|
||||
|
||||
@@ -79,7 +79,9 @@ fn has_foreign_key_change(foreign_key: &EditableStructureForeignKey, original: &
|
||||
fn drop_foreign_key_sql(dialect: StructureDialect, table: &str, name: &str) -> String {
|
||||
match dialect {
|
||||
StructureDialect::Mysql => format!("ALTER TABLE {table} DROP FOREIGN KEY {};", quote_ident(dialect, name)),
|
||||
StructureDialect::Postgres => format!("ALTER TABLE {table} DROP CONSTRAINT {};", quote_ident(dialect, name)),
|
||||
StructureDialect::Postgres | StructureDialect::Oracle => {
|
||||
format!("ALTER TABLE {table} DROP CONSTRAINT {};", quote_ident(dialect, name))
|
||||
}
|
||||
_ => unreachable!("foreign key SQL requested for unsupported dialect"),
|
||||
}
|
||||
}
|
||||
@@ -117,11 +119,11 @@ fn create_foreign_key_sql(
|
||||
);
|
||||
sql.push(')');
|
||||
|
||||
if let Some(action) = action_clause("ON DELETE", &foreign_key.on_delete, warnings) {
|
||||
if let Some(action) = action_clause(dialect, "ON DELETE", &foreign_key.on_delete, warnings) {
|
||||
sql.push(' ');
|
||||
sql.push_str(&action);
|
||||
}
|
||||
if let Some(action) = action_clause("ON UPDATE", &foreign_key.on_update, warnings) {
|
||||
if let Some(action) = action_clause(dialect, "ON UPDATE", &foreign_key.on_update, warnings) {
|
||||
sql.push(' ');
|
||||
sql.push_str(&action);
|
||||
}
|
||||
@@ -129,11 +131,27 @@ fn create_foreign_key_sql(
|
||||
Some(sql)
|
||||
}
|
||||
|
||||
fn action_clause(prefix: &str, value: &str, warnings: &mut Vec<String>) -> Option<String> {
|
||||
fn action_clause(dialect: StructureDialect, prefix: &str, value: &str, warnings: &mut Vec<String>) -> Option<String> {
|
||||
let action = normalize_action(value);
|
||||
if action.is_empty() {
|
||||
return None;
|
||||
}
|
||||
if dialect == StructureDialect::Oracle {
|
||||
if prefix == "ON UPDATE" {
|
||||
if action != "NO ACTION" {
|
||||
warnings.push(format!("Oracle does not support {prefix} {action}."));
|
||||
}
|
||||
return None;
|
||||
}
|
||||
return match action.as_str() {
|
||||
"CASCADE" | "SET NULL" => Some(format!("{prefix} {action}")),
|
||||
"NO ACTION" => None,
|
||||
_ => {
|
||||
warnings.push(format!("Unsupported Oracle foreign key action \"{}\".", clean(value)));
|
||||
None
|
||||
}
|
||||
};
|
||||
}
|
||||
match action.as_str() {
|
||||
"CASCADE" | "SET NULL" | "RESTRICT" | "NO ACTION" => Some(format!("{prefix} {action}")),
|
||||
_ => {
|
||||
|
||||
@@ -3526,6 +3526,71 @@ fn builds_mysql_composite_foreign_key() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_oracle_foreign_key_with_supported_actions() {
|
||||
let mut customer_id = column("CUSTOMER_ID");
|
||||
customer_id.data_type = "NUMBER(19)".to_string();
|
||||
let mut customer_fk = foreign_key("ORDERS_COPY_FK1", "CUSTOMER_ID", "CUSTOMERS", "ID");
|
||||
customer_fk.ref_schema = "CRM".to_string();
|
||||
customer_fk.on_update = "NO ACTION".to_string();
|
||||
customer_fk.on_delete = "CASCADE".to_string();
|
||||
|
||||
let result = build_create_table_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::Oracle),
|
||||
schema: Some("HR".to_string()),
|
||||
table_name: "ORDERS_COPY".to_string(),
|
||||
columns: vec![customer_id],
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: vec![customer_fk],
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.statements[1],
|
||||
"ALTER TABLE \"HR\".\"ORDERS_COPY\" ADD CONSTRAINT \"ORDERS_COPY_FK1\" FOREIGN KEY (\"CUSTOMER_ID\") REFERENCES \"CRM\".\"CUSTOMERS\" (\"ID\") ON DELETE CASCADE;"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_oracle_foreign_key_replacement() {
|
||||
let mut customer_fk = foreign_key("ORDERS_FK1", "CUSTOMER_ID", "CUSTOMERS", "ID");
|
||||
customer_fk.on_delete = "SET NULL".to_string();
|
||||
customer_fk.original = Some(ForeignKeyInfo {
|
||||
name: "ORDERS_FK_OLD".to_string(),
|
||||
column: "CUSTOMER_ID".to_string(),
|
||||
ref_schema: Some("CRM".to_string()),
|
||||
ref_table: "CUSTOMERS".to_string(),
|
||||
ref_column: "ID".to_string(),
|
||||
on_update: None,
|
||||
on_delete: Some("NO ACTION".to_string()),
|
||||
});
|
||||
customer_fk.ref_schema = "CRM".to_string();
|
||||
|
||||
let result = build_table_structure_change_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::Oracle),
|
||||
schema: Some("HR".to_string()),
|
||||
table_name: "ORDERS".to_string(),
|
||||
columns: Vec::new(),
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: vec![customer_fk],
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.statements,
|
||||
vec![
|
||||
"ALTER TABLE \"HR\".\"ORDERS\" DROP CONSTRAINT \"ORDERS_FK_OLD\";",
|
||||
"ALTER TABLE \"HR\".\"ORDERS\" ADD CONSTRAINT \"ORDERS_FK1\" FOREIGN KEY (\"CUSTOMER_ID\") REFERENCES \"CRM\".\"CUSTOMERS\" (\"ID\") ON DELETE SET NULL;",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_mysql_trigger_changes() {
|
||||
let mut existing = trigger("orders_bu", "BEFORE", "UPDATE", "BEGIN\n SET NEW.updated_at = NOW();\nEND");
|
||||
|
||||
Reference in new issue
Block a user