From 82dbde13b67ffbd6bbcbef9ecf01ef18c236271f Mon Sep 17 00:00:00 2001 From: Mansur Mustaquim Date: Fri, 8 Feb 2019 20:20:51 +0500 Subject: [PATCH] Fix for ScriptUtils failure when '--' occurs inside a multi-line comment on the same line as '*/' (#22392) * Test for multi-line comment block where the comment end delimiter occurs on a line starting with the single-line comment prefix * ScriptUtils successfully parses a SQL script containing a multi-line comment block where the comment-end delimiter occurs on a line starting with the single-line comment prefix. --- .../jdbc/datasource/init/ScriptUtils.java | 19 ++++++++------- .../datasource/init/ScriptUtilsUnitTests.java | 14 +++++++++++ ...t-data-with-multi-line-nested-comments.sql | 23 +++++++++++++++++++ 3 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 spring-jdbc/src/test/resources/org/springframework/jdbc/datasource/init/test-data-with-multi-line-nested-comments.sql diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptUtils.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptUtils.java index 863280ede0b..d9f3167d847 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptUtils.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptUtils.java @@ -259,7 +259,7 @@ public abstract class ScriptUtils { * @throws IOException in case of I/O errors */ static String readScript(EncodedResource resource) throws IOException { - return readScript(resource, DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR); + return readScript(resource, DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, DEFAULT_BLOCK_COMMENT_END_DELIMITER); } /** @@ -273,15 +273,16 @@ public abstract class ScriptUtils { * @param commentPrefix the prefix that identifies comments in the SQL script — * typically "--" * @param separator the statement separator in the SQL script — typically ";" + * @param blockCommentEndDelimiter the end block comment delimiter * @return a {@code String} containing the script lines * @throws IOException in case of I/O errors */ private static String readScript(EncodedResource resource, @Nullable String commentPrefix, - @Nullable String separator) throws IOException { + @Nullable String separator, @Nullable String blockCommentEndDelimiter) throws IOException { LineNumberReader lnr = new LineNumberReader(resource.getReader()); try { - return readScript(lnr, commentPrefix, separator); + return readScript(lnr, commentPrefix, separator, blockCommentEndDelimiter); } finally { lnr.close(); @@ -297,19 +298,21 @@ public abstract class ScriptUtils { * a statement — will be included in the results. * @param lineNumberReader the {@code LineNumberReader} containing the script * to be processed - * @param commentPrefix the prefix that identifies comments in the SQL script — + * @param lineCommentPrefix the prefix that identifies comments in the SQL script — * typically "--" * @param separator the statement separator in the SQL script — typically ";" + * @param blockCommentEndDelimiter the end block comment delimiter * @return a {@code String} containing the script lines * @throws IOException in case of I/O errors */ - public static String readScript(LineNumberReader lineNumberReader, @Nullable String commentPrefix, - @Nullable String separator) throws IOException { + public static String readScript(LineNumberReader lineNumberReader, @Nullable String lineCommentPrefix, + @Nullable String separator, @Nullable String blockCommentEndDelimiter) throws IOException { String currentStatement = lineNumberReader.readLine(); StringBuilder scriptBuilder = new StringBuilder(); while (currentStatement != null) { - if (commentPrefix != null && !currentStatement.startsWith(commentPrefix)) { + if ((blockCommentEndDelimiter != null && currentStatement.contains(blockCommentEndDelimiter)) || + (lineCommentPrefix != null && !currentStatement.startsWith(lineCommentPrefix))) { if (scriptBuilder.length() > 0) { scriptBuilder.append('\n'); } @@ -460,7 +463,7 @@ public abstract class ScriptUtils { String script; try { - script = readScript(resource, commentPrefix, separator); + script = readScript(resource, commentPrefix, separator, blockCommentEndDelimiter); } catch (IOException ex) { throw new CannotReadScriptException(resource, ex); diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/datasource/init/ScriptUtilsUnitTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/datasource/init/ScriptUtilsUnitTests.java index 80f44ff57fb..b55ab143020 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/datasource/init/ScriptUtilsUnitTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/datasource/init/ScriptUtilsUnitTests.java @@ -162,6 +162,20 @@ public class ScriptUtilsUnitTests { assertEquals("statement 2 not split correctly", statement2, statements.get(1)); } + @Test + public void readAndSplitScriptContainingMultiLineNestedComments() throws Exception { + String script = readScript("test-data-with-multi-line-nested-comments.sql"); + List statements = new ArrayList<>(); + splitSqlScript(script, ';', statements); + + String statement1 = "INSERT INTO users(first_name, last_name) VALUES('Juergen', 'Hoeller')"; + String statement2 = "INSERT INTO users(first_name, last_name) VALUES( 'Sam' , 'Brannen' )"; + + assertEquals("wrong number of statements", 2, statements.size()); + assertEquals("statement 1 not split correctly", statement1, statements.get(0)); + assertEquals("statement 2 not split correctly", statement2, statements.get(1)); + } + @Test public void containsDelimiters() { assertFalse(containsSqlScriptDelimiters("select 1\n select ';'", ";")); diff --git a/spring-jdbc/src/test/resources/org/springframework/jdbc/datasource/init/test-data-with-multi-line-nested-comments.sql b/spring-jdbc/src/test/resources/org/springframework/jdbc/datasource/init/test-data-with-multi-line-nested-comments.sql new file mode 100644 index 00000000000..8c1e1174b73 --- /dev/null +++ b/spring-jdbc/src/test/resources/org/springframework/jdbc/datasource/init/test-data-with-multi-line-nested-comments.sql @@ -0,0 +1,23 @@ +/* This is a multi line comment + * The next comment line has no text + + * The next comment line starts with a space. + * x, y, z... + */ + +INSERT INTO users(first_name, last_name) VALUES('Juergen', 'Hoeller'); +-- This is also a comment. +/*------------------------------------------- +-- A fancy multi-line comments that puts +-- single line comments inside of a multi-line +-- comment block. +Moreover, the block commend end delimiter +appears on a line that can potentially also +be a single-line comment if we weren't +already inside a multi-line comment run. +-------------------------------------------*/ + INSERT INTO +users(first_name, last_name) -- This is a single line comment containing the block-end-comment sequence here */ but it's still a single-line comment +VALUES( 'Sam' -- first_name + , 'Brannen' -- last_name +);-- \ No newline at end of file