@@ -80,6 +80,12 @@ public abstract class ScriptUtils {
80
80
*/
81
81
public static final String DEFAULT_COMMENT_PREFIX = "--" ;
82
82
83
+ /**
84
+ * Default prefixes for single-line comments within SQL scripts: {@code ["--"]}.
85
+ * @since 5.2
86
+ */
87
+ public static final String [] DEFAULT_COMMENT_PREFIXES = { DEFAULT_COMMENT_PREFIX };
88
+
83
89
/**
84
90
* Default start delimiter for block comments within SQL scripts: {@code "/*"}.
85
91
*/
@@ -170,9 +176,46 @@ public static void splitSqlScript(@Nullable EncodedResource resource, String scr
170
176
String separator , String commentPrefix , String blockCommentStartDelimiter ,
171
177
String blockCommentEndDelimiter , List <String > statements ) throws ScriptException {
172
178
179
+ Assert .hasText (commentPrefix , "'commentPrefix' must not be null or empty" );
180
+ splitSqlScript (resource , script , separator , new String [] { commentPrefix },
181
+ blockCommentStartDelimiter , blockCommentEndDelimiter , statements );
182
+ }
183
+
184
+ /**
185
+ * Split an SQL script into separate statements delimited by the provided
186
+ * separator string. Each individual statement will be added to the provided
187
+ * {@code List}.
188
+ * <p>Within the script, the provided {@code commentPrefix} will be honored:
189
+ * any text beginning with the comment prefix and extending to the end of the
190
+ * line will be omitted from the output. Similarly, the provided
191
+ * {@code blockCommentStartDelimiter} and {@code blockCommentEndDelimiter}
192
+ * delimiters will be honored: any text enclosed in a block comment will be
193
+ * omitted from the output. In addition, multiple adjacent whitespace characters
194
+ * will be collapsed into a single space.
195
+ * @param resource the resource from which the script was read
196
+ * @param script the SQL script
197
+ * @param separator text separating each statement
198
+ * (typically a ';' or newline character)
199
+ * @param commentPrefixes the prefixes that identify SQL line comments
200
+ * (typically "--")
201
+ * @param blockCommentStartDelimiter the <em>start</em> block comment delimiter;
202
+ * never {@code null} or empty
203
+ * @param blockCommentEndDelimiter the <em>end</em> block comment delimiter;
204
+ * never {@code null} or empty
205
+ * @param statements the list that will contain the individual statements
206
+ * @throws ScriptException if an error occurred while splitting the SQL script
207
+ * @since 5.2
208
+ */
209
+ public static void splitSqlScript (@ Nullable EncodedResource resource , String script ,
210
+ String separator , String [] commentPrefixes , String blockCommentStartDelimiter ,
211
+ String blockCommentEndDelimiter , List <String > statements ) throws ScriptException {
212
+
173
213
Assert .hasText (script , "'script' must not be null or empty" );
174
214
Assert .notNull (separator , "'separator' must not be null" );
175
- Assert .hasText (commentPrefix , "'commentPrefix' must not be null or empty" );
215
+ Assert .notNull (commentPrefixes , "'commentPrefixes' must not be null" );
216
+ for (int i = 0 ; i < commentPrefixes .length ; i ++) {
217
+ Assert .hasText (commentPrefixes [i ], "'commentPrefixes' must not contain null or empty elements" );
218
+ }
176
219
Assert .hasText (blockCommentStartDelimiter , "'blockCommentStartDelimiter' must not be null or empty" );
177
220
Assert .hasText (blockCommentEndDelimiter , "'blockCommentEndDelimiter' must not be null or empty" );
178
221
@@ -210,7 +253,7 @@ else if (!inSingleQuote && (c == '"')) {
210
253
i += separator .length () - 1 ;
211
254
continue ;
212
255
}
213
- else if (script . startsWith ( commentPrefix , i )) {
256
+ else if (startsWithAny ( script , commentPrefixes , i )) {
214
257
// Skip over any content from the start of the comment to the EOL
215
258
int indexOfNextNewline = script .indexOf ('\n' , i );
216
259
if (indexOfNextNewline > i ) {
@@ -260,7 +303,7 @@ else if (c == ' ' || c == '\r' || c == '\n' || c == '\t') {
260
303
* @throws IOException in case of I/O errors
261
304
*/
262
305
static String readScript (EncodedResource resource ) throws IOException {
263
- return readScript (resource , DEFAULT_COMMENT_PREFIX , DEFAULT_STATEMENT_SEPARATOR , DEFAULT_BLOCK_COMMENT_END_DELIMITER );
306
+ return readScript (resource , DEFAULT_COMMENT_PREFIXES , DEFAULT_STATEMENT_SEPARATOR , DEFAULT_BLOCK_COMMENT_END_DELIMITER );
264
307
}
265
308
266
309
/**
@@ -271,19 +314,19 @@ static String readScript(EncodedResource resource) throws IOException {
271
314
* a statement — will be included in the results.
272
315
* @param resource the {@code EncodedResource} containing the script
273
316
* to be processed
274
- * @param commentPrefix the prefix that identifies comments in the SQL script
317
+ * @param commentPrefixes the prefix that identifies comments in the SQL script
275
318
* (typically "--")
276
319
* @param separator the statement separator in the SQL script (typically ";")
277
320
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
278
321
* @return a {@code String} containing the script lines
279
322
* @throws IOException in case of I/O errors
280
323
*/
281
- private static String readScript (EncodedResource resource , @ Nullable String commentPrefix ,
324
+ private static String readScript (EncodedResource resource , @ Nullable String [] commentPrefixes ,
282
325
@ Nullable String separator , @ Nullable String blockCommentEndDelimiter ) throws IOException {
283
326
284
327
LineNumberReader lnr = new LineNumberReader (resource .getReader ());
285
328
try {
286
- return readScript (lnr , commentPrefix , separator , blockCommentEndDelimiter );
329
+ return readScript (lnr , commentPrefixes , separator , blockCommentEndDelimiter );
287
330
}
288
331
finally {
289
332
lnr .close ();
@@ -309,11 +352,35 @@ private static String readScript(EncodedResource resource, @Nullable String comm
309
352
public static String readScript (LineNumberReader lineNumberReader , @ Nullable String lineCommentPrefix ,
310
353
@ Nullable String separator , @ Nullable String blockCommentEndDelimiter ) throws IOException {
311
354
355
+ String [] lineCommentPrefixes = (lineCommentPrefix != null ) ? new String [] { lineCommentPrefix } : null ;
356
+ return readScript (lineNumberReader , lineCommentPrefixes , separator , blockCommentEndDelimiter );
357
+ }
358
+
359
+ /**
360
+ * Read a script from the provided {@code LineNumberReader}, using the supplied
361
+ * comment prefix and statement separator, and build a {@code String} containing
362
+ * the lines.
363
+ * <p>Lines <em>beginning</em> with the comment prefix are excluded from the
364
+ * results; however, line comments anywhere else — for example, within
365
+ * a statement — will be included in the results.
366
+ * @param lineNumberReader the {@code LineNumberReader} containing the script
367
+ * to be processed
368
+ * @param lineCommentPrefixes the prefixes that identify comments in the SQL script
369
+ * (typically "--")
370
+ * @param separator the statement separator in the SQL script (typically ";")
371
+ * @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
372
+ * @return a {@code String} containing the script lines
373
+ * @throws IOException in case of I/O errors
374
+ * @since 5.2
375
+ */
376
+ public static String readScript (LineNumberReader lineNumberReader , @ Nullable String [] lineCommentPrefixes ,
377
+ @ Nullable String separator , @ Nullable String blockCommentEndDelimiter ) throws IOException {
378
+
312
379
String currentStatement = lineNumberReader .readLine ();
313
380
StringBuilder scriptBuilder = new StringBuilder ();
314
381
while (currentStatement != null ) {
315
382
if ((blockCommentEndDelimiter != null && currentStatement .contains (blockCommentEndDelimiter )) ||
316
- (lineCommentPrefix != null && !currentStatement . startsWith ( lineCommentPrefix ))) {
383
+ (lineCommentPrefixes != null && !startsWithAny ( currentStatement , lineCommentPrefixes , 0 ))) {
317
384
if (scriptBuilder .length () > 0 ) {
318
385
scriptBuilder .append ('\n' );
319
386
}
@@ -340,6 +407,15 @@ private static void appendSeparatorToScriptIfNecessary(StringBuilder scriptBuild
340
407
}
341
408
}
342
409
410
+ private static boolean startsWithAny (String script , String [] prefixes , int toffset ) {
411
+ for (String prefix : prefixes ) {
412
+ if (script .startsWith (prefix , toffset )) {
413
+ return true ;
414
+ }
415
+ }
416
+ return false ;
417
+ }
418
+
343
419
/**
344
420
* Does the provided SQL script contain the specified delimiter?
345
421
* @param script the SQL script
@@ -454,6 +530,46 @@ public static void executeSqlScript(Connection connection, EncodedResource resou
454
530
boolean ignoreFailedDrops , String commentPrefix , @ Nullable String separator ,
455
531
String blockCommentStartDelimiter , String blockCommentEndDelimiter ) throws ScriptException {
456
532
533
+ executeSqlScript (connection , resource , continueOnError , ignoreFailedDrops ,
534
+ new String [] { commentPrefix }, separator , blockCommentStartDelimiter ,
535
+ blockCommentEndDelimiter );
536
+ }
537
+
538
+ /**
539
+ * Execute the given SQL script.
540
+ * <p>Statement separators and comments will be removed before executing
541
+ * individual statements within the supplied script.
542
+ * <p><strong>Warning</strong>: this method does <em>not</em> release the
543
+ * provided {@link Connection}.
544
+ * @param connection the JDBC connection to use to execute the script; already
545
+ * configured and ready to use
546
+ * @param resource the resource (potentially associated with a specific encoding)
547
+ * to load the SQL script from
548
+ * @param continueOnError whether or not to continue without throwing an exception
549
+ * in the event of an error
550
+ * @param ignoreFailedDrops whether or not to continue in the event of specifically
551
+ * an error on a {@code DROP} statement
552
+ * @param commentPrefixes the prefixes that identify single-line comments in the
553
+ * SQL script (typically "--")
554
+ * @param separator the script statement separator; defaults to
555
+ * {@value #DEFAULT_STATEMENT_SEPARATOR} if not specified and falls back to
556
+ * {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort; may be set to
557
+ * {@value #EOF_STATEMENT_SEPARATOR} to signal that the script contains a
558
+ * single statement without a separator
559
+ * @param blockCommentStartDelimiter the <em>start</em> block comment delimiter
560
+ * @param blockCommentEndDelimiter the <em>end</em> block comment delimiter
561
+ * @throws ScriptException if an error occurred while executing the SQL script
562
+ * @since 5.2
563
+ * @see #DEFAULT_STATEMENT_SEPARATOR
564
+ * @see #FALLBACK_STATEMENT_SEPARATOR
565
+ * @see #EOF_STATEMENT_SEPARATOR
566
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
567
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
568
+ */
569
+ public static void executeSqlScript (Connection connection , EncodedResource resource , boolean continueOnError ,
570
+ boolean ignoreFailedDrops , String [] commentPrefixes , @ Nullable String separator ,
571
+ String blockCommentStartDelimiter , String blockCommentEndDelimiter ) throws ScriptException {
572
+
457
573
try {
458
574
if (logger .isDebugEnabled ()) {
459
575
logger .debug ("Executing SQL script from " + resource );
@@ -462,7 +578,7 @@ public static void executeSqlScript(Connection connection, EncodedResource resou
462
578
463
579
String script ;
464
580
try {
465
- script = readScript (resource , commentPrefix , separator , blockCommentEndDelimiter );
581
+ script = readScript (resource , commentPrefixes , separator , blockCommentEndDelimiter );
466
582
}
467
583
catch (IOException ex ) {
468
584
throw new CannotReadScriptException (resource , ex );
@@ -476,7 +592,7 @@ public static void executeSqlScript(Connection connection, EncodedResource resou
476
592
}
477
593
478
594
List <String > statements = new ArrayList <>();
479
- splitSqlScript (resource , script , separator , commentPrefix , blockCommentStartDelimiter ,
595
+ splitSqlScript (resource , script , separator , commentPrefixes , blockCommentStartDelimiter ,
480
596
blockCommentEndDelimiter , statements );
481
597
482
598
int stmtNumber = 0 ;
0 commit comments