mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
Restore exposure of original BatchUpdateException as root cause
Closes gh-35717 See gh-35547
This commit is contained in:
+12
-12
@@ -80,43 +80,43 @@ public class SQLExceptionSubclassTranslator extends AbstractFallbackSQLException
|
||||
|
||||
if (sqlEx instanceof SQLTransientException) {
|
||||
if (sqlEx instanceof SQLTransientConnectionException) {
|
||||
return new TransientDataAccessResourceException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new TransientDataAccessResourceException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
if (sqlEx instanceof SQLTransactionRollbackException) {
|
||||
if (SQLStateSQLExceptionTranslator.indicatesCannotAcquireLock(sqlEx.getSQLState())) {
|
||||
return new CannotAcquireLockException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new CannotAcquireLockException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
return new PessimisticLockingFailureException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new PessimisticLockingFailureException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
if (sqlEx instanceof SQLTimeoutException) {
|
||||
return new QueryTimeoutException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new QueryTimeoutException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
}
|
||||
else if (sqlEx instanceof SQLNonTransientException) {
|
||||
if (sqlEx instanceof SQLNonTransientConnectionException) {
|
||||
return new DataAccessResourceFailureException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new DataAccessResourceFailureException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
if (sqlEx instanceof SQLDataException) {
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
if (sqlEx instanceof SQLIntegrityConstraintViolationException) {
|
||||
if (SQLStateSQLExceptionTranslator.indicatesDuplicateKey(sqlEx.getSQLState(), sqlEx.getErrorCode())) {
|
||||
return new DuplicateKeyException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new DuplicateKeyException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
if (sqlEx instanceof SQLInvalidAuthorizationSpecException) {
|
||||
return new PermissionDeniedDataAccessException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new PermissionDeniedDataAccessException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
if (sqlEx instanceof SQLSyntaxErrorException) {
|
||||
return new BadSqlGrammarException(task, (sql != null ? sql : ""), sqlEx);
|
||||
return new BadSqlGrammarException(task, (sql != null ? sql : ""), ex);
|
||||
}
|
||||
if (sqlEx instanceof SQLFeatureNotSupportedException) {
|
||||
return new InvalidDataAccessApiUsageException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new InvalidDataAccessApiUsageException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
}
|
||||
else if (sqlEx instanceof SQLRecoverableException) {
|
||||
return new RecoverableDataAccessException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new RecoverableDataAccessException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
|
||||
// Fallback to Spring's own SQL state translation...
|
||||
|
||||
+9
-9
@@ -131,35 +131,35 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
|
||||
logger.debug("Extracted SQL state class '" + classCode + "' from value '" + sqlState + "'");
|
||||
}
|
||||
if (BAD_SQL_GRAMMAR_CODES.contains(classCode)) {
|
||||
return new BadSqlGrammarException(task, (sql != null ? sql : ""), sqlEx);
|
||||
return new BadSqlGrammarException(task, (sql != null ? sql : ""), ex);
|
||||
}
|
||||
else if (DATA_INTEGRITY_VIOLATION_CODES.contains(classCode)) {
|
||||
if (indicatesDuplicateKey(sqlState, sqlEx.getErrorCode())) {
|
||||
return new DuplicateKeyException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new DuplicateKeyException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new DataIntegrityViolationException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
else if (PESSIMISTIC_LOCKING_FAILURE_CODES.contains(classCode)) {
|
||||
if (indicatesCannotAcquireLock(sqlState)) {
|
||||
return new CannotAcquireLockException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new CannotAcquireLockException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
return new PessimisticLockingFailureException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new PessimisticLockingFailureException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
else if (DATA_ACCESS_RESOURCE_FAILURE_CODES.contains(classCode)) {
|
||||
if (indicatesQueryTimeout(sqlState)) {
|
||||
return new QueryTimeoutException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new QueryTimeoutException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
return new DataAccessResourceFailureException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new DataAccessResourceFailureException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
else if (TRANSIENT_DATA_ACCESS_RESOURCE_CODES.contains(classCode)) {
|
||||
return new TransientDataAccessResourceException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new TransientDataAccessResourceException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
}
|
||||
|
||||
// For MySQL: exception class name indicating a timeout?
|
||||
// (since MySQL doesn't throw the JDBC 4 SQLTimeoutException)
|
||||
if (sqlEx.getClass().getName().contains("Timeout")) {
|
||||
return new QueryTimeoutException(buildMessage(task, sql, sqlEx), sqlEx);
|
||||
return new QueryTimeoutException(buildMessage(task, sql, sqlEx), ex);
|
||||
}
|
||||
|
||||
// Couldn't resolve anything proper - resort to UncategorizedSQLException.
|
||||
|
||||
+1
-2
@@ -181,8 +181,7 @@ class SQLStateSQLExceptionTranslatorTests {
|
||||
static void assertTranslation(DataAccessException dae, SQLException ex, Class<?> dataAccessExceptionType) {
|
||||
assertThat(dae).as("Specific translation must not result in null").isNotNull();
|
||||
assertThat(dae).as("Wrong DataAccessException type returned").isExactlyInstanceOf(dataAccessExceptionType);
|
||||
assertThat(dae.getCause()).as("The exact same original SQLException must be preserved").isSameAs(
|
||||
ex instanceof BatchUpdateException bue ? bue.getNextException() : ex);
|
||||
assertThat(dae.getCause()).as("The exact same original SQLException must be preserved").isSameAs(ex);
|
||||
}
|
||||
|
||||
static BatchUpdateException buildBatchUpdateException(@Nullable String sqlState, SQLException next) {
|
||||
|
||||
Reference in New Issue
Block a user