Skip to content

Commit 1c0ef32

Browse files
authored
[release/9.0] Uniquify all variables used in SQL Server migration scripts (#35228)
Fixes #35132
1 parent b7a436f commit 1c0ef32

File tree

3 files changed

+494
-480
lines changed

3 files changed

+494
-480
lines changed

src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace Microsoft.EntityFrameworkCore.Migrations;
2929
public class SqlServerMigrationsSqlGenerator : MigrationsSqlGenerator
3030
{
3131
private IReadOnlyList<MigrationOperation> _operations = null!;
32-
private int _variableCounter;
32+
private int _variableCounter = -1;
3333

3434
private readonly ICommandBatchPreparer _commandBatchPreparer;
3535

@@ -643,25 +643,23 @@ protected override void Generate(
643643

644644
subBuilder.Append(")");
645645

646+
var historyTableName = operation[SqlServerAnnotationNames.TemporalHistoryTableName] as string;
647+
string historyTable;
646648
if (needsExec)
647649
{
648650
subBuilder
649651
.EndCommand();
650652

651653
var execBody = subBuilder.GetCommandList().Single().CommandText.Replace("'", "''");
652654

655+
var schemaVariable = Uniquify("@historyTableSchema");
653656
builder
654-
.AppendLine("DECLARE @historyTableSchema sysname = SCHEMA_NAME()")
657+
.AppendLine($"DECLARE {schemaVariable} sysname = SCHEMA_NAME()")
655658
.Append("EXEC(N'")
656659
.Append(execBody);
657-
}
658660

659-
var historyTableName = operation[SqlServerAnnotationNames.TemporalHistoryTableName] as string;
660-
string historyTable;
661-
if (needsExec)
662-
{
663661
historyTable = Dependencies.SqlGenerationHelper.DelimitIdentifier(historyTableName!);
664-
tableCreationOptions.Add($"SYSTEM_VERSIONING = ON (HISTORY_TABLE = [' + @historyTableSchema + N'].{historyTable})");
662+
tableCreationOptions.Add($"SYSTEM_VERSIONING = ON (HISTORY_TABLE = [' + {schemaVariable} + N'].{historyTable})");
665663
}
666664
else
667665
{
@@ -1116,10 +1114,11 @@ protected override void Generate(
11161114
{
11171115
if (operation[SqlServerAnnotationNames.EditionOptions] is string editionOptions)
11181116
{
1117+
var dbVariable = Uniquify("@db_name");
11191118
builder
11201119
.AppendLine("BEGIN")
1121-
.AppendLine("DECLARE @db_name nvarchar(max) = DB_NAME();")
1122-
.AppendLine("EXEC(N'ALTER DATABASE [' + @db_name + '] MODIFY ( ")
1120+
.AppendLine($"DECLARE {dbVariable} nvarchar(max) = DB_NAME();")
1121+
.AppendLine($"EXEC(N'ALTER DATABASE [' + {dbVariable} + '] MODIFY ( ")
11231122
.Append(editionOptions.Replace("'", "''"))
11241123
.AppendLine(" );');")
11251124
.AppendLine("END")
@@ -1128,19 +1127,21 @@ protected override void Generate(
11281127

11291128
if (operation.Collation != operation.OldDatabase.Collation)
11301129
{
1130+
var dbVariable = Uniquify("@db_name");
11311131
builder
11321132
.AppendLine("BEGIN")
1133-
.AppendLine("DECLARE @db_name nvarchar(max) = DB_NAME();");
1133+
.AppendLine($"DECLARE {dbVariable} nvarchar(max) = DB_NAME();");
11341134

1135+
var collation = operation.Collation;
11351136
if (operation.Collation == null)
11361137
{
1137-
builder.AppendLine("DECLARE @defaultCollation nvarchar(max) = CAST(SERVERPROPERTY('Collation') AS nvarchar(max));");
1138+
var collationVariable = Uniquify("@defaultCollation");
1139+
builder.AppendLine($"DECLARE {collationVariable} nvarchar(max) = CAST(SERVERPROPERTY('Collation') AS nvarchar(max));");
1140+
collation = "' + " + collationVariable + " + N'";
11381141
}
11391142

11401143
builder
1141-
.Append("EXEC(N'ALTER DATABASE [' + @db_name + '] COLLATE ")
1142-
.Append(operation.Collation ?? "' + @defaultCollation + N'")
1143-
.AppendLine(";');")
1144+
.AppendLine($"EXEC(N'ALTER DATABASE [' + {dbVariable} + '] COLLATE {collation};');")
11441145
.AppendLine("END")
11451146
.AppendLine();
11461147
}
@@ -1167,10 +1168,11 @@ protected override void Generate(
11671168

11681169
using (builder.Indent())
11691170
{
1171+
var dbVariable = Uniquify("@db_name");
11701172
builder
11711173
.AppendLine("BEGIN")
11721174
.AppendLine("ALTER DATABASE CURRENT SET AUTO_CLOSE OFF;")
1173-
.AppendLine("DECLARE @db_name nvarchar(max) = DB_NAME();")
1175+
.AppendLine($"DECLARE {dbVariable} nvarchar(max) = DB_NAME();")
11741176
.AppendLine("DECLARE @fg_name nvarchar(max);")
11751177
.AppendLine("SELECT TOP(1) @fg_name = [name] FROM [sys].[filegroups] WHERE [type] = N'FX';")
11761178
.AppendLine()
@@ -1180,20 +1182,21 @@ protected override void Generate(
11801182
{
11811183
builder
11821184
.AppendLine("BEGIN")
1183-
.AppendLine("SET @fg_name = @db_name + N'_MODFG';")
1185+
.AppendLine($"SET @fg_name = {dbVariable} + N'_MODFG';")
11841186
.AppendLine("EXEC(N'ALTER DATABASE CURRENT ADD FILEGROUP [' + @fg_name + '] CONTAINS MEMORY_OPTIMIZED_DATA;');")
11851187
.AppendLine("END");
11861188
}
11871189

1190+
var pathVariable = Uniquify("@path");
11881191
builder
11891192
.AppendLine()
1190-
.AppendLine("DECLARE @path nvarchar(max);")
1191-
.Append("SELECT TOP(1) @path = [physical_name] FROM [sys].[database_files] ")
1193+
.AppendLine($"DECLARE {pathVariable} nvarchar(max);")
1194+
.Append($"SELECT TOP(1) {pathVariable} = [physical_name] FROM [sys].[database_files] ")
11921195
.AppendLine("WHERE charindex('\\', [physical_name]) > 0 ORDER BY [file_id];")
1193-
.AppendLine("IF (@path IS NULL)")
1194-
.IncrementIndent().AppendLine("SET @path = '\\' + @db_name;").DecrementIndent()
1196+
.AppendLine($"IF ({pathVariable} IS NULL)")
1197+
.IncrementIndent().AppendLine($"SET {pathVariable} = '\\' + {dbVariable};").DecrementIndent()
11951198
.AppendLine()
1196-
.AppendLine("DECLARE @filename nvarchar(max) = right(@path, charindex('\\', reverse(@path)) - 1);")
1199+
.AppendLine($"DECLARE @filename nvarchar(max) = right({pathVariable}, charindex('\\', reverse({pathVariable})) - 1);")
11971200
.AppendLine(
11981201
"SET @filename = REPLACE(left(@filename, len(@filename) - charindex('.', reverse(@filename))), '''', '''''') + N'_MOD';")
11991202
.AppendLine(
@@ -1739,10 +1742,11 @@ protected virtual void Transfer(
17391742
{
17401743
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));
17411744

1745+
var schemaVariable = Uniquify("@defaultSchema");
17421746
builder
1743-
.AppendLine("DECLARE @defaultSchema sysname = SCHEMA_NAME();")
1747+
.AppendLine($"DECLARE {schemaVariable} sysname = SCHEMA_NAME();")
17441748
.Append("EXEC(")
1745-
.Append("N'ALTER SCHEMA [' + @defaultSchema + ")
1749+
.Append($"N'ALTER SCHEMA [' + {schemaVariable} + ")
17461750
.Append(
17471751
stringTypeMapping.GenerateSqlLiteral(
17481752
"] TRANSFER " + Dependencies.SqlGenerationHelper.DelimitIdentifier(name, schema) + ";"))
@@ -1908,7 +1912,7 @@ protected virtual void DropDefaultConstraint(
19081912
{
19091913
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));
19101914

1911-
var variable = "@var" + _variableCounter++;
1915+
var variable = Uniquify("@var");
19121916

19131917
builder
19141918
.Append("DECLARE ")
@@ -2039,18 +2043,18 @@ protected virtual void AddDescription(
20392043
string? column = null,
20402044
bool omitVariableDeclarations = false)
20412045
{
2042-
string schemaLiteral;
2046+
var schemaLiteral = Uniquify("@defaultSchema", increase: !omitVariableDeclarations);
2047+
var descriptionVariable = Uniquify("@description", increase: false);
2048+
20432049
if (schema == null)
20442050
{
20452051
if (!omitVariableDeclarations)
20462052
{
2047-
builder.Append("DECLARE @defaultSchema AS sysname")
2053+
builder.Append($"DECLARE {schemaLiteral} AS sysname")
20482054
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
2049-
builder.Append("SET @defaultSchema = SCHEMA_NAME()")
2055+
builder.Append($"SET {schemaLiteral} = SCHEMA_NAME()")
20502056
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
20512057
}
2052-
2053-
schemaLiteral = "@defaultSchema";
20542058
}
20552059
else
20562060
{
@@ -2059,16 +2063,15 @@ protected virtual void AddDescription(
20592063

20602064
if (!omitVariableDeclarations)
20612065
{
2062-
builder.Append("DECLARE @description AS sql_variant")
2066+
builder.Append($"DECLARE {descriptionVariable} AS sql_variant")
20632067
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
20642068
}
20652069

2066-
builder.Append("SET @description = ")
2067-
.Append(Literal(description))
2070+
builder.Append($"SET {descriptionVariable} = {Literal(description)}")
20682071
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
20692072
builder
20702073
.Append("EXEC sp_addextendedproperty 'MS_Description', ")
2071-
.Append("@description")
2074+
.Append(descriptionVariable)
20722075
.Append(", 'SCHEMA', ")
20732076
.Append(schemaLiteral)
20742077
.Append(", 'TABLE', ")
@@ -2221,18 +2224,17 @@ protected virtual void DropDescription(
22212224
{
22222225
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));
22232226

2224-
string schemaLiteral;
2227+
var schemaLiteral = Uniquify("@defaultSchema", increase: !omitVariableDeclarations);
2228+
var descriptionVariable = Uniquify("@description", increase: false);
22252229
if (schema == null)
22262230
{
22272231
if (!omitVariableDeclarations)
22282232
{
2229-
builder.Append("DECLARE @defaultSchema AS sysname")
2233+
builder.Append($"DECLARE {schemaLiteral} AS sysname")
22302234
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
2231-
builder.Append("SET @defaultSchema = SCHEMA_NAME()")
2235+
builder.Append($"SET {schemaLiteral} = SCHEMA_NAME()")
22322236
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
22332237
}
2234-
2235-
schemaLiteral = "@defaultSchema";
22362238
}
22372239
else
22382240
{
@@ -2241,7 +2243,7 @@ protected virtual void DropDescription(
22412243

22422244
if (!omitVariableDeclarations)
22432245
{
2244-
builder.Append("DECLARE @description AS sql_variant")
2246+
builder.Append($"DECLARE {descriptionVariable} AS sql_variant")
22452247
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
22462248
}
22472249

@@ -2351,6 +2353,16 @@ private static bool HasDifferences(IEnumerable<IAnnotation> source, IEnumerable<
23512353
return count != targetAnnotations.Count;
23522354
}
23532355

2356+
private string Uniquify(string variableName, bool increase = true)
2357+
{
2358+
if (increase)
2359+
{
2360+
_variableCounter++;
2361+
}
2362+
2363+
return _variableCounter == 0 ? variableName : variableName + _variableCounter;
2364+
}
2365+
23542366
private IReadOnlyList<MigrationOperation> RewriteOperations(
23552367
IReadOnlyList<MigrationOperation> migrationOperations,
23562368
IModel? model,
@@ -3043,10 +3055,12 @@ void EnableVersioning(string table, string? schema, string historyTableName, str
30433055
{
30443056
var stringBuilder = new StringBuilder();
30453057

3058+
string? schemaVariable = null;
30463059
if (historyTableSchema == null)
30473060
{
3061+
schemaVariable = Uniquify("@historyTableSchema");
30483062
// need to run command using EXEC to inject default schema
3049-
stringBuilder.AppendLine("DECLARE @historyTableSchema sysname = SCHEMA_NAME()");
3063+
stringBuilder.AppendLine($"DECLARE {schemaVariable} sysname = SCHEMA_NAME()");
30503064
stringBuilder.Append("EXEC(N'");
30513065
}
30523066

@@ -3065,7 +3079,7 @@ void EnableVersioning(string table, string? schema, string historyTableName, str
30653079
else
30663080
{
30673081
stringBuilder.AppendLine(
3068-
$" SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [' + @historyTableSchema + '].{historyTable}))')");
3082+
$" SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [' + {schemaVariable} + '].{historyTable}))')");
30693083
}
30703084

30713085
operations.Add(

0 commit comments

Comments
 (0)