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.
This commit is contained in:
Mansur Mustaquim 2019-02-08 20:20:51 +05:00 committed by Juergen Hoeller
parent a698adf125
commit 82dbde13b6
3 changed files with 48 additions and 8 deletions

View File

@ -259,7 +259,7 @@ public abstract class ScriptUtils {
* @throws IOException in case of I/O errors * @throws IOException in case of I/O errors
*/ */
static String readScript(EncodedResource resource) throws IOException { 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 — * @param commentPrefix the prefix that identifies comments in the SQL script —
* typically "--" * typically "--"
* @param separator the statement separator in the SQL script — typically ";" * @param separator the statement separator in the SQL script — typically ";"
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
* @return a {@code String} containing the script lines * @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors * @throws IOException in case of I/O errors
*/ */
private static String readScript(EncodedResource resource, @Nullable String commentPrefix, 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()); LineNumberReader lnr = new LineNumberReader(resource.getReader());
try { try {
return readScript(lnr, commentPrefix, separator); return readScript(lnr, commentPrefix, separator, blockCommentEndDelimiter);
} }
finally { finally {
lnr.close(); lnr.close();
@ -297,19 +298,21 @@ public abstract class ScriptUtils {
* a statement &mdash; will be included in the results. * a statement &mdash; will be included in the results.
* @param lineNumberReader the {@code LineNumberReader} containing the script * @param lineNumberReader the {@code LineNumberReader} containing the script
* to be processed * to be processed
* @param commentPrefix the prefix that identifies comments in the SQL script &mdash; * @param lineCommentPrefix the prefix that identifies comments in the SQL script &mdash;
* typically "--" * typically "--"
* @param separator the statement separator in the SQL script &mdash; typically ";" * @param separator the statement separator in the SQL script &mdash; typically ";"
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
* @return a {@code String} containing the script lines * @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors * @throws IOException in case of I/O errors
*/ */
public static String readScript(LineNumberReader lineNumberReader, @Nullable String commentPrefix, public static String readScript(LineNumberReader lineNumberReader, @Nullable String lineCommentPrefix,
@Nullable String separator) throws IOException { @Nullable String separator, @Nullable String blockCommentEndDelimiter) throws IOException {
String currentStatement = lineNumberReader.readLine(); String currentStatement = lineNumberReader.readLine();
StringBuilder scriptBuilder = new StringBuilder(); StringBuilder scriptBuilder = new StringBuilder();
while (currentStatement != null) { while (currentStatement != null) {
if (commentPrefix != null && !currentStatement.startsWith(commentPrefix)) { if ((blockCommentEndDelimiter != null && currentStatement.contains(blockCommentEndDelimiter)) ||
(lineCommentPrefix != null && !currentStatement.startsWith(lineCommentPrefix))) {
if (scriptBuilder.length() > 0) { if (scriptBuilder.length() > 0) {
scriptBuilder.append('\n'); scriptBuilder.append('\n');
} }
@ -460,7 +463,7 @@ public abstract class ScriptUtils {
String script; String script;
try { try {
script = readScript(resource, commentPrefix, separator); script = readScript(resource, commentPrefix, separator, blockCommentEndDelimiter);
} }
catch (IOException ex) { catch (IOException ex) {
throw new CannotReadScriptException(resource, ex); throw new CannotReadScriptException(resource, ex);

View File

@ -162,6 +162,20 @@ public class ScriptUtilsUnitTests {
assertEquals("statement 2 not split correctly", statement2, statements.get(1)); 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<String> 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 @Test
public void containsDelimiters() { public void containsDelimiters() {
assertFalse(containsSqlScriptDelimiters("select 1\n select ';'", ";")); assertFalse(containsSqlScriptDelimiters("select 1\n select ';'", ";"));

View File

@ -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
);--