From 46f03d2ab3d32d96df33776c048de9c94f92962e Mon Sep 17 00:00:00 2001 From: Ivan Ponomarev Date: Thu, 16 Nov 2023 11:27:59 +0000 Subject: [PATCH 1/5] fix bugs introduced by #7646 --- .../org/testcontainers/ext/ScriptScanner.java | 32 +++++++++--- .../java/org/testcontainers/ext/Test.java | 25 ++++++++++ .../testcontainers/ext/ScriptScannerTest.java | 49 +++++++++++++++++++ 3 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 modules/database-commons/src/main/java/org/testcontainers/ext/Test.java create mode 100644 modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptScanner.java b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptScanner.java index 528acd139c7..1ffde4c0e29 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptScanner.java +++ b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptScanner.java @@ -28,11 +28,7 @@ class ScriptScanner { private final Pattern whitespace = Pattern.compile("\\s+"); - private final Pattern identifier = Pattern.compile("[a-z][a-z0-9_]*", Pattern.CASE_INSENSITIVE); - - private final Pattern singleQuotedString = Pattern.compile("'(\\\\'|[^'])*'"); - - private final Pattern ansiQuotedString = Pattern.compile("\"(\\\\\"|[^\"])*\""); + private final Pattern identifier = Pattern.compile("[a-z][a-z0-9_$]*", Pattern.CASE_INSENSITIVE); private final Pattern dollarQuotedStringDelimiter = Pattern.compile("\\$\\w*\\$"); @@ -54,7 +50,8 @@ private boolean matches(String substring) { private boolean matches(Pattern regexp) { Matcher m = regexp.matcher(script); - if (m.find(offset) && m.start() == offset) { + m.region(offset, script.length()); + if (m.lookingAt()) { currentMatch = m.group(); offset = m.end(); return true; @@ -99,6 +96,27 @@ private boolean matchesMultilineComment() { return false; } + + private boolean matchesQuotedString(final char quote) { + if (script.charAt(offset) == quote) { + boolean escaped = false; + for (int i = offset + 1; i < script.length(); i++) { + char c = script.charAt(i); + if (escaped) { + //just skip the escaped character and drop the flag + escaped = false; + } else if (c == '\\') { + escaped = true; + } else if (c == quote) { + currentMatch = script.substring(offset, i + 1); + offset = i + 1; + return true; + } + } + } + return false; + } + private boolean matchesDollarQuotedString() { //Matches $$ .... $$ if (matches(dollarQuotedStringDelimiter)) { @@ -124,7 +142,7 @@ Lexem next() { return Lexem.SEPARATOR; } else if (matchesSingleLineComment() || matchesMultilineComment()) { return Lexem.COMMENT; - } else if (matches(singleQuotedString) || matches(ansiQuotedString) || matchesDollarQuotedString()) { + } else if (matchesQuotedString('\'') || matchesQuotedString('"') || matchesDollarQuotedString()) { return Lexem.QUOTED_STRING; } else if (matches(identifier)) { return Lexem.IDENTIFIER; diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/Test.java b/modules/database-commons/src/main/java/org/testcontainers/ext/Test.java new file mode 100644 index 00000000000..1becc921b6c --- /dev/null +++ b/modules/database-commons/src/main/java/org/testcontainers/ext/Test.java @@ -0,0 +1,25 @@ +package org.testcontainers.ext; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.stream.Collectors; + +public class Test { + public static void main(String[] args) throws IOException { + Path p = Paths.get("C:\\ideaspace\\synthesized\\testing-suite\\engine\\executor\\src\\e2e\\resources\\testspecs\\mysql\\prepare_test_data.sql"); + + String s = Files.lines(p).collect(Collectors.joining("\n")); + ArrayList l = new ArrayList<>(); + ScriptUtils.splitSqlScript("a", s, ";", + ScriptUtils.DEFAULT_COMMENT_PREFIX, ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER, + ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER, l); + l.forEach(line -> { + System.out.println(line); + System.out.println("----"); + }); + + } +} diff --git a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java new file mode 100644 index 00000000000..9dece077f50 --- /dev/null +++ b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java @@ -0,0 +1,49 @@ +package org.testcontainers.ext; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; + +import java.util.regex.Pattern; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ScriptScannerTest { + @Test + public void testHugeStringLiteral() { + String script = "/* a comment */ \"" + StringUtils.repeat('~', 10000) + "\";"; + ScriptScanner scanner = scanner(script); + assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.COMMENT); + assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.WHITESPACE); + assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.QUOTED_STRING); + assertThat(scanner.getCurrentMatch()).matches(Pattern.compile("\"~+\"")); + } + + @Test + public void testPgIdentifierWithDollarSigns() { + ScriptScanner scanner = scanner("this$is$a$valid$postgreSQL$identifier " + + "$a$While this is a quoted string$a$$ --just followed by a dollar sign"); + assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.IDENTIFIER); + assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.WHITESPACE); + assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.QUOTED_STRING); + assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.OTHER); + } + + @Test + public void testQuotedLiterals(){ + ScriptScanner scanner = scanner("'this \\'is a literal' \"this \\\" is a literal\""); + assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.QUOTED_STRING); + assertThat(scanner.getCurrentMatch()).isEqualTo("'this \\'is a literal'"); + assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.WHITESPACE); + assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.QUOTED_STRING); + assertThat(scanner.getCurrentMatch()).isEqualTo("\"this \\\" is a literal\""); + } + + private static ScriptScanner scanner(String script) { + return new ScriptScanner("dummy", + script, + ScriptUtils.DEFAULT_STATEMENT_SEPARATOR, + ScriptUtils.DEFAULT_COMMENT_PREFIX, + ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER, + ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER); + } +} From a8bb7ac140579972d84d703c690bcb8bb17652d1 Mon Sep 17 00:00:00 2001 From: Ivan Ponomarev Date: Thu, 16 Nov 2023 11:42:40 +0000 Subject: [PATCH 2/5] remove erroneously committed file --- .../java/org/testcontainers/ext/Test.java | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 modules/database-commons/src/main/java/org/testcontainers/ext/Test.java diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/Test.java b/modules/database-commons/src/main/java/org/testcontainers/ext/Test.java deleted file mode 100644 index 1becc921b6c..00000000000 --- a/modules/database-commons/src/main/java/org/testcontainers/ext/Test.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.testcontainers.ext; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.stream.Collectors; - -public class Test { - public static void main(String[] args) throws IOException { - Path p = Paths.get("C:\\ideaspace\\synthesized\\testing-suite\\engine\\executor\\src\\e2e\\resources\\testspecs\\mysql\\prepare_test_data.sql"); - - String s = Files.lines(p).collect(Collectors.joining("\n")); - ArrayList l = new ArrayList<>(); - ScriptUtils.splitSqlScript("a", s, ";", - ScriptUtils.DEFAULT_COMMENT_PREFIX, ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER, - ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER, l); - l.forEach(line -> { - System.out.println(line); - System.out.println("----"); - }); - - } -} From 13ea394b4fcd3d1e4e640eae31a638087c50c18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 16 Nov 2023 15:46:11 -0600 Subject: [PATCH 3/5] Apply suggestions from code review --- .../src/main/java/org/testcontainers/ext/ScriptScanner.java | 1 - .../src/test/java/org/testcontainers/ext/ScriptScannerTest.java | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptScanner.java b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptScanner.java index 1ffde4c0e29..686527e9364 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptScanner.java +++ b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptScanner.java @@ -96,7 +96,6 @@ private boolean matchesMultilineComment() { return false; } - private boolean matchesQuotedString(final char quote) { if (script.charAt(offset) == quote) { boolean escaped = false; diff --git a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java index 9dece077f50..6db57c017e3 100644 --- a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java +++ b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java @@ -8,6 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class ScriptScannerTest { + @Test public void testHugeStringLiteral() { String script = "/* a comment */ \"" + StringUtils.repeat('~', 10000) + "\";"; From d0230c9c3d236253f2df8fcb05c042a56f2a3c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 16 Nov 2023 15:48:18 -0600 Subject: [PATCH 4/5] Update modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java --- .../src/test/java/org/testcontainers/ext/ScriptScannerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java index 6db57c017e3..746d1df4d82 100644 --- a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java +++ b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java @@ -11,7 +11,7 @@ public class ScriptScannerTest { @Test public void testHugeStringLiteral() { - String script = "/* a comment */ \"" + StringUtils.repeat('~', 10000) + "\";"; + String script = "/* a comment */ \"" + StringUtils.repeat('~', 10000) + "\";"; ScriptScanner scanner = scanner(script); assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.COMMENT); assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.WHITESPACE); From 49a2094effa65a8adb8126c9aa0ef1897d660b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 16 Nov 2023 15:53:25 -0600 Subject: [PATCH 5/5] Fix format --- .../org/testcontainers/ext/ScriptScannerTest.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java index 746d1df4d82..7e24026c4ec 100644 --- a/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java +++ b/modules/database-commons/src/test/java/org/testcontainers/ext/ScriptScannerTest.java @@ -21,8 +21,10 @@ public void testHugeStringLiteral() { @Test public void testPgIdentifierWithDollarSigns() { - ScriptScanner scanner = scanner("this$is$a$valid$postgreSQL$identifier " + - "$a$While this is a quoted string$a$$ --just followed by a dollar sign"); + ScriptScanner scanner = scanner( + "this$is$a$valid$postgreSQL$identifier " + + "$a$While this is a quoted string$a$$ --just followed by a dollar sign" + ); assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.IDENTIFIER); assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.WHITESPACE); assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.QUOTED_STRING); @@ -30,7 +32,7 @@ public void testPgIdentifierWithDollarSigns() { } @Test - public void testQuotedLiterals(){ + public void testQuotedLiterals() { ScriptScanner scanner = scanner("'this \\'is a literal' \"this \\\" is a literal\""); assertThat(scanner.next()).isEqualTo(ScriptScanner.Lexem.QUOTED_STRING); assertThat(scanner.getCurrentMatch()).isEqualTo("'this \\'is a literal'"); @@ -40,11 +42,13 @@ public void testQuotedLiterals(){ } private static ScriptScanner scanner(String script) { - return new ScriptScanner("dummy", + return new ScriptScanner( + "dummy", script, ScriptUtils.DEFAULT_STATEMENT_SEPARATOR, ScriptUtils.DEFAULT_COMMENT_PREFIX, ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER, - ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER); + ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER + ); } }