From 358abe5e97d3e585f9ddb76f8c09130e5a5dfdcb Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Thu, 7 Dec 2023 16:23:21 +0000 Subject: [PATCH] Fix splitting migrations SQL by GO Fixes #32457 --- EFCore.sln.DotSettings | 1 + .../SqlServerMigrationsSqlGenerator.cs | 6 +- .../MigrationsInfrastructureTestBase.cs | 44 +++++- .../MigrationsInfrastructureSqlServerTest.cs | 140 ++++++++++++++++++ .../MigrationsInfrastructureSqliteTest.cs | 10 ++ 5 files changed, 197 insertions(+), 4 deletions(-) diff --git a/EFCore.sln.DotSettings b/EFCore.sln.DotSettings index 8712157ec96..85601ea8df9 100644 --- a/EFCore.sln.DotSettings +++ b/EFCore.sln.DotSettings @@ -268,6 +268,7 @@ The .NET Foundation licenses this file to you under the MIT license. True 2 DO_NOTHING + True True True True diff --git a/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs b/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs index 0b180e9f83e..79a85f8e513 100644 --- a/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs +++ b/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs @@ -1381,7 +1381,9 @@ protected override void Generate(SqlOperation operation, IModel? model, Migratio } var trimmed = line.TrimStart(); - if (trimmed.StartsWith("GO", StringComparison.OrdinalIgnoreCase)) + if (trimmed.StartsWith("GO", StringComparison.OrdinalIgnoreCase) + && (trimmed.Length == 2 + || char.IsWhiteSpace(trimmed[2]))) { var batch = batchBuilder.ToString(); batchBuilder.Clear(); @@ -2489,7 +2491,7 @@ private IReadOnlyList RewriteOperations( // for create table we always generate new temporal information from the operation itself // just in case there was a table with that name before that got deleted/renamed // this shouldn't happen as we re-use existin tables rather than drop/recreate - // but we are being extra defensive here + // but we are being extra defensive here // and also, temporal state (disabled versioning etc.) should always reset when creating a table temporalInformation = BuildTemporalInformationFromMigrationOperation(schema, createTableOperation); diff --git a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs index 9887af67645..0d1a226dcce 100644 --- a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs @@ -71,7 +71,8 @@ public virtual void Can_apply_all_migrations() history.GetAppliedMigrations(), x => Assert.Equal("00000000000001_Migration1", x.MigrationId), x => Assert.Equal("00000000000002_Migration2", x.MigrationId), - x => Assert.Equal("00000000000003_Migration3", x.MigrationId)); + x => Assert.Equal("00000000000003_Migration3", x.MigrationId), + x => Assert.Equal("00000000000004_Migration4", x.MigrationId)); } [ConditionalFact] @@ -142,7 +143,8 @@ public virtual async Task Can_apply_all_migrations_async() await history.GetAppliedMigrationsAsync(), x => Assert.Equal("00000000000001_Migration1", x.MigrationId), x => Assert.Equal("00000000000002_Migration2", x.MigrationId), - x => Assert.Equal("00000000000003_Migration3", x.MigrationId)); + x => Assert.Equal("00000000000003_Migration3", x.MigrationId), + x => Assert.Equal("00000000000004_Migration4", x.MigrationId)); } [ConditionalFact] @@ -412,4 +414,42 @@ protected override void Down(MigrationBuilder migrationBuilder) { } } + + [DbContext(typeof(MigrationsContext))] + [Migration("00000000000004_Migration4")] + private class Migration4 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + if (ActiveProvider == "Microsoft.EntityFrameworkCore.SqlServer") + { + migrationBuilder.Sql(""" + CREATE PROCEDURE [dbo].[GotoReproduction] + AS + BEGIN + DECLARE @Counter int; + SET @Counter = 1; + WHILE @Counter < 10 + BEGIN + SELECT @Counter + SET @Counter = @Counter + 1 + IF @Counter = 4 GOTO Branch_One --Jumps to the first branch. + IF @Counter = 5 GOTO Branch_Two --This will never execute. + END + Branch_One: + SELECT 'Jumping To Branch One.' + GOTO Branch_Three; --This will prevent Branch_Two from executing. + Branch_Two: + SELECT 'Jumping To Branch Two.' + Branch_Three: + SELECT 'Jumping To Branch Three.' + END; + """); + } + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + } + } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs index c02380efd1a..7ce04a75909 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs @@ -123,6 +123,38 @@ INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) COMMIT; GO +BEGIN TRANSACTION; +GO + + CREATE PROCEDURE [dbo].[GotoReproduction] + AS + BEGIN + DECLARE @Counter int; + SET @Counter = 1; + WHILE @Counter < 10 + BEGIN + SELECT @Counter + SET @Counter = @Counter + 1 + IF @Counter = 4 GOTO Branch_One --Jumps to the first branch. + IF @Counter = 5 GOTO Branch_Two --This will never execute. + END + Branch_One: + SELECT 'Jumping To Branch One.' + GOTO Branch_Three; --This will prevent Branch_Two from executing. + Branch_Two: + SELECT 'Jumping To Branch Two.' + Branch_Three: + SELECT 'Jumping To Branch Three.' + END; +GO + +INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) +VALUES (N'00000000000004_Migration4', N'7.0.0-test'); +GO + +COMMIT; +GO + """, Sql, @@ -173,6 +205,32 @@ INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000003_Migration3', N'7.0.0-test'); GO + CREATE PROCEDURE [dbo].[GotoReproduction] + AS + BEGIN + DECLARE @Counter int; + SET @Counter = 1; + WHILE @Counter < 10 + BEGIN + SELECT @Counter + SET @Counter = @Counter + 1 + IF @Counter = 4 GOTO Branch_One --Jumps to the first branch. + IF @Counter = 5 GOTO Branch_Two --This will never execute. + END + Branch_One: + SELECT 'Jumping To Branch One.' + GOTO Branch_Three; --This will prevent Branch_Two from executing. + Branch_Two: + SELECT 'Jumping To Branch Two.' + Branch_Three: + SELECT 'Jumping To Branch Three.' + END; +GO + +INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) +VALUES (N'00000000000004_Migration4', N'7.0.0-test'); +GO + """, Sql, @@ -333,6 +391,50 @@ INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) COMMIT; GO +BEGIN TRANSACTION; +GO + +IF NOT EXISTS ( + SELECT * FROM [__EFMigrationsHistory] + WHERE [MigrationId] = N'00000000000004_Migration4' +) +BEGIN + CREATE PROCEDURE [dbo].[GotoReproduction] + AS + BEGIN + DECLARE @Counter int; + SET @Counter = 1; + WHILE @Counter < 10 + BEGIN + SELECT @Counter + SET @Counter = @Counter + 1 + IF @Counter = 4 GOTO Branch_One --Jumps to the first branch. + IF @Counter = 5 GOTO Branch_Two --This will never execute. + END + Branch_One: + SELECT 'Jumping To Branch One.' + GOTO Branch_Three; --This will prevent Branch_Two from executing. + Branch_Two: + SELECT 'Jumping To Branch Two.' + Branch_Three: + SELECT 'Jumping To Branch Three.' + END; +END; +GO + +IF NOT EXISTS ( + SELECT * FROM [__EFMigrationsHistory] + WHERE [MigrationId] = N'00000000000004_Migration4' +) +BEGIN + INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'00000000000004_Migration4', N'7.0.0-test'); +END; +GO + +COMMIT; +GO + """, Sql, @@ -425,6 +527,44 @@ INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) END; GO +IF NOT EXISTS ( + SELECT * FROM [__EFMigrationsHistory] + WHERE [MigrationId] = N'00000000000004_Migration4' +) +BEGIN + CREATE PROCEDURE [dbo].[GotoReproduction] + AS + BEGIN + DECLARE @Counter int; + SET @Counter = 1; + WHILE @Counter < 10 + BEGIN + SELECT @Counter + SET @Counter = @Counter + 1 + IF @Counter = 4 GOTO Branch_One --Jumps to the first branch. + IF @Counter = 5 GOTO Branch_Two --This will never execute. + END + Branch_One: + SELECT 'Jumping To Branch One.' + GOTO Branch_Three; --This will prevent Branch_Two from executing. + Branch_Two: + SELECT 'Jumping To Branch Two.' + Branch_Three: + SELECT 'Jumping To Branch Three.' + END; +END; +GO + +IF NOT EXISTS ( + SELECT * FROM [__EFMigrationsHistory] + WHERE [MigrationId] = N'00000000000004_Migration4' +) +BEGIN + INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'00000000000004_Migration4', N'7.0.0-test'); +END; +GO + """, Sql, diff --git a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs index 3a70db60f49..c8c33bfc715 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs @@ -88,6 +88,13 @@ public override void Can_generate_up_scripts() COMMIT; +BEGIN TRANSACTION; + +INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") +VALUES ('00000000000004_Migration4', '7.0.0-test'); + +COMMIT; + """, Sql, @@ -121,6 +128,9 @@ public override void Can_generate_up_scripts_noTransactions() INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000003_Migration3', '7.0.0-test'); +INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") +VALUES ('00000000000004_Migration4', '7.0.0-test'); + """, Sql,