Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 56 additions & 42 deletions src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace Microsoft.EntityFrameworkCore.Migrations;
public class SqlServerMigrationsSqlGenerator : MigrationsSqlGenerator
{
private IReadOnlyList<MigrationOperation> _operations = null!;
private int _variableCounter;
private int _variableCounter = -1;

private readonly ICommandBatchPreparer _commandBatchPreparer;

Expand Down Expand Up @@ -643,25 +643,23 @@ protected override void Generate(

subBuilder.Append(")");

var historyTableName = operation[SqlServerAnnotationNames.TemporalHistoryTableName] as string;
string historyTable;
if (needsExec)
{
subBuilder
.EndCommand();

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

var schemaVariable = Uniquify("@historyTableSchema");
builder
.AppendLine("DECLARE @historyTableSchema sysname = SCHEMA_NAME()")
.AppendLine($"DECLARE {schemaVariable} sysname = SCHEMA_NAME()")
.Append("EXEC(N'")
.Append(execBody);
}

var historyTableName = operation[SqlServerAnnotationNames.TemporalHistoryTableName] as string;
string historyTable;
if (needsExec)
{
historyTable = Dependencies.SqlGenerationHelper.DelimitIdentifier(historyTableName!);
tableCreationOptions.Add($"SYSTEM_VERSIONING = ON (HISTORY_TABLE = [' + @historyTableSchema + N'].{historyTable})");
tableCreationOptions.Add($"SYSTEM_VERSIONING = ON (HISTORY_TABLE = [' + {schemaVariable} + N'].{historyTable})");
}
else
{
Expand Down Expand Up @@ -1116,10 +1114,11 @@ protected override void Generate(
{
if (operation[SqlServerAnnotationNames.EditionOptions] is string editionOptions)
{
var dbVariable = Uniquify("@db_name");
builder
.AppendLine("BEGIN")
.AppendLine("DECLARE @db_name nvarchar(max) = DB_NAME();")
.AppendLine("EXEC(N'ALTER DATABASE [' + @db_name + '] MODIFY ( ")
.AppendLine($"DECLARE {dbVariable} nvarchar(max) = DB_NAME();")
.AppendLine($"EXEC(N'ALTER DATABASE [' + {dbVariable} + '] MODIFY ( ")
.Append(editionOptions.Replace("'", "''"))
.AppendLine(" );');")
.AppendLine("END")
Expand All @@ -1128,19 +1127,21 @@ protected override void Generate(

if (operation.Collation != operation.OldDatabase.Collation)
{
var dbVariable = Uniquify("@db_name");
builder
.AppendLine("BEGIN")
.AppendLine("DECLARE @db_name nvarchar(max) = DB_NAME();");
.AppendLine($"DECLARE {dbVariable} nvarchar(max) = DB_NAME();");

var collation = operation.Collation;
if (operation.Collation == null)
{
builder.AppendLine("DECLARE @defaultCollation nvarchar(max) = CAST(SERVERPROPERTY('Collation') AS nvarchar(max));");
var collationVariable = Uniquify("@defaultCollation");
builder.AppendLine($"DECLARE {collationVariable} nvarchar(max) = CAST(SERVERPROPERTY('Collation') AS nvarchar(max));");
collation = "' + " + collationVariable + " + N'";
}

builder
.Append("EXEC(N'ALTER DATABASE [' + @db_name + '] COLLATE ")
.Append(operation.Collation ?? "' + @defaultCollation + N'")
.AppendLine(";');")
.AppendLine($"EXEC(N'ALTER DATABASE [' + {dbVariable} + '] COLLATE {collation};');")
.AppendLine("END")
.AppendLine();
}
Expand All @@ -1167,10 +1168,11 @@ protected override void Generate(

using (builder.Indent())
{
var dbVariable = Uniquify("@db_name");
builder
.AppendLine("BEGIN")
.AppendLine("ALTER DATABASE CURRENT SET AUTO_CLOSE OFF;")
.AppendLine("DECLARE @db_name nvarchar(max) = DB_NAME();")
.AppendLine($"DECLARE {dbVariable} nvarchar(max) = DB_NAME();")
.AppendLine("DECLARE @fg_name nvarchar(max);")
.AppendLine("SELECT TOP(1) @fg_name = [name] FROM [sys].[filegroups] WHERE [type] = N'FX';")
.AppendLine()
Expand All @@ -1180,20 +1182,21 @@ protected override void Generate(
{
builder
.AppendLine("BEGIN")
.AppendLine("SET @fg_name = @db_name + N'_MODFG';")
.AppendLine($"SET @fg_name = {dbVariable} + N'_MODFG';")
.AppendLine("EXEC(N'ALTER DATABASE CURRENT ADD FILEGROUP [' + @fg_name + '] CONTAINS MEMORY_OPTIMIZED_DATA;');")
.AppendLine("END");
}

var pathVariable = Uniquify("@path");
builder
.AppendLine()
.AppendLine("DECLARE @path nvarchar(max);")
.Append("SELECT TOP(1) @path = [physical_name] FROM [sys].[database_files] ")
.AppendLine($"DECLARE {pathVariable} nvarchar(max);")
.Append($"SELECT TOP(1) {pathVariable} = [physical_name] FROM [sys].[database_files] ")
.AppendLine("WHERE charindex('\\', [physical_name]) > 0 ORDER BY [file_id];")
.AppendLine("IF (@path IS NULL)")
.IncrementIndent().AppendLine("SET @path = '\\' + @db_name;").DecrementIndent()
.AppendLine($"IF ({pathVariable} IS NULL)")
.IncrementIndent().AppendLine($"SET {pathVariable} = '\\' + {dbVariable};").DecrementIndent()
.AppendLine()
.AppendLine("DECLARE @filename nvarchar(max) = right(@path, charindex('\\', reverse(@path)) - 1);")
.AppendLine($"DECLARE @filename nvarchar(max) = right({pathVariable}, charindex('\\', reverse({pathVariable})) - 1);")
.AppendLine(
"SET @filename = REPLACE(left(@filename, len(@filename) - charindex('.', reverse(@filename))), '''', '''''') + N'_MOD';")
.AppendLine(
Expand Down Expand Up @@ -1739,10 +1742,11 @@ protected virtual void Transfer(
{
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));

var schemaVariable = Uniquify("@defaultSchema");
builder
.AppendLine("DECLARE @defaultSchema sysname = SCHEMA_NAME();")
.AppendLine($"DECLARE {schemaVariable} sysname = SCHEMA_NAME();")
.Append("EXEC(")
.Append("N'ALTER SCHEMA [' + @defaultSchema + ")
.Append($"N'ALTER SCHEMA [' + {schemaVariable} + ")
.Append(
stringTypeMapping.GenerateSqlLiteral(
"] TRANSFER " + Dependencies.SqlGenerationHelper.DelimitIdentifier(name, schema) + ";"))
Expand Down Expand Up @@ -1908,7 +1912,7 @@ protected virtual void DropDefaultConstraint(
{
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));

var variable = "@var" + _variableCounter++;
var variable = Uniquify("@var");

builder
.Append("DECLARE ")
Expand Down Expand Up @@ -2039,18 +2043,18 @@ protected virtual void AddDescription(
string? column = null,
bool omitVariableDeclarations = false)
{
string schemaLiteral;
var schemaLiteral = Uniquify("@defaultSchema", increase: !omitVariableDeclarations);
var descriptionVariable = Uniquify("@description", increase: false);

if (schema == null)
{
if (!omitVariableDeclarations)
{
builder.Append("DECLARE @defaultSchema AS sysname")
builder.Append($"DECLARE {schemaLiteral} AS sysname")
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
builder.Append("SET @defaultSchema = SCHEMA_NAME()")
builder.Append($"SET {schemaLiteral} = SCHEMA_NAME()")
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
}

schemaLiteral = "@defaultSchema";
}
else
{
Expand All @@ -2059,16 +2063,15 @@ protected virtual void AddDescription(

if (!omitVariableDeclarations)
{
builder.Append("DECLARE @description AS sql_variant")
builder.Append($"DECLARE {descriptionVariable} AS sql_variant")
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
}

builder.Append("SET @description = ")
.Append(Literal(description))
builder.Append($"SET {descriptionVariable} = {Literal(description)}")
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
builder
.Append("EXEC sp_addextendedproperty 'MS_Description', ")
.Append("@description")
.Append(descriptionVariable)
.Append(", 'SCHEMA', ")
.Append(schemaLiteral)
.Append(", 'TABLE', ")
Expand Down Expand Up @@ -2221,18 +2224,17 @@ protected virtual void DropDescription(
{
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));

string schemaLiteral;
var schemaLiteral = Uniquify("@defaultSchema", increase: !omitVariableDeclarations);
var descriptionVariable = Uniquify("@description", increase: false);
if (schema == null)
{
if (!omitVariableDeclarations)
{
builder.Append("DECLARE @defaultSchema AS sysname")
builder.Append($"DECLARE {schemaLiteral} AS sysname")
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
builder.Append("SET @defaultSchema = SCHEMA_NAME()")
builder.Append($"SET {schemaLiteral} = SCHEMA_NAME()")
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
}

schemaLiteral = "@defaultSchema";
}
else
{
Expand All @@ -2241,7 +2243,7 @@ protected virtual void DropDescription(

if (!omitVariableDeclarations)
{
builder.Append("DECLARE @description AS sql_variant")
builder.Append($"DECLARE {descriptionVariable} AS sql_variant")
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
}

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

private string Uniquify(string variableName, bool increase = true)
{
if (increase)
{
_variableCounter++;
}

return _variableCounter == 0 ? variableName : variableName + _variableCounter;
}

private IReadOnlyList<MigrationOperation> RewriteOperations(
IReadOnlyList<MigrationOperation> migrationOperations,
IModel? model,
Expand Down Expand Up @@ -3043,10 +3055,12 @@ void EnableVersioning(string table, string? schema, string historyTableName, str
{
var stringBuilder = new StringBuilder();

string? schemaVariable = null;
if (historyTableSchema == null)
{
schemaVariable = Uniquify("@historyTableSchema");
// need to run command using EXEC to inject default schema
stringBuilder.AppendLine("DECLARE @historyTableSchema sysname = SCHEMA_NAME()");
stringBuilder.AppendLine($"DECLARE {schemaVariable} sysname = SCHEMA_NAME()");
stringBuilder.Append("EXEC(N'");
}

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

operations.Add(
Expand Down
Loading