fix(oracle): emit DEFAULT before NOT NULL in create-table columns
This commit is contained in:
1 parent
ff874e8af9
commit
a782039e1f
2 files changed
+61
-3
No files matched your search
@@ -110,6 +110,19 @@ pub fn build_create_table_sql(mut options: TableStructureSqlOptions) -> TableStr
|
||||
parts.push(format!("COLLATE {}", quote_ident(dialect, &column.collation)));
|
||||
}
|
||||
}
|
||||
// Oracle's column grammar is `col type [DEFAULT expr] [inline constraint ...]`, so the
|
||||
// DEFAULT clause has to precede NOT NULL. Emitting `NOT NULL DEFAULT ...` leaves the
|
||||
// parser looking for the closing parenthesis of the column list and fails with
|
||||
// ORA-00907 (t8y2/dbx#9477). Scoped to Oracle: every other engine keeps the historical
|
||||
// NOT NULL-then-DEFAULT order.
|
||||
let default_value = normalize_default(Some(&column.default_value));
|
||||
let default_clause = (!default_value.is_empty() && dialect != StructureDialect::ManticoreSearch)
|
||||
.then(|| format!("DEFAULT {}", format_default_for_sql(dialect, &column.data_type, &default_value)));
|
||||
if dialect == StructureDialect::Oracle {
|
||||
if let Some(clause) = default_clause.clone() {
|
||||
parts.push(clause);
|
||||
}
|
||||
}
|
||||
if dialect == StructureDialect::Sqlite
|
||||
&& column.is_primary_key
|
||||
&& column.extra.as_ref().is_some_and(|e| e.auto_increment.unwrap_or(false))
|
||||
@@ -130,9 +143,10 @@ pub fn build_create_table_sql(mut options: TableStructureSqlOptions) -> TableStr
|
||||
if let Some(extra_clause) = column_extra_clause(dialect, column) {
|
||||
parts.push(extra_clause);
|
||||
}
|
||||
let default_value = normalize_default(Some(&column.default_value));
|
||||
if !default_value.is_empty() && dialect != StructureDialect::ManticoreSearch {
|
||||
parts.push(format!("DEFAULT {}", format_default_for_sql(dialect, &column.data_type, &default_value)));
|
||||
if dialect != StructureDialect::Oracle {
|
||||
if let Some(clause) = default_clause {
|
||||
parts.push(clause);
|
||||
}
|
||||
}
|
||||
if let Some(on_update) = column.extra.as_ref().and_then(|e| e.on_update_current_timestamp).filter(|v| *v) {
|
||||
if on_update && dialect == StructureDialect::Mysql {
|
||||
|
||||
@@ -1207,6 +1207,50 @@ fn oracle_timestamp_default_precedes_nullability_in_modify_sql() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oracle_create_table_places_default_before_not_null() {
|
||||
// Oracle's column grammar is `col type [DEFAULT expr] [NOT NULL]`. Cloning a table whose
|
||||
// NOT NULL column carries a default used to emit `NOT NULL DEFAULT ...`, which the server
|
||||
// rejects with ORA-00907 (t8y2/dbx#9477).
|
||||
let mut id = column("ID");
|
||||
id.data_type = "NUMBER(10)".to_string();
|
||||
id.is_primary_key = true;
|
||||
let mut status = column("STATUS");
|
||||
status.data_type = "VARCHAR2(1 BYTE)".to_string();
|
||||
status.is_nullable = false;
|
||||
status.default_value = "'A'".to_string();
|
||||
let mut created_at = column("CREATED_AT");
|
||||
created_at.data_type = "DATE".to_string();
|
||||
created_at.is_nullable = false;
|
||||
created_at.default_value = "SYSDATE".to_string();
|
||||
|
||||
let result = build_create_table_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::Oracle),
|
||||
driver_profile: None,
|
||||
schema: Some("APP".to_string()),
|
||||
table_name: "ORDERS_COPY".to_string(),
|
||||
columns: vec![id, status, created_at],
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: Vec::new(),
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
mysql_engine: None,
|
||||
partitioned: false,
|
||||
is_gaussdb_m_mode: false,
|
||||
table_collation: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert!(
|
||||
result.statements[0].contains("\"STATUS\" VARCHAR2(1 BYTE) DEFAULT 'A' NOT NULL"),
|
||||
"ddl: {}",
|
||||
result.statements[0]
|
||||
);
|
||||
assert!(result.statements[0].contains("CREATED_AT DATE DEFAULT SYSDATE NOT NULL"), "ddl: {}", result.statements[0]);
|
||||
assert!(!result.statements[0].contains("NOT NULL DEFAULT"), "ddl: {}", result.statements[0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oracle_create_table_preserves_character_length_units() {
|
||||
let mut byte_col = column("BYTE_COL");
|
||||
|
||||
Reference in new issue
Block a user