diff --git a/grate.unittests/Basic/Infrastructure/Oracle/Statement_Splitting/BatchSplitterReplacer_.cs b/grate.unittests/Basic/Infrastructure/Oracle/Statement_Splitting/BatchSplitterReplacer_.cs index 0909624b..3ca6dc11 100644 --- a/grate.unittests/Basic/Infrastructure/Oracle/Statement_Splitting/BatchSplitterReplacer_.cs +++ b/grate.unittests/Basic/Infrastructure/Oracle/Statement_Splitting/BatchSplitterReplacer_.cs @@ -262,10 +262,12 @@ public void slash_with_comment_after() } [Test] - public void slash_with_semicolon_directly_after() + public void slash_with_semicolon_directly_after_yields_just_one_splitter() { - string sql_to_match = "jalla /;"; - string expected_scrubbed = "jalla " + Batch_terminator_replacement_string + ";"; + string sql_to_match = @"jalla; +/"; + string expected_scrubbed = "jalla" + @" +" + Batch_terminator_replacement_string; TestContext.WriteLine(sql_to_match); string sql_statement_scrubbed = Replacer.Replace(sql_to_match); Assert.AreEqual(expected_scrubbed, sql_statement_scrubbed); diff --git a/grate.unittests/Basic/Infrastructure/Oracle/Statement_Splitting/StatementSplitter_.cs b/grate.unittests/Basic/Infrastructure/Oracle/Statement_Splitting/StatementSplitter_.cs index d5bf5a6c..73fc3b44 100644 --- a/grate.unittests/Basic/Infrastructure/Oracle/Statement_Splitting/StatementSplitter_.cs +++ b/grate.unittests/Basic/Infrastructure/Oracle/Statement_Splitting/StatementSplitter_.cs @@ -1,4 +1,5 @@ -using FluentAssertions; +using System.Linq; +using FluentAssertions; using grate.Infrastructure; using grate.Migration; using Microsoft.Extensions.Logging.Abstractions; @@ -15,7 +16,7 @@ public class StatementSplitter_ private static readonly StatementSplitter Splitter = new(Database.StatementSeparatorRegex); [Test] - public void Splits_and_removes_GO_statements() + public void Splits_and_removes_slashes_and_semicolon() { var original = @" SELECT * FROM v$version WHERE banner LIKE 'Oracle%'; @@ -27,6 +28,39 @@ SELECT 1 var batches = Splitter.Split(original); batches.Should().HaveCount(2); + batches.First().Should().NotEndWith(";"); + } + + [Test] + public void Splits_and_removes_slashes_and_semicolon_2() + { + var original = @" + create table table_one ( + col number + ); + / + + create table table_two ( + col number + ) +"; + var batches = Splitter.Split(original); + + batches.Should().HaveCount(2); + batches.First().Should().NotEndWith(";"); + } + + [Test] + public void Splits_and_removes_semicolon() + { + var original = @" +SELECT * FROM v$version WHERE banner LIKE 'Oracle%'; +SELECT 1 +"; + var batches = Splitter.Split(original).ToArray(); + + batches.Should().HaveCount(2); + batches.First().Should().NotEndWith(";"); } } diff --git a/grate.unittests/Generic/GenericDatabase.cs b/grate.unittests/Generic/GenericDatabase.cs index aa6586b9..c999571f 100644 --- a/grate.unittests/Generic/GenericDatabase.cs +++ b/grate.unittests/Generic/GenericDatabase.cs @@ -47,15 +47,16 @@ public virtual async Task Is_created_with_custom_script_if_custom_create_databas var customScript = Context.Syntax.CreateDatabase(scriptedDatabase, password); TestConfig.WriteContent(Wrap(config.SqlFilesDirectory, config.Folders?.CreateDatabase?.Path), "createDatabase.sql", customScript); - try - { + //try + //{ await using var migrator = GetMigrator(config); await migrator.Migrate(); - } - catch (DbException) - { + //} + //catch (DbException e) + //{ + //var s = e.Message; //Do nothing because database name is wrong due to custom script - } + //} File.Delete(Path.Join(Wrap(config.SqlFilesDirectory, config.Folders?.CreateDatabase?.Path).ToString(), "createDatabase.sql")); diff --git a/grate.unittests/TestInfrastructure/OracleSplitterContext.cs b/grate.unittests/TestInfrastructure/OracleSplitterContext.cs index 5c5e856d..96c4a3af 100644 --- a/grate.unittests/TestInfrastructure/OracleSplitterContext.cs +++ b/grate.unittests/TestInfrastructure/OracleSplitterContext.cs @@ -30,14 +30,6 @@ public static class FullSplitter /* / */ -BOB7 - -/* - -/ - -*/ - BOB8 -- @@ -121,14 +113,6 @@ INSERT [dbo].[Foo] ([Bar]) VALUES (N'/ speed racer, / speed racer, / speed racer /* / */ -BOB7 - -/* - -/ - -*/ - BOB8 -- @@ -164,7 +148,7 @@ yeppsasd decimal(20, 6) NULL, uhuhhh datetime NULL, slsald varchar(15) NULL, uhasdf varchar(15) NULL, - daf_asdfasdf DECIMAL(20,6) NULL; + daf_asdfasdf DECIMAL(20,6) NULL " + StatementSplitter.BatchTerminatorReplacementString + @" EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Daily job', diff --git a/grate/Infrastructure/BatchSplitterReplacer.cs b/grate/Infrastructure/BatchSplitterReplacer.cs index 23e38232..c87ddf3b 100644 --- a/grate/Infrastructure/BatchSplitterReplacer.cs +++ b/grate/Infrastructure/BatchSplitterReplacer.cs @@ -14,7 +14,18 @@ public BatchSplitterReplacer(string pattern, string replacement) _regex = new Regex(pattern, IgnoreCase | Multiline); } - public string Replace(string text) => _regex.Replace(text, ReplaceBatchSeparator); + public string Replace(string text) + { + var replace = _regex.Replace(text, ReplaceBatchSeparator); + + // Combine multiple consecutive replacement tokens with one (needed for Oracle, if ; and / are on separate lines) + replace = Regex.Replace( + replace, + Regex.Escape(Replacement) + "(\\s*)" + Regex.Escape(Replacement), + "$1" + Replacement); + + return replace; + } private string ReplaceBatchSeparator(Match match) { @@ -22,4 +33,4 @@ private string ReplaceBatchSeparator(Match match) var replacement = groups["BATCHSPLITTER"].Success ? Replacement : string.Empty; return groups["KEEP1"].Value + replacement + groups["KEEP2"].Value; } -} \ No newline at end of file +} diff --git a/grate/Infrastructure/OracleSyntax.cs b/grate/Infrastructure/OracleSyntax.cs index dbc1a99b..5ede35b4 100644 --- a/grate/Infrastructure/OracleSyntax.cs +++ b/grate/Infrastructure/OracleSyntax.cs @@ -11,8 +11,10 @@ public string StatementSeparatorRegex const string strings = @"(?'[^']*')"; const string dashComments = @"(?--.*$)"; const string starComments = @"(?/\*[\S\s]*?\*/)"; - const string separator = @"(?^|\s)(?/)(?\s|;|$)"; - return strings + "|" + dashComments + "|" + starComments + "|" + separator; + const string batchSeparator = @"(?.*)(?;)(?\s|$)"; + //const string sqlPlusExecuteCommand = @"(?^|\s)(?\/|;)(?\s*|$|\n)"; + const string sqlPlusExecuteCommand = @"(?^|\s)(?\/)(?\s|$)"; + return strings + "|" + dashComments + "|" + starComments + "|" + batchSeparator + "|" + sqlPlusExecuteCommand; } }