"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptUtils.java" between
spring-framework-5.3.7.tar.gz and spring-framework-5.3.8.tar.gz

About: Spring Framework is an application framework for the Java platform and .NET Framework. Community edition.

ScriptUtils.java  (spring-framework-5.3.7):ScriptUtils.java  (spring-framework-5.3.8)
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* https://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
skipping to change at line 38 skipping to change at line 38
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource; import org.springframework.core.io.support.EncodedResource;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* Generic utility methods for working with SQL scripts. * Generic utility methods for working with SQL scripts in conjunction with JDBC .
* *
* <p>Mainly for internal use within the framework. * <p>Mainly for internal use within the framework.
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Sam Brannen * @author Sam Brannen
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Keith Donald * @author Keith Donald
* @author Dave Syer * @author Dave Syer
* @author Chris Beams * @author Chris Beams
* @author Oliver Gierke * @author Oliver Gierke
* @author Chris Baldwin * @author Chris Baldwin
* @author Nicolas Debeissat * @author Nicolas Debeissat
* @author Phillip Webb * @author Phillip Webb
* @since 4.0.3 * @since 4.0.3
* @see org.springframework.r2dbc.connection.init.ScriptUtils
*/ */
public abstract class ScriptUtils { public abstract class ScriptUtils {
/** /**
* Default statement separator within SQL scripts: {@code ";"}. * Default statement separator within SQL scripts: {@code ";"}.
*/ */
public static final String DEFAULT_STATEMENT_SEPARATOR = ";"; public static final String DEFAULT_STATEMENT_SEPARATOR = ";";
/** /**
* Fallback statement separator within SQL scripts: {@code "\n"}. * Fallback statement separator within SQL scripts: {@code "\n"}.
skipping to change at line 103 skipping to change at line 104
public static final String DEFAULT_BLOCK_COMMENT_START_DELIMITER = "/*"; public static final String DEFAULT_BLOCK_COMMENT_START_DELIMITER = "/*";
/** /**
* Default end delimiter for block comments within SQL scripts: <code>"*& #47;"</code>. * Default end delimiter for block comments within SQL scripts: <code>"*& #47;"</code>.
*/ */
public static final String DEFAULT_BLOCK_COMMENT_END_DELIMITER = "*/"; public static final String DEFAULT_BLOCK_COMMENT_END_DELIMITER = "*/";
private static final Log logger = LogFactory.getLog(ScriptUtils.class); private static final Log logger = LogFactory.getLog(ScriptUtils.class);
/** /**
* Execute the given SQL script using default settings for statement
* separators, comment delimiters, and exception handling flags.
* <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; al
ready
* configured and ready to use
* @param resource the resource to load the SQL script from; encoded with
the
* current platform's default encoding
* @throws ScriptException if an error occurred while executing the SQL s
cript
* @see #executeSqlScript(Connection, EncodedResource, boolean, boolean,
String, String, String, String)
* @see #DEFAULT_STATEMENT_SEPARATOR
* @see #DEFAULT_COMMENT_PREFIX
* @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER
* @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnec
tion
*/
public static void executeSqlScript(Connection connection, Resource resou
rce) throws ScriptException {
executeSqlScript(connection, new EncodedResource(resource));
}
/**
* Execute the given SQL script using default settings for statement
* separators, comment delimiters, and exception handling flags.
* <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; al
ready
* configured and ready to use
* @param resource the resource (potentially associated with a specific e
ncoding)
* to load the SQL script from
* @throws ScriptException if an error occurred while executing the SQL s
cript
* @see #executeSqlScript(Connection, EncodedResource, boolean, boolean,
String, String, String, String)
* @see #DEFAULT_STATEMENT_SEPARATOR
* @see #DEFAULT_COMMENT_PREFIX
* @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER
* @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnec
tion
*/
public static void executeSqlScript(Connection connection, EncodedResourc
e resource) throws ScriptException {
executeSqlScript(connection, resource, false, false, DEFAULT_COMM
ENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR,
DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BL
OCK_COMMENT_END_DELIMITER);
}
/**
* 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; al
ready
* configured and ready to use
* @param resource the resource (potentially associated with a specific e
ncoding)
* 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 sp
ecifically
* an error on a {@code DROP} statement
* @param commentPrefix the prefix that identifies single-line comments i
n 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 del
imiter
* @param blockCommentEndDelimiter the <em>end</em> block comment delimit
er
* @throws ScriptException if an error occurred while executing the SQL s
cript
* @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#releaseConnec
tion
*/
public static void executeSqlScript(Connection connection, EncodedResourc
e resource, boolean continueOnError,
boolean ignoreFailedDrops, String commentPrefix, @Nullabl
e String separator,
String blockCommentStartDelimiter, String blockCommentEnd
Delimiter) throws ScriptException {
executeSqlScript(connection, resource, continueOnError, ignoreFai
ledDrops,
new String[] { commentPrefix }, separator, blockC
ommentStartDelimiter,
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; al
ready
* configured and ready to use
* @param resource the resource (potentially associated with a specific e
ncoding)
* 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 sp
ecifically
* 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 del
imiter
* @param blockCommentEndDelimiter the <em>end</em> block comment delimit
er
* @throws ScriptException if an error occurred while executing the SQL s
cript
* @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#releaseConnec
tion
*/
public static void executeSqlScript(Connection connection, EncodedResourc
e resource, boolean continueOnError,
boolean ignoreFailedDrops, String[] commentPrefixes, @Nul
lable String separator,
String blockCommentStartDelimiter, String blockCommentEnd
Delimiter) throws ScriptException {
try {
if (logger.isDebugEnabled()) {
logger.debug("Executing SQL script from " + resou
rce);
}
long startTime = System.currentTimeMillis();
String script;
try {
script = readScript(resource, separator, commentP
refixes, blockCommentEndDelimiter);
}
catch (IOException ex) {
throw new CannotReadScriptException(resource, ex)
;
}
if (separator == null) {
separator = DEFAULT_STATEMENT_SEPARATOR;
}
if (!EOF_STATEMENT_SEPARATOR.equals(separator) &&
!containsStatementSeparator(resource, scr
ipt, separator, commentPrefixes,
blockCommentStartDelimiter, block
CommentEndDelimiter)) {
separator = FALLBACK_STATEMENT_SEPARATOR;
}
List<String> statements = new ArrayList<>();
splitSqlScript(resource, script, separator, commentPrefix
es, blockCommentStartDelimiter,
blockCommentEndDelimiter, statements);
int stmtNumber = 0;
Statement stmt = connection.createStatement();
try {
for (String statement : statements) {
stmtNumber++;
try {
stmt.execute(statement);
int rowsAffected = stmt.getUpdate
Count();
if (logger.isDebugEnabled()) {
logger.debug(rowsAffected
+ " returned as update count for SQL: " + statement);
SQLWarning warningToLog =
stmt.getWarnings();
while (warningToLog != nu
ll) {
logger.debug("SQL
Warning ignored: SQL state '" + warningToLog.getSQLState() +
"
', error code '" + warningToLog.getErrorCode() +
"
', message [" + warningToLog.getMessage() + "]");
warningToLog = wa
rningToLog.getNextWarning();
}
}
}
catch (SQLException ex) {
boolean dropStatement = StringUti
ls.startsWithIgnoreCase(statement.trim(), "drop");
if (continueOnError || (dropState
ment && ignoreFailedDrops)) {
if (logger.isDebugEnabled
()) {
logger.debug(Scri
ptStatementFailedException.buildErrorMessage(statement, stmtNumber, resource), e
x);
}
}
else {
throw new ScriptStatement
FailedException(statement, stmtNumber, resource, ex);
}
}
}
}
finally {
try {
stmt.close();
}
catch (Throwable ex) {
logger.trace("Could not close JDBC Statem
ent", ex);
}
}
long elapsedTime = System.currentTimeMillis() - startTime
;
if (logger.isDebugEnabled()) {
logger.debug("Executed SQL script from " + resour
ce + " in " + elapsedTime + " ms.");
}
}
catch (Exception ex) {
if (ex instanceof ScriptException) {
throw (ScriptException) ex;
}
throw new UncategorizedScriptException(
"Failed to execute database script from resource
[" + resource + "]", ex);
}
}
/**
* Read a script from the provided resource, using the supplied comment p
refixes
* and statement separator, and build a {@code String} containing the lin
es.
* <p>Lines <em>beginning</em> with one of the comment prefixes are exclu
ded
* from the results; however, line comments anywhere else &mdash; for exa
mple,
* within a statement &mdash; will be included in the results.
* @param resource the {@code EncodedResource} containing the script
* to be processed
* @param separator the statement separator in the SQL script (typically
";")
* @param commentPrefixes the prefixes that identify comments in the SQL
script
* (typically "--")
* @param blockCommentEndDelimiter the <em>end</em> block comment delimit
er
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
*/
static String readScript(EncodedResource resource, @Nullable String separ
ator,
String[] commentPrefixes, String blockCommentEndDelimiter
) throws IOException {
try (LineNumberReader lnr = new LineNumberReader(resource.getRead
er())) {
return readScript(lnr, commentPrefixes, separator, blockC
ommentEndDelimiter);
}
}
/**
* Read a script from the provided {@code LineNumberReader}, using the su
pplied
* comment prefix and statement separator, and build a {@code String} con
taining
* the lines.
* <p>Lines <em>beginning</em> with the comment prefix are excluded from
the
* results; however, line comments anywhere else &mdash; for example, wit
hin
* a statement &mdash; will be included in the results.
* @param lineNumberReader the {@code LineNumberReader} containing the sc
ript
* to be processed
* @param commentPrefix the prefix that identifies comments in the SQL sc
ript
* (typically "--")
* @param separator the statement separator in the SQL script (typically
";")
* @param blockCommentEndDelimiter the <em>end</em> block comment delimit
er
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
* @deprecated as of Spring Framework 5.2.16 with no plans for replacemen
t.
* This is an internal API and will likely be removed in Spring Framework
6.0.
*/
@Deprecated
public static String readScript(LineNumberReader lineNumberReader, @Nulla
ble String commentPrefix,
@Nullable String separator, @Nullable String blockComment
EndDelimiter) throws IOException {
String[] commentPrefixes = (commentPrefix != null) ? new String[]
{ commentPrefix } : null;
return readScript(lineNumberReader, commentPrefixes, separator, b
lockCommentEndDelimiter);
}
/**
* Read a script from the provided {@code LineNumberReader}, using the su
pplied
* comment prefixes and statement separator, and build a {@code String} c
ontaining
* the lines.
* <p>Lines <em>beginning</em> with one of the comment prefixes are exclu
ded
* from the results; however, line comments anywhere else &mdash; for exa
mple,
* within a statement &mdash; will be included in the results.
* @param lineNumberReader the {@code LineNumberReader} containing the sc
ript
* to be processed
* @param commentPrefixes 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 delimit
er
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
* @since 5.2
* @deprecated as of Spring Framework 5.2.16 with no plans for replacemen
t.
* This is an internal API and will likely be removed in Spring Framework
6.0.
*/
@Deprecated
public static String readScript(LineNumberReader lineNumberReader, @Nulla
ble String[] commentPrefixes,
@Nullable String separator, @Nullable String blockComment
EndDelimiter) throws IOException {
String currentStatement = lineNumberReader.readLine();
StringBuilder scriptBuilder = new StringBuilder();
while (currentStatement != null) {
if ((blockCommentEndDelimiter != null && currentStatement
.contains(blockCommentEndDelimiter)) ||
(commentPrefixes != null && !startsWithAny(curren
tStatement, commentPrefixes, 0))) {
if (scriptBuilder.length() > 0) {
scriptBuilder.append('\n');
}
scriptBuilder.append(currentStatement);
}
currentStatement = lineNumberReader.readLine();
}
appendSeparatorToScriptIfNecessary(scriptBuilder, separator);
return scriptBuilder.toString();
}
private static void appendSeparatorToScriptIfNecessary(StringBuilder scri
ptBuilder, @Nullable String separator) {
if (separator == null) {
return;
}
String trimmed = separator.trim();
if (trimmed.length() == separator.length()) {
return;
}
// separator ends in whitespace, so we might want to see if the s
cript is trying
// to end the same way
if (scriptBuilder.lastIndexOf(trimmed) == scriptBuilder.length()
- trimmed.length()) {
scriptBuilder.append(separator.substring(trimmed.length()
));
}
}
/**
* Determine if the provided SQL script contains the specified delimiter.
* <p>This method is intended to be used to find the string delimiting ea
ch
* SQL statement &mdash; for example, a ';' character.
* <p>Any occurrence of the delimiter within the script will be ignored i
f it
* is within a <em>literal</em> block of text enclosed in single quotes
* ({@code '}) or double quotes ({@code "}), if it is escaped with a back
slash
* ({@code \}), or if it is within a single-line comment or block comment
.
* @param script the SQL script to search within
* @param delimiter the statement delimiter to search for
* @see #DEFAULT_COMMENT_PREFIXES
* @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER
* @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER
* @deprecated as of Spring Framework 5.2.16 with no plans for replacemen
t.
* This is an internal API and will likely be removed in Spring Framework
6.0.
*/
@Deprecated
public static boolean containsSqlScriptDelimiters(String script, String d
elimiter) {
return containsStatementSeparator(null, script, delimiter, DEFAUL
T_COMMENT_PREFIXES,
DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMM
ENT_END_DELIMITER);
}
/**
* Determine if the provided SQL script contains the specified statement
separator.
* <p>This method is intended to be used to find the string separating ea
ch
* SQL statement &mdash; for example, a ';' character.
* <p>Any occurrence of the separator within the script will be ignored i
f it
* is within a <em>literal</em> block of text enclosed in single quotes
* ({@code '}) or double quotes ({@code "}), if it is escaped with a back
slash
* ({@code \}), or if it is within a single-line comment or block comment
.
* @param resource the resource from which the script was read, or {@code
null}
* if unknown
* @param script the SQL script to search within
* @param separator the statement separator to search for
* @param commentPrefixes the prefixes that identify single-line comments
* (typically {@code "--"})
* @param blockCommentStartDelimiter the <em>start</em> block comment del
imiter
* (typically {@code "/*"})
* @param blockCommentEndDelimiter the <em>end</em> block comment delimit
er
* (typically <code>"*&#47;"</code>)
* @since 5.2.16
*/
private static boolean containsStatementSeparator(@Nullable EncodedResour
ce resource, String script,
String separator, String[] commentPrefixes, String blockC
ommentStartDelimiter,
String blockCommentEndDelimiter) throws ScriptException {
boolean inSingleQuote = false;
boolean inDoubleQuote = false;
boolean inEscape = false;
for (int i = 0; i < script.length(); i++) {
char c = script.charAt(i);
if (inEscape) {
inEscape = false;
continue;
}
// MySQL style escapes
if (c == '\\') {
inEscape = true;
continue;
}
if (!inDoubleQuote && (c == '\'')) {
inSingleQuote = !inSingleQuote;
}
else if (!inSingleQuote && (c == '"')) {
inDoubleQuote = !inDoubleQuote;
}
if (!inSingleQuote && !inDoubleQuote) {
if (script.startsWith(separator, i)) {
return true;
}
else if (startsWithAny(script, commentPrefixes, i
)) {
// Skip over any content from the start o
f the comment to the EOL
int indexOfNextNewline = script.indexOf('
\n', i);
if (indexOfNextNewline > i) {
i = indexOfNextNewline;
continue;
}
else {
// If there's no EOL, we must be
at the end of the script, so stop here.
break;
}
}
else if (script.startsWith(blockCommentStartDelim
iter, i)) {
// Skip over any block comments
int indexOfCommentEnd = script.indexOf(bl
ockCommentEndDelimiter, i);
if (indexOfCommentEnd > i) {
i = indexOfCommentEnd + blockComm
entEndDelimiter.length() - 1;
continue;
}
else {
throw new ScriptParseException(
"Missing block co
mment end delimiter: " + blockCommentEndDelimiter, resource);
}
}
}
}
return false;
}
/**
* Split an SQL script into separate statements delimited by the provided * Split an SQL script into separate statements delimited by the provided
* separator character. Each individual statement will be added to the * separator character. Each individual statement will be added to the
* provided {@code List}. * provided {@code List}.
* <p>Within the script, {@value #DEFAULT_COMMENT_PREFIX} will be used as the * <p>Within the script, {@value #DEFAULT_COMMENT_PREFIX} will be used as the
* comment prefix; any text beginning with the comment prefix and extendi ng to * comment prefix; any text beginning with the comment prefix and extendi ng to
* the end of the line will be omitted from the output. Similarly, * the end of the line will be omitted from the output. Similarly,
* {@value #DEFAULT_BLOCK_COMMENT_START_DELIMITER} and * {@value #DEFAULT_BLOCK_COMMENT_START_DELIMITER} and
* {@value #DEFAULT_BLOCK_COMMENT_END_DELIMITER} will be used as the * {@value #DEFAULT_BLOCK_COMMENT_END_DELIMITER} will be used as the
* <em>start</em> and <em>end</em> block comment delimiters: any text enc losed * <em>start</em> and <em>end</em> block comment delimiters: any text enc losed
* in a block comment will be omitted from the output. In addition, multi ple * in a block comment will be omitted from the output. In addition, multi ple
* adjacent whitespace characters will be collapsed into a single space. * adjacent whitespace characters will be collapsed into a single space.
* @param script the SQL script * @param script the SQL script
* @param separator character separating each statement (typically a ';') * @param separator character separating each statement (typically a ';')
* @param statements the list that will contain the individual statements * @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL s cript * @throws ScriptException if an error occurred while splitting the SQL s cript
* @see #splitSqlScript(String, String, List) * @see #splitSqlScript(String, String, List)
* @see #splitSqlScript(EncodedResource, String, String, String, String, String, List) * @see #splitSqlScript(EncodedResource, String, String, String, String, String, List)
* @deprecated as of Spring Framework 5.2.16 with no plans for replacemen
t.
* This is an internal API and will likely be removed in Spring Framework
6.0.
*/ */
@Deprecated
public static void splitSqlScript(String script, char separator, List<Str ing> statements) throws ScriptException { public static void splitSqlScript(String script, char separator, List<Str ing> statements) throws ScriptException {
splitSqlScript(script, String.valueOf(separator), statements); splitSqlScript(script, String.valueOf(separator), statements);
} }
/** /**
* Split an SQL script into separate statements delimited by the provided * Split an SQL script into separate statements delimited by the provided
* separator string. Each individual statement will be added to the * separator string. Each individual statement will be added to the
* provided {@code List}. * provided {@code List}.
* <p>Within the script, {@value #DEFAULT_COMMENT_PREFIX} will be used as the * <p>Within the script, {@value #DEFAULT_COMMENT_PREFIX} will be used as the
* comment prefix; any text beginning with the comment prefix and extendi ng to * comment prefix; any text beginning with the comment prefix and extendi ng to
skipping to change at line 144 skipping to change at line 557
* <em>start</em> and <em>end</em> block comment delimiters: any text enc losed * <em>start</em> and <em>end</em> block comment delimiters: any text enc losed
* in a block comment will be omitted from the output. In addition, multi ple * in a block comment will be omitted from the output. In addition, multi ple
* adjacent whitespace characters will be collapsed into a single space. * adjacent whitespace characters will be collapsed into a single space.
* @param script the SQL script * @param script the SQL script
* @param separator text separating each statement * @param separator text separating each statement
* (typically a ';' or newline character) * (typically a ';' or newline character)
* @param statements the list that will contain the individual statements * @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL s cript * @throws ScriptException if an error occurred while splitting the SQL s cript
* @see #splitSqlScript(String, char, List) * @see #splitSqlScript(String, char, List)
* @see #splitSqlScript(EncodedResource, String, String, String, String, String, List) * @see #splitSqlScript(EncodedResource, String, String, String, String, String, List)
* @deprecated as of Spring Framework 5.2.16 with no plans for replacemen
t.
* This is an internal API and will likely be removed in Spring Framework
6.0.
*/ */
@Deprecated
public static void splitSqlScript(String script, String separator, List<S tring> statements) throws ScriptException { public static void splitSqlScript(String script, String separator, List<S tring> statements) throws ScriptException {
splitSqlScript(null, script, separator, DEFAULT_COMMENT_PREFIX, D EFAULT_BLOCK_COMMENT_START_DELIMITER, splitSqlScript(null, script, separator, DEFAULT_COMMENT_PREFIX, D EFAULT_BLOCK_COMMENT_START_DELIMITER,
DEFAULT_BLOCK_COMMENT_END_DELIMITER, statements); DEFAULT_BLOCK_COMMENT_END_DELIMITER, statements);
} }
/** /**
* Split an SQL script into separate statements delimited by the provided * Split an SQL script into separate statements delimited by the provided
* separator string. Each individual statement will be added to the provi ded * separator string. Each individual statement will be added to the provi ded
* {@code List}. * {@code List}.
* <p>Within the script, the provided {@code commentPrefix} will be honor ed: * <p>Within the script, the provided {@code commentPrefix} will be honor ed:
skipping to change at line 173 skipping to change at line 589
* @param separator text separating each statement * @param separator text separating each statement
* (typically a ';' or newline character) * (typically a ';' or newline character)
* @param commentPrefix the prefix that identifies SQL line comments * @param commentPrefix the prefix that identifies SQL line comments
* (typically "--") * (typically "--")
* @param blockCommentStartDelimiter the <em>start</em> block comment del imiter; * @param blockCommentStartDelimiter the <em>start</em> block comment del imiter;
* never {@code null} or empty * never {@code null} or empty
* @param blockCommentEndDelimiter the <em>end</em> block comment delimit er; * @param blockCommentEndDelimiter the <em>end</em> block comment delimit er;
* never {@code null} or empty * never {@code null} or empty
* @param statements the list that will contain the individual statements * @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL s cript * @throws ScriptException if an error occurred while splitting the SQL s cript
* @deprecated as of Spring Framework 5.2.16 with no plans for replacemen
t.
* This is an internal API and will likely be removed in Spring Framework
6.0.
*/ */
@Deprecated
public static void splitSqlScript(@Nullable EncodedResource resource, Str ing script, public static void splitSqlScript(@Nullable EncodedResource resource, Str ing script,
String separator, String commentPrefix, String blockComme ntStartDelimiter, String separator, String commentPrefix, String blockComme ntStartDelimiter,
String blockCommentEndDelimiter, List<String> statements) throws ScriptException { String blockCommentEndDelimiter, List<String> statements) throws ScriptException {
Assert.hasText(commentPrefix, "'commentPrefix' must not be null o r empty"); Assert.hasText(commentPrefix, "'commentPrefix' must not be null o r empty");
splitSqlScript(resource, script, separator, new String[] { commen tPrefix }, splitSqlScript(resource, script, separator, new String[] { commen tPrefix },
blockCommentStartDelimiter, blockCommentEndDelimi ter, statements); blockCommentStartDelimiter, blockCommentEndDelimi ter, statements);
} }
/** /**
skipping to change at line 207 skipping to change at line 626
* (typically a ';' or newline character) * (typically a ';' or newline character)
* @param commentPrefixes the prefixes that identify SQL line comments * @param commentPrefixes the prefixes that identify SQL line comments
* (typically "--") * (typically "--")
* @param blockCommentStartDelimiter the <em>start</em> block comment del imiter; * @param blockCommentStartDelimiter the <em>start</em> block comment del imiter;
* never {@code null} or empty * never {@code null} or empty
* @param blockCommentEndDelimiter the <em>end</em> block comment delimit er; * @param blockCommentEndDelimiter the <em>end</em> block comment delimit er;
* never {@code null} or empty * never {@code null} or empty
* @param statements the list that will contain the individual statements * @param statements the list that will contain the individual statements
* @throws ScriptException if an error occurred while splitting the SQL s cript * @throws ScriptException if an error occurred while splitting the SQL s cript
* @since 5.2 * @since 5.2
* @deprecated as of Spring Framework 5.2.16 with no plans for replacemen
t.
* This is an internal API and will likely be removed in Spring Framework
6.0.
*/ */
@Deprecated
public static void splitSqlScript(@Nullable EncodedResource resource, Str ing script, public static void splitSqlScript(@Nullable EncodedResource resource, Str ing script,
String separator, String[] commentPrefixes, String blockC ommentStartDelimiter, String separator, String[] commentPrefixes, String blockC ommentStartDelimiter,
String blockCommentEndDelimiter, List<String> statements) throws ScriptException { String blockCommentEndDelimiter, List<String> statements) throws ScriptException {
Assert.hasText(script, "'script' must not be null or empty"); Assert.hasText(script, "'script' must not be null or empty");
Assert.notNull(separator, "'separator' must not be null"); Assert.notNull(separator, "'separator' must not be null");
Assert.notEmpty(commentPrefixes, "'commentPrefixes' must not be n ull or empty"); Assert.notEmpty(commentPrefixes, "'commentPrefixes' must not be n ull or empty");
for (String commentPrefix : commentPrefixes) { for (String commentPrefix : commentPrefixes) {
Assert.hasText(commentPrefix, "'commentPrefixes' must not contain null or empty elements"); Assert.hasText(commentPrefix, "'commentPrefixes' must not contain null or empty elements");
} }
skipping to change at line 297 skipping to change at line 719
} }
} }
sb.append(c); sb.append(c);
} }
if (StringUtils.hasText(sb)) { if (StringUtils.hasText(sb)) {
statements.add(sb.toString()); statements.add(sb.toString());
} }
} }
/**
* Read a script from the given resource, using "{@code --}" as the comme
nt prefix
* and "{@code ;}" as the statement separator, and build a String contain
ing the lines.
* @param resource the {@code EncodedResource} to be read
* @return {@code String} containing the script lines
* @throws IOException in case of I/O errors
*/
static String readScript(EncodedResource resource) throws IOException {
return readScript(resource, DEFAULT_COMMENT_PREFIXES, DEFAULT_STA
TEMENT_SEPARATOR, DEFAULT_BLOCK_COMMENT_END_DELIMITER);
}
/**
* Read a script from the provided resource, using the supplied comment p
refixes
* and statement separator, and build a {@code String} containing the lin
es.
* <p>Lines <em>beginning</em> with one of the comment prefixes are exclu
ded
* from the results; however, line comments anywhere else &mdash; for exa
mple,
* within a statement &mdash; will be included in the results.
* @param resource the {@code EncodedResource} containing the script
* to be processed
* @param commentPrefixes 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 delimit
er
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
*/
private static String readScript(EncodedResource resource, @Nullable Stri
ng[] commentPrefixes,
@Nullable String separator, @Nullable String blockComment
EndDelimiter) throws IOException {
try (LineNumberReader lnr = new LineNumberReader(resource.getRead
er())) {
return readScript(lnr, commentPrefixes, separator, blockC
ommentEndDelimiter);
}
}
/**
* Read a script from the provided {@code LineNumberReader}, using the su
pplied
* comment prefix and statement separator, and build a {@code String} con
taining
* the lines.
* <p>Lines <em>beginning</em> with the comment prefix are excluded from
the
* results; however, line comments anywhere else &mdash; for example, wit
hin
* a statement &mdash; will be included in the results.
* @param lineNumberReader the {@code LineNumberReader} containing the sc
ript
* to be processed
* @param lineCommentPrefix the prefix that identifies comments in the SQ
L script
* (typically "--")
* @param separator the statement separator in the SQL script (typically
";")
* @param blockCommentEndDelimiter the <em>end</em> block comment delimit
er
* @return a {@code String} containing the script lines
* @throws IOException in case of I/O errors
*/
public static String readScript(LineNumberReader lineNumberReader, @Nulla
ble String lineCommentPrefix,
@Nullable String separator, @Nullable String blockComment
EndDelimiter) throws IOException {
String[] lineCommentPrefixes = (lineCommentPrefix != null) ? new
String[] { lineCommentPrefix } : null;
return readScript(lineNumberReader, lineCommentPrefixes, separato
r, blockCommentEndDelimiter);
}
/**
* Read a script from the provided {@code LineNumberReader}, using the su
pplied
* comment prefixes and statement separator, and build a {@code String} c
ontaining
* the lines.
* <p>Lines <em>beginning</em> with one of the comment prefixes are exclu
ded
* from the results; however, line comments anywhere else &mdash; for exa
mple,
* within a statement &mdash; will be included in the results.
* @param lineNumberReader the {@code LineNumberReader} containing the sc
ript
* 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 delimit
er
* @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, @Nulla
ble String[] lineCommentPrefixes,
@Nullable String separator, @Nullable String blockComment
EndDelimiter) throws IOException {
String currentStatement = lineNumberReader.readLine();
StringBuilder scriptBuilder = new StringBuilder();
while (currentStatement != null) {
if ((blockCommentEndDelimiter != null && currentStatement
.contains(blockCommentEndDelimiter)) ||
(lineCommentPrefixes != null && !startsWithAny(cu
rrentStatement, lineCommentPrefixes, 0))) {
if (scriptBuilder.length() > 0) {
scriptBuilder.append('\n');
}
scriptBuilder.append(currentStatement);
}
currentStatement = lineNumberReader.readLine();
}
appendSeparatorToScriptIfNecessary(scriptBuilder, separator);
return scriptBuilder.toString();
}
private static void appendSeparatorToScriptIfNecessary(StringBuilder scri
ptBuilder, @Nullable String separator) {
if (separator == null) {
return;
}
String trimmed = separator.trim();
if (trimmed.length() == separator.length()) {
return;
}
// separator ends in whitespace, so we might want to see if the s
cript is trying
// to end the same way
if (scriptBuilder.lastIndexOf(trimmed) == scriptBuilder.length()
- trimmed.length()) {
scriptBuilder.append(separator.substring(trimmed.length()
));
}
}
private static boolean startsWithAny(String script, String[] prefixes, in t offset) { private static boolean startsWithAny(String script, String[] prefixes, in t offset) {
for (String prefix : prefixes) { for (String prefix : prefixes) {
if (script.startsWith(prefix, offset)) { if (script.startsWith(prefix, offset)) {
return true; return true;
} }
} }
return false; return false;
} }
/**
* Does the provided SQL script contain the specified delimiter?
* @param script the SQL script
* @param delim the string delimiting each statement - typically a ';' ch
aracter
*/
public static boolean containsSqlScriptDelimiters(String script, String d
elim) {
boolean inLiteral = false;
boolean inEscape = false;
for (int i = 0; i < script.length(); i++) {
char c = script.charAt(i);
if (inEscape) {
inEscape = false;
continue;
}
// MySQL style escapes
if (c == '\\') {
inEscape = true;
continue;
}
if (c == '\'') {
inLiteral = !inLiteral;
}
if (!inLiteral && script.startsWith(delim, i)) {
return true;
}
}
return false;
}
/**
* Execute the given SQL script using default settings for statement
* separators, comment delimiters, and exception handling flags.
* <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; al
ready
* configured and ready to use
* @param resource the resource to load the SQL script from; encoded with
the
* current platform's default encoding
* @throws ScriptException if an error occurred while executing the SQL s
cript
* @see #executeSqlScript(Connection, EncodedResource, boolean, boolean,
String, String, String, String)
* @see #DEFAULT_STATEMENT_SEPARATOR
* @see #DEFAULT_COMMENT_PREFIX
* @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER
* @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnec
tion
*/
public static void executeSqlScript(Connection connection, Resource resou
rce) throws ScriptException {
executeSqlScript(connection, new EncodedResource(resource));
}
/**
* Execute the given SQL script using default settings for statement
* separators, comment delimiters, and exception handling flags.
* <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; al
ready
* configured and ready to use
* @param resource the resource (potentially associated with a specific e
ncoding)
* to load the SQL script from
* @throws ScriptException if an error occurred while executing the SQL s
cript
* @see #executeSqlScript(Connection, EncodedResource, boolean, boolean,
String, String, String, String)
* @see #DEFAULT_STATEMENT_SEPARATOR
* @see #DEFAULT_COMMENT_PREFIX
* @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER
* @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnec
tion
*/
public static void executeSqlScript(Connection connection, EncodedResourc
e resource) throws ScriptException {
executeSqlScript(connection, resource, false, false, DEFAULT_COMM
ENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR,
DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BL
OCK_COMMENT_END_DELIMITER);
}
/**
* 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; al
ready
* configured and ready to use
* @param resource the resource (potentially associated with a specific e
ncoding)
* 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 sp
ecifically
* an error on a {@code DROP} statement
* @param commentPrefix the prefix that identifies single-line comments i
n 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 del
imiter
* @param blockCommentEndDelimiter the <em>end</em> block comment delimit
er
* @throws ScriptException if an error occurred while executing the SQL s
cript
* @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#releaseConnec
tion
*/
public static void executeSqlScript(Connection connection, EncodedResourc
e resource, boolean continueOnError,
boolean ignoreFailedDrops, String commentPrefix, @Nullabl
e String separator,
String blockCommentStartDelimiter, String blockCommentEnd
Delimiter) throws ScriptException {
executeSqlScript(connection, resource, continueOnError, ignoreFai
ledDrops,
new String[] { commentPrefix }, separator, blockC
ommentStartDelimiter,
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; al
ready
* configured and ready to use
* @param resource the resource (potentially associated with a specific e
ncoding)
* 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 sp
ecifically
* 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 del
imiter
* @param blockCommentEndDelimiter the <em>end</em> block comment delimit
er
* @throws ScriptException if an error occurred while executing the SQL s
cript
* @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#releaseConnec
tion
*/
public static void executeSqlScript(Connection connection, EncodedResourc
e resource, boolean continueOnError,
boolean ignoreFailedDrops, String[] commentPrefixes, @Nul
lable String separator,
String blockCommentStartDelimiter, String blockCommentEnd
Delimiter) throws ScriptException {
try {
if (logger.isDebugEnabled()) {
logger.debug("Executing SQL script from " + resou
rce);
}
long startTime = System.currentTimeMillis();
String script;
try {
script = readScript(resource, commentPrefixes, se
parator, blockCommentEndDelimiter);
}
catch (IOException ex) {
throw new CannotReadScriptException(resource, ex)
;
}
if (separator == null) {
separator = DEFAULT_STATEMENT_SEPARATOR;
}
if (!EOF_STATEMENT_SEPARATOR.equals(separator) && !contai
nsSqlScriptDelimiters(script, separator)) {
separator = FALLBACK_STATEMENT_SEPARATOR;
}
List<String> statements = new ArrayList<>();
splitSqlScript(resource, script, separator, commentPrefix
es, blockCommentStartDelimiter,
blockCommentEndDelimiter, statements);
int stmtNumber = 0;
Statement stmt = connection.createStatement();
try {
for (String statement : statements) {
stmtNumber++;
try {
stmt.execute(statement);
int rowsAffected = stmt.getUpdate
Count();
if (logger.isDebugEnabled()) {
logger.debug(rowsAffected
+ " returned as update count for SQL: " + statement);
SQLWarning warningToLog =
stmt.getWarnings();
while (warningToLog != nu
ll) {
logger.debug("SQL
Warning ignored: SQL state '" + warningToLog.getSQLState() +
"
', error code '" + warningToLog.getErrorCode() +
"
', message [" + warningToLog.getMessage() + "]");
warningToLog = wa
rningToLog.getNextWarning();
}
}
}
catch (SQLException ex) {
boolean dropStatement = StringUti
ls.startsWithIgnoreCase(statement.trim(), "drop");
if (continueOnError || (dropState
ment && ignoreFailedDrops)) {
if (logger.isDebugEnabled
()) {
logger.debug(Scri
ptStatementFailedException.buildErrorMessage(statement, stmtNumber, resource), e
x);
}
}
else {
throw new ScriptStatement
FailedException(statement, stmtNumber, resource, ex);
}
}
}
}
finally {
try {
stmt.close();
}
catch (Throwable ex) {
logger.trace("Could not close JDBC Statem
ent", ex);
}
}
long elapsedTime = System.currentTimeMillis() - startTime
;
if (logger.isDebugEnabled()) {
logger.debug("Executed SQL script from " + resour
ce + " in " + elapsedTime + " ms.");
}
}
catch (Exception ex) {
if (ex instanceof ScriptException) {
throw (ScriptException) ex;
}
throw new UncategorizedScriptException(
"Failed to execute database script from resource
[" + resource + "]", ex);
}
}
} }
 End of changes. 14 change blocks. 
453 lines changed or deleted 568 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)