@ -80,6 +80,12 @@ public abstract class ScriptUtils {
@@ -80,6 +80,12 @@ public abstract class ScriptUtils {
* /
public static final String DEFAULT_COMMENT_PREFIX = "--" ;
/ * *
* Default prefixes for single - line comments within SQL scripts : { @code [ "--" ] } .
* @since 5 . 2
* /
public static final String [ ] DEFAULT_COMMENT_PREFIXES = { DEFAULT_COMMENT_PREFIX } ;
/ * *
* Default start delimiter for block comments within SQL scripts : { @code "/*" } .
* /
@ -170,9 +176,46 @@ public abstract class ScriptUtils {
@@ -170,9 +176,46 @@ public abstract class ScriptUtils {
String separator , String commentPrefix , String blockCommentStartDelimiter ,
String blockCommentEndDelimiter , List < String > statements ) throws ScriptException {
Assert . hasText ( commentPrefix , "'commentPrefix' must not be null or empty" ) ;
splitSqlScript ( resource , script , separator , new String [ ] { commentPrefix } ,
blockCommentStartDelimiter , blockCommentEndDelimiter , statements ) ;
}
/ * *
* Split an SQL script into separate statements delimited by the provided
* separator string . Each individual statement will be added to the provided
* { @code List } .
* < p > Within the script , the provided { @code commentPrefix } will be honored :
* any text beginning with the comment prefix and extending to the end of the
* line will be omitted from the output . Similarly , the provided
* { @code blockCommentStartDelimiter } and { @code blockCommentEndDelimiter }
* delimiters will be honored : any text enclosed in a block comment will be
* omitted from the output . In addition , multiple adjacent whitespace characters
* will be collapsed into a single space .
* @param resource the resource from which the script was read
* @param script the SQL script
* @param separator text separating each statement
* ( typically a ';' or newline character )
* @param commentPrefixes the prefixes that identify SQL line comments
* ( typically "--" )
* @param blockCommentStartDelimiter the < em > start < / em > block comment delimiter ;
* never { @code null } or empty
* @param blockCommentEndDelimiter the < em > end < / em > block comment delimiter ;
* never { @code null } or empty
* @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL script
* @since 5 . 2
* /
public static void splitSqlScript ( @Nullable EncodedResource resource , String script ,
String separator , String [ ] commentPrefixes , String blockCommentStartDelimiter ,
String blockCommentEndDelimiter , List < String > statements ) throws ScriptException {
Assert . hasText ( script , "'script' must not be null or empty" ) ;
Assert . notNull ( separator , "'separator' must not be null" ) ;
Assert . hasText ( commentPrefix , "'commentPrefix' must not be null or empty" ) ;
Assert . notNull ( commentPrefixes , "'commentPrefixes' must not be null" ) ;
for ( int i = 0 ; i < commentPrefixes . length ; i + + ) {
Assert . hasText ( commentPrefixes [ i ] , "'commentPrefixes' must not contain null or empty elements" ) ;
}
Assert . hasText ( blockCommentStartDelimiter , "'blockCommentStartDelimiter' must not be null or empty" ) ;
Assert . hasText ( blockCommentEndDelimiter , "'blockCommentEndDelimiter' must not be null or empty" ) ;
@ -210,7 +253,7 @@ public abstract class ScriptUtils {
@@ -210,7 +253,7 @@ public abstract class ScriptUtils {
i + = separator . length ( ) - 1 ;
continue ;
}
else if ( script . startsWith ( commentPrefix , i ) ) {
else if ( startsWithAny ( script , commentPrefixes , i ) ) {
// Skip over any content from the start of the comment to the EOL
int indexOfNextNewline = script . indexOf ( '\n' , i ) ;
if ( indexOfNextNewline > i ) {
@ -260,7 +303,7 @@ public abstract class ScriptUtils {
@@ -260,7 +303,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 , DEFAULT_BLOCK_COMMENT_END_DELIMITER ) ;
return readScript ( resource , DEFAULT_COMMENT_PREFIXES , DEFAULT_STATEMENT_SEPARATOR , DEFAULT_BLOCK_COMMENT_END_DELIMITER ) ;
}
/ * *
@ -271,19 +314,19 @@ public abstract class ScriptUtils {
@@ -271,19 +314,19 @@ public abstract class ScriptUtils {
* a statement & mdash ; will be included in the results .
* @param resource the { @code EncodedResource } containing the script
* to be processed
* @param commentPrefix the prefix that identifies comments in the SQL script
* @param commentPrefixes the prefix that identifies comments 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
* @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 [ ] commentPrefixes ,
@Nullable String separator , @Nullable String blockCommentEndDelimiter ) throws IOException {
LineNumberReader lnr = new LineNumberReader ( resource . getReader ( ) ) ;
try {
return readScript ( lnr , commentPrefix , separator , blockCommentEndDelimiter ) ;
return readScript ( lnr , commentPrefixes , separator , blockCommentEndDelimiter ) ;
}
finally {
lnr . close ( ) ;
@ -309,11 +352,35 @@ public abstract class ScriptUtils {
@@ -309,11 +352,35 @@ public abstract class ScriptUtils {
public static String readScript ( LineNumberReader lineNumberReader , @Nullable String lineCommentPrefix ,
@Nullable String separator , @Nullable String blockCommentEndDelimiter ) throws IOException {
String [ ] lineCommentPrefixes = ( lineCommentPrefix ! = null ) ? new String [ ] { lineCommentPrefix } : null ;
return readScript ( lineNumberReader , lineCommentPrefixes , separator , blockCommentEndDelimiter ) ;
}
/ * *
* Read a script from the provided { @code LineNumberReader } , using the supplied
* comment prefix and statement separator , and build a { @code String } containing
* the lines .
* < p > Lines < em > beginning < / em > with the comment prefix are excluded from the
* results ; however , line comments anywhere else & mdash ; for example , within
* a statement & mdash ; will be included in the results .
* @param lineNumberReader the { @code LineNumberReader } containing the script
* to be processed
* @param lineCommentPrefixes the prefixes that identify comments 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
* @throws IOException in case of I / O errors
* @since 5 . 2
* /
public static String readScript ( LineNumberReader lineNumberReader , @Nullable String [ ] lineCommentPrefixes ,
@Nullable String separator , @Nullable String blockCommentEndDelimiter ) throws IOException {
String currentStatement = lineNumberReader . readLine ( ) ;
StringBuilder scriptBuilder = new StringBuilder ( ) ;
while ( currentStatement ! = null ) {
if ( ( blockCommentEndDelimiter ! = null & & currentStatement . contains ( blockCommentEndDelimiter ) ) | |
( lineCommentPrefix ! = null & & ! currentStatement . startsWith ( lineCommentPrefix ) ) ) {
( lineCommentPrefixes ! = null & & ! startsWithAny ( currentStatement , lineCommentPrefixes , 0 ) ) ) {
if ( scriptBuilder . length ( ) > 0 ) {
scriptBuilder . append ( '\n' ) ;
}
@ -340,6 +407,15 @@ public abstract class ScriptUtils {
@@ -340,6 +407,15 @@ public abstract class ScriptUtils {
}
}
private static boolean startsWithAny ( String script , String [ ] prefixes , int toffset ) {
for ( String prefix : prefixes ) {
if ( script . startsWith ( prefix , toffset ) ) {
return true ;
}
}
return false ;
}
/ * *
* Does the provided SQL script contain the specified delimiter ?
* @param script the SQL script
@ -454,6 +530,46 @@ public abstract class ScriptUtils {
@@ -454,6 +530,46 @@ public abstract class ScriptUtils {
boolean ignoreFailedDrops , String commentPrefix , @Nullable String separator ,
String blockCommentStartDelimiter , String blockCommentEndDelimiter ) throws ScriptException {
executeSqlScript ( connection , resource , continueOnError , ignoreFailedDrops ,
new String [ ] { commentPrefix } , separator , blockCommentStartDelimiter ,
blockCommentEndDelimiter ) ;
}
/ * *
* Execute the given SQL script .
* < p > Statement separators and comments will be removed before executing
* individual statements within the supplied script .
* < p > < strong > Warning < / strong > : this method does < em > not < / em > release the
* provided { @link Connection } .
* @param connection the JDBC connection to use to execute the script ; already
* configured and ready to use
* @param resource the resource ( potentially associated with a specific encoding )
* to load the SQL script from
* @param continueOnError whether or not to continue without throwing an exception
* in the event of an error
* @param ignoreFailedDrops whether or not to continue in the event of specifically
* an error on a { @code DROP } statement
* @param commentPrefixes the prefixes that identify single - line comments in the
* SQL script ( typically "--" )
* @param separator the script statement separator ; defaults to
* { @value # DEFAULT_STATEMENT_SEPARATOR } if not specified and falls back to
* { @value # FALLBACK_STATEMENT_SEPARATOR } as a last resort ; may be set to
* { @value # EOF_STATEMENT_SEPARATOR } to signal that the script contains a
* single statement without a separator
* @param blockCommentStartDelimiter the < em > start < / em > block comment delimiter
* @param blockCommentEndDelimiter the < em > end < / em > block comment delimiter
* @throws ScriptException if an error occurred while executing the SQL script
* @since 5 . 2
* @see # DEFAULT_STATEMENT_SEPARATOR
* @see # FALLBACK_STATEMENT_SEPARATOR
* @see # EOF_STATEMENT_SEPARATOR
* @see org . springframework . jdbc . datasource . DataSourceUtils # getConnection
* @see org . springframework . jdbc . datasource . DataSourceUtils # releaseConnection
* /
public static void executeSqlScript ( Connection connection , EncodedResource resource , boolean continueOnError ,
boolean ignoreFailedDrops , String [ ] commentPrefixes , @Nullable String separator ,
String blockCommentStartDelimiter , String blockCommentEndDelimiter ) throws ScriptException {
try {
if ( logger . isDebugEnabled ( ) ) {
logger . debug ( "Executing SQL script from " + resource ) ;
@ -462,7 +578,7 @@ public abstract class ScriptUtils {
@@ -462,7 +578,7 @@ public abstract class ScriptUtils {
String script ;
try {
script = readScript ( resource , commentPrefix , separator , blockCommentEndDelimiter ) ;
script = readScript ( resource , commentPrefixes , separator , blockCommentEndDelimiter ) ;
}
catch ( IOException ex ) {
throw new CannotReadScriptException ( resource , ex ) ;
@ -476,7 +592,7 @@ public abstract class ScriptUtils {
@@ -476,7 +592,7 @@ public abstract class ScriptUtils {
}
List < String > statements = new ArrayList < > ( ) ;
splitSqlScript ( resource , script , separator , commentPrefix , blockCommentStartDelimiter ,
splitSqlScript ( resource , script , separator , commentPrefixes , blockCommentStartDelimiter ,
blockCommentEndDelimiter , statements ) ;
int stmtNumber = 0 ;