Fix: 修复 SQL Server 修改默认值时报错 (#2190)
* Fix SQL Server default constraint DDL * Polish SQL Server default display --------- Co-authored-by: staff <staff@qimaos-MacBook-Pro.local>
This commit is contained in:
1 parent
25dcbeb7e4
commit
73a996ebe6
5 files changed
+288
-7
No files matched your search
@@ -444,12 +444,13 @@ pub(super) fn build_sqlserver_existing_column_sql(
|
||||
.unwrap_or(false);
|
||||
|
||||
if has_old_default {
|
||||
let sql_var = sqlserver_default_constraint_sql_var(table, ¤t_name);
|
||||
statements.push(format!(
|
||||
"DECLARE @sql NVARCHAR(MAX);\
|
||||
SELECT @sql = 'ALTER TABLE {table} DROP CONSTRAINT [' + name + ']'\
|
||||
FROM sys.default_constraints\
|
||||
WHERE parent_object_id = OBJECT_ID('{table}') AND parent_column_id = COLUMNPROPERTY(OBJECT_ID('{table}'), '{col_name}', 'ColumnId');\
|
||||
EXEC sp_executesql @sql;",
|
||||
"DECLARE {sql_var} NVARCHAR(MAX); \
|
||||
SELECT TOP (1) {sql_var} = N'ALTER TABLE {table} DROP CONSTRAINT ' + QUOTENAME(dc.name) \
|
||||
FROM sys.default_constraints AS dc \
|
||||
WHERE dc.parent_object_id = OBJECT_ID(N'{table}') AND dc.parent_column_id = COLUMNPROPERTY(OBJECT_ID(N'{table}'), N'{col_name}', 'ColumnId'); \
|
||||
IF {sql_var} IS NOT NULL EXEC sp_executesql {sql_var};",
|
||||
table = table.replace('\'', "''"),
|
||||
col_name = current_name.replace('\'', "''")
|
||||
));
|
||||
@@ -484,6 +485,15 @@ pub(super) fn build_sqlserver_existing_column_sql(
|
||||
statements
|
||||
}
|
||||
|
||||
fn sqlserver_default_constraint_sql_var(table: &str, column_name: &str) -> String {
|
||||
let mut hash = 0x811c_9dc5u32;
|
||||
for byte in table.bytes().chain([0]).chain(column_name.bytes()) {
|
||||
hash ^= u32::from(byte);
|
||||
hash = hash.wrapping_mul(0x0100_0193);
|
||||
}
|
||||
format!("@dbx_default_sql_{hash:08x}")
|
||||
}
|
||||
|
||||
fn has_sqlserver_identity_change(column: &EditableStructureColumn) -> bool {
|
||||
let Some(original) = &column.original else {
|
||||
return false;
|
||||
|
||||
@@ -1021,6 +1021,78 @@ fn builds_sql_server_quoted_column_and_index_statements() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sqlserver_default_changes_drop_old_constraints_with_isolated_batches() {
|
||||
let mut sku = column("sku");
|
||||
sku.data_type = "nvarchar(64)".to_string();
|
||||
sku.default_value = "new sku".to_string();
|
||||
sku.original = Some(ColumnInfo {
|
||||
name: "sku".to_string(),
|
||||
data_type: "nvarchar(64)".to_string(),
|
||||
is_nullable: true,
|
||||
column_default: Some("'old sku'".to_string()),
|
||||
is_primary_key: false,
|
||||
extra: None,
|
||||
comment: None,
|
||||
});
|
||||
|
||||
let mut active = column("active");
|
||||
active.data_type = "bit".to_string();
|
||||
active.is_nullable = false;
|
||||
active.default_value = "1".to_string();
|
||||
active.original = Some(ColumnInfo {
|
||||
name: "active".to_string(),
|
||||
data_type: "bit".to_string(),
|
||||
is_nullable: false,
|
||||
column_default: Some("0".to_string()),
|
||||
is_primary_key: false,
|
||||
extra: None,
|
||||
comment: None,
|
||||
});
|
||||
|
||||
let result = build_table_structure_change_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::SqlServer),
|
||||
schema: Some("core".to_string()),
|
||||
table_name: "products".to_string(),
|
||||
columns: vec![sku, active],
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: Vec::new(),
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(result.statements.len(), 4);
|
||||
|
||||
let sku_drop = &result.statements[0];
|
||||
let active_drop = &result.statements[2];
|
||||
let sku_var = sku_drop.strip_prefix("DECLARE ").unwrap().split_once(" NVARCHAR(MAX);").unwrap().0;
|
||||
let active_var = active_drop.strip_prefix("DECLARE ").unwrap().split_once(" NVARCHAR(MAX);").unwrap().0;
|
||||
assert_ne!(sku_var, "@sql");
|
||||
assert_ne!(active_var, "@sql");
|
||||
assert_ne!(sku_var, active_var);
|
||||
|
||||
for (sql, column_name) in [(sku_drop, "sku"), (active_drop, "active")] {
|
||||
assert!(sql.contains("SELECT TOP (1)"));
|
||||
assert!(sql.contains(" + QUOTENAME(dc.name) FROM sys.default_constraints AS dc WHERE "));
|
||||
assert!(sql.contains("OBJECT_ID(N'[core].[products]')"));
|
||||
assert!(sql.contains(&format!("N'{column_name}', 'ColumnId'")));
|
||||
assert!(sql.contains(" IF "));
|
||||
assert!(!sql.contains("]'FROM"));
|
||||
assert!(!sql.contains("constraintsWHERE"));
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
result.statements[1],
|
||||
"ALTER TABLE [core].[products] ADD CONSTRAINT [DF_products_sku] DEFAULT 'new sku' FOR [sku];"
|
||||
);
|
||||
assert_eq!(
|
||||
result.statements[3],
|
||||
"ALTER TABLE [core].[products] ADD CONSTRAINT [DF_products_active] DEFAULT 1 FOR [active];"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sqlserver_unchanged_foreign_key_does_not_warn_when_saving_other_changes() {
|
||||
let mut email = column("email");
|
||||
|
||||
Reference in new issue
Block a user