Support EOF as statement separator in SQL scripts
Prior to Spring Framework 4.0.3, it was possible to supply a bogus statement separator (i.e., a separator string that does not exist in the configured SQL scripts) to ResourceDatabasePopulator with the side effect that the entire contents of a script file would be interpreted as a single SQL statement. This undocumented feature was never intentional; however, some developers came to rely on it. Unfortunately, changes made in conjunction with SPR-9531 and SPR-11560 caused such scenarios to no longer work. This commit introduces first-class support for executing scripts which contain a single statement that spans multiple lines but is not followed by an explicit statement separator. Specifically, ScriptUtils.EOF_STATEMENT_SEPARATOR may now be specified as a 'virtual' statement separator to denote that a script contains a single statement and no actual separator. Issue: SPR-11687
This commit is contained in:
parent
2a937a369e
commit
cc0ae3a881
|
@ -21,6 +21,7 @@ import javax.sql.DataSource;
|
|||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.jdbc.datasource.init.ScriptUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
@ -161,7 +162,9 @@ public class EmbeddedDatabaseBuilder {
|
|||
|
||||
/**
|
||||
* Specify the statement separator used in all SQL scripts, if a custom one.
|
||||
* <p>Default is ";".
|
||||
* <p>Defaults to {@code ";"} if not specified and falls back to {@code "\n"}
|
||||
* as a last resort; may be set to {@link ScriptUtils#EOF_STATEMENT_SEPARATOR}
|
||||
* to signal that each script contains a single statement without a separator.
|
||||
* @param separator the statement separator
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 4.0.3
|
||||
|
@ -173,7 +176,7 @@ public class EmbeddedDatabaseBuilder {
|
|||
|
||||
/**
|
||||
* Specify the single-line comment prefix used in all SQL scripts.
|
||||
* <p>Default is "--".
|
||||
* <p>Defaults to {@code "--"}.
|
||||
* @param commentPrefix the prefix for single-line comments
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 4.0.3
|
||||
|
@ -185,7 +188,7 @@ public class EmbeddedDatabaseBuilder {
|
|||
|
||||
/**
|
||||
* Specify the start delimiter for block comments in all SQL scripts.
|
||||
* <p>Default is "/*".
|
||||
* <p>Defaults to {@code "/*"}.
|
||||
* @param blockCommentStartDelimiter the start delimiter for block comments
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 4.0.3
|
||||
|
@ -198,7 +201,7 @@ public class EmbeddedDatabaseBuilder {
|
|||
|
||||
/**
|
||||
* Specify the end delimiter for block comments in all SQL scripts.
|
||||
* <p>Default is "*/".
|
||||
* <p>Defaults to <code>"*/"</code>.
|
||||
* @param blockCommentEndDelimiter the end delimiter for block comments
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 4.0.3
|
||||
|
|
|
@ -142,16 +142,18 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
|||
|
||||
/**
|
||||
* Specify the statement separator, if a custom one.
|
||||
* <p>Default is ";".
|
||||
* @param separator the statement separator
|
||||
* <p>Defaults to {@code ";"} if not specified and falls back to {@code "\n"}
|
||||
* as a last resort; may be set to {@link ScriptUtils#EOF_STATEMENT_SEPARATOR}
|
||||
* to signal that each script contains a single statement without a separator.
|
||||
* @param separator the script statement separator
|
||||
*/
|
||||
public void setSeparator(String separator) {
|
||||
this.separator = separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prefix that identifies line comments within the SQL scripts.
|
||||
* <p>Default is "--".
|
||||
* Set the prefix that identifies single-line comments within the SQL scripts.
|
||||
* <p>Defaults to {@code "--"}.
|
||||
* @param commentPrefix the prefix for single-line comments
|
||||
*/
|
||||
public void setCommentPrefix(String commentPrefix) {
|
||||
|
@ -161,7 +163,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
|||
/**
|
||||
* Set the start delimiter that identifies block comments within the SQL
|
||||
* scripts.
|
||||
* <p>Default is "/*".
|
||||
* <p>Defaults to {@code "/*"}.
|
||||
* @param blockCommentStartDelimiter the start delimiter for block comments
|
||||
* @since 4.0.3
|
||||
* @see #setBlockCommentEndDelimiter
|
||||
|
@ -173,7 +175,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
|||
/**
|
||||
* Set the end delimiter that identifies block comments within the SQL
|
||||
* scripts.
|
||||
* <p>Default is "*/".
|
||||
* <p>Defaults to <code>"*/"</code>.
|
||||
* @param blockCommentEndDelimiter the end delimiter for block comments
|
||||
* @since 4.0.3
|
||||
* @see #setBlockCommentStartDelimiter
|
||||
|
|
|
@ -61,6 +61,17 @@ public abstract class ScriptUtils {
|
|||
*/
|
||||
public static final String FALLBACK_STATEMENT_SEPARATOR = "\n";
|
||||
|
||||
/**
|
||||
* End of file (EOF) SQL statement separator.
|
||||
* <p>This value may be supplied as the {@code separator} to {@link
|
||||
* #executeSqlScript(Connection, EncodedResource, boolean, boolean, String, String, String, String)}
|
||||
* to denote that an SQL script contains a single statement (potentially
|
||||
* spanning multiple lines) with no explicit statement separator. Note that
|
||||
* such a script should not actually contain this value; it is merely a
|
||||
* <em>virtual</em> statement separator.
|
||||
*/
|
||||
public static final String EOF_STATEMENT_SEPARATOR = "<<< END OF SCRIPT >>>";
|
||||
|
||||
/**
|
||||
* Default prefix for line comments within SQL scripts.
|
||||
*/
|
||||
|
@ -399,12 +410,17 @@ public abstract class ScriptUtils {
|
|||
* 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
|
||||
* {@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; never
|
||||
* {@code null} or empty
|
||||
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter; never
|
||||
* {@code null} or empty
|
||||
* @throws ScriptException if an error occurred while executing the SQL script
|
||||
* @see #DEFAULT_STATEMENT_SEPARATOR
|
||||
* @see #FALLBACK_STATEMENT_SEPARATOR
|
||||
* @see #EOF_STATEMENT_SEPARATOR
|
||||
*/
|
||||
public static void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError,
|
||||
boolean ignoreFailedDrops, String commentPrefix, String separator, String blockCommentStartDelimiter,
|
||||
|
@ -428,7 +444,7 @@ public abstract class ScriptUtils {
|
|||
if (separator == null) {
|
||||
separator = DEFAULT_STATEMENT_SEPARATOR;
|
||||
}
|
||||
if (!containsSqlScriptDelimiters(script, separator)) {
|
||||
if (!EOF_STATEMENT_SEPARATOR.equals(separator) && !containsSqlScriptDelimiters(script, separator)) {
|
||||
separator = FALLBACK_STATEMENT_SEPARATOR;
|
||||
}
|
||||
|
||||
|
|
|
@ -139,6 +139,17 @@ public abstract class AbstractDatabasePopulatorTests extends AbstractDatabaseIni
|
|||
assertUsersDatabaseCreated("Brannen", "Hoeller");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scriptWithoutStatementSeparator() throws Exception {
|
||||
databasePopulator.setSeparator(ScriptUtils.EOF_STATEMENT_SEPARATOR);
|
||||
databasePopulator.addScript(resource("drop-users-schema.sql"));
|
||||
databasePopulator.addScript(resource("users-schema-without-separator.sql"));
|
||||
databasePopulator.addScript(resource("users-data.sql"));
|
||||
DatabasePopulatorUtils.execute(databasePopulator, db);
|
||||
|
||||
assertUsersDatabaseCreated("Brannen");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWithMultipleScriptResources() throws Exception {
|
||||
final ResourceDatabasePopulator populator = new ResourceDatabasePopulator(usersSchema(),
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
DROP TABLE users IF EXISTS
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO
|
||||
users(first_name, last_name)
|
||||
values('Sam', 'Brannen')
|
|
@ -0,0 +1,5 @@
|
|||
CREATE TABLE users (
|
||||
id INTEGER NOT NULL IDENTITY,
|
||||
first_name VARCHAR(50) NOT NULL,
|
||||
last_name VARCHAR(50) NOT NULL
|
||||
)
|
Loading…
Reference in New Issue