fix(sqlserver): wrap identity INSERTs in exported SQL scripts

This commit is contained in:
U1 authored and GitHub committed 2026-09-15 16:59:58 +08:00
1 parent dd99786c01
commit e255c49e7d
1 file changed
+38 -5
+38 -5
View File
@@ -1211,10 +1211,14 @@ pub fn build_export_insert_statements(options: BuildExportInsertStatementsOption
.collect::<Vec<_>>()
.join(", ");
let mut statements = Vec::new();
let needs_dameng_identity_insert = options.database_type == Some(DatabaseType::Dameng)
&& insert_columns.iter().any(|(index, _, _)| {
is_identity_column_extra(options.column_extras.get(*index).and_then(|value| value.as_deref()))
});
// Dameng and SQL Server both reject explicit values for identity columns
// unless `SET IDENTITY_INSERT <table> ON` wraps the statement (SQL Server
// error 544), so exported INSERTs must carry the wrapper.
let needs_identity_insert_wrapper =
matches!(options.database_type, Some(DatabaseType::Dameng) | Some(DatabaseType::SqlServer))
&& insert_columns.iter().any(|(index, _, _)| {
is_identity_column_extra(options.column_extras.get(*index).and_then(|value| value.as_deref()))
});
let statement_prefix = format!("INSERT INTO {table} ({columns}) VALUES ");
let statement_overhead_bytes = export_sql_statement_bytes(options.database_type, &statement_prefix) + 1;
@@ -1233,7 +1237,7 @@ pub fn build_export_insert_statements(options: BuildExportInsertStatementsOption
insert_sql.push_str(&statement_prefix);
insert_sql.push_str(values);
insert_sql.push(';');
if needs_dameng_identity_insert {
if needs_identity_insert_wrapper {
statements.push(wrap_dameng_identity_insert_sql_for_table(&insert_sql, &table));
} else {
statements.push(insert_sql);
@@ -5695,6 +5699,35 @@ mod tests {
);
}
#[test]
fn sqlserver_identity_export_inserts_enable_identity_insert() {
// The SQL Server column metadata reports `identity(seed,increment)`;
// explicit values for such columns are rejected with error 544 unless
// the INSERT is wrapped in SET IDENTITY_INSERT.
let statements = build_export_insert_statements(BuildExportInsertStatementsOptions {
database_type: Some(DatabaseType::SqlServer),
identifier_quote: None,
schema: Some("dbo".to_string()),
table_name: Some("events".to_string()),
qualified_table_name: None,
columns: vec!["id".to_string(), "name".to_string()],
column_types: vec![Some("int".to_string()), Some("nvarchar(50)".to_string())],
column_extras: vec![Some("identity(1,1)".to_string()), None],
spatial_columns: Vec::new(),
spatial_values: Vec::new(),
rows: vec![vec![json!(1), json!("Ada")]],
batch_size: Some(10),
})
.unwrap();
assert_eq!(
statements,
vec![
"SET IDENTITY_INSERT [dbo].[events] ON;\nINSERT INTO [dbo].[events] ([id], [name]) VALUES (1, N'Ada');\nSET IDENTITY_INSERT [dbo].[events] OFF;"
]
);
}
#[test]
fn builds_database_sql_export_with_ddl_before_data() {
let sql = build_database_sql_export(BuildDatabaseSqlExportOptions {