From a15d023b454e5ab585f1279522401e8fe583a1d2 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 9 Oct 2010 12:35:21 +0000 Subject: [PATCH] ResourceDatabasePopulator throws descriptive ScriptStatementFailedException with resource details (SPR-7546) --- .../embedded/EmbeddedDatabaseFactory.java | 22 +++++----- .../init/DataSourceInitializer.java | 2 +- .../init/ResourceDatabasePopulator.java | 27 ++++++------ .../init/ScriptStatementFailedException.java | 42 +++++++++++++++++++ 4 files changed, 69 insertions(+), 24 deletions(-) create mode 100644 org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptStatementFailedException.java diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java index cc806c92a0..2898becf10 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/EmbeddedDatabaseFactory.java @@ -161,7 +161,7 @@ public class EmbeddedDatabaseFactory { } } } - catch (SQLException ex) { + catch (Exception ex) { throw new DataAccessResourceFailureException("Failed to populate database", ex); } } @@ -203,30 +203,30 @@ public class EmbeddedDatabaseFactory { return this.dataSource.getConnection(username, password); } - public int getLoginTimeout() throws SQLException { - return this.dataSource.getLoginTimeout(); - } - public PrintWriter getLogWriter() throws SQLException { return this.dataSource.getLogWriter(); } - public void setLoginTimeout(int seconds) throws SQLException { - this.dataSource.setLoginTimeout(seconds); - } - public void setLogWriter(PrintWriter out) throws SQLException { this.dataSource.setLogWriter(out); } - public boolean isWrapperFor(Class iface) throws SQLException { - return this.dataSource.isWrapperFor(iface); + public int getLoginTimeout() throws SQLException { + return this.dataSource.getLoginTimeout(); + } + + public void setLoginTimeout(int seconds) throws SQLException { + this.dataSource.setLoginTimeout(seconds); } public T unwrap(Class iface) throws SQLException { return this.dataSource.unwrap(iface); } + public boolean isWrapperFor(Class iface) throws SQLException { + return this.dataSource.isWrapperFor(iface); + } + public void shutdown() { shutdownDatabase(); } diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java index a6e394e78c..1e8ae1fbbe 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DataSourceInitializer.java @@ -88,7 +88,7 @@ public class DataSourceInitializer implements InitializingBean { } } } - catch (SQLException ex) { + catch (Exception ex) { throw new DataAccessResourceFailureException("Failed to populate database", ex); } } diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java index 0404963d3e..08bc769066 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.java @@ -36,8 +36,8 @@ import org.springframework.util.StringUtils; /** * Populates a database from SQL scripts defined in external resources. * - *

Call {@link #addScript(Resource)} to add a SQL script location.
- * Call {@link #setSqlScriptEncoding(String)} to set the encoding for all added scripts.
+ *

Call {@link #addScript(Resource)} to add a SQL script location. + * Call {@link #setSqlScriptEncoding(String)} to set the encoding for all added scripts. * * @author Keith Donald * @author Dave Syer @@ -131,15 +131,17 @@ public class ResourceDatabasePopulator implements DatabasePopulator { } /** - * Execute the given SQL script.

The script will normally be loaded by classpath. There should be one statement - * per line. Any semicolons will be removed. Do not use this method to execute DDL if you expect rollback. + * Execute the given SQL script. + *

The script will normally be loaded by classpath. There should be one statement per line. + * Any semicolons will be removed. + *

Do not use this method to execute DDL if you expect rollback. * @param connection the JDBC Connection with which to perform JDBC operations - * @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 of not to continue in thw event of specifically an error on a DROP. + * @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 of not to continue in the event of specifically an error on a DROP */ - private void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError, boolean ignoreFailedDrops) - throws SQLException { + private void executeSqlScript(Connection connection, EncodedResource resource, + boolean continueOnError, boolean ignoreFailedDrops) throws SQLException { if (logger.isInfoEnabled()) { logger.info("Executing SQL script from " + resource); @@ -170,14 +172,15 @@ public class ResourceDatabasePopulator implements DatabasePopulator { } } catch (SQLException ex) { - boolean dropStatement = statement.trim().toLowerCase().startsWith("drop"); + boolean dropStatement = StringUtils.startsWithIgnoreCase(statement.trim(), "drop"); if (continueOnError || (dropStatement && ignoreFailedDrops)) { if (logger.isDebugEnabled()) { - logger.debug("Line " + lineNumber + " statement failed: " + statement, ex); + logger.debug("Failed to execute SQL script statement at line " + lineNumber + + " of resource " + resource + ": " + statement, ex); } } else { - throw ex; + throw new ScriptStatementFailedException(statement, lineNumber, resource, ex); } } } diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptStatementFailedException.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptStatementFailedException.java new file mode 100644 index 0000000000..906b788e04 --- /dev/null +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptStatementFailedException.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.datasource.init; + +import org.springframework.core.io.support.EncodedResource; + +/** + * Thrown by {@link ResourceDatabasePopulator} if a statement in one of its SQL scripts + * failed when executing it against the target database. + * + * @author Juergen Hoeller + * @since 3.0.5 + */ +public class ScriptStatementFailedException extends RuntimeException { + + /** + * Constructor a new ScriptStatementFailedException. + * @param statement the actual SQL statement that failed + * @param lineNumber the line number in the SQL script + * @param resource the resource that could not be read from + * @param cause the underlying cause of the resource access failure + */ + public ScriptStatementFailedException(String statement, int lineNumber, EncodedResource resource, Throwable cause) { + super("Failed to execute SQL script statement at line " + lineNumber + + " of resource " + resource + ": " + statement, cause); + } + +}