Skip to content

Commit e33adad

Browse files
committed
Detect SQL state 57014 as QueryTimeoutException
Closes gh-35073
1 parent 45d887f commit e33adad

File tree

2 files changed

+29
-11
lines changed

2 files changed

+29
-11
lines changed

spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslator.java

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
7070
"44" // With check violation
7171
);
7272

73+
private static final Set<String> PESSIMISTIC_LOCKING_FAILURE_CODES = Set.of(
74+
"40", // Transaction rollback
75+
"61" // Oracle: deadlock
76+
);
77+
7378
private static final Set<String> DATA_ACCESS_RESOURCE_FAILURE_CODES = Set.of(
7479
"08", // Connection exception
7580
"53", // PostgreSQL: insufficient resources (for example, disk full)
@@ -84,11 +89,6 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
8489
"S1" // DB2: communication failure
8590
);
8691

87-
private static final Set<String> PESSIMISTIC_LOCKING_FAILURE_CODES = Set.of(
88-
"40", // Transaction rollback
89-
"61" // Oracle: deadlock
90-
);
91-
9292
private static final Set<Integer> DUPLICATE_KEY_ERROR_CODES = Set.of(
9393
1, // Oracle
9494
301, // SAP HANA
@@ -117,18 +117,21 @@ else if (DATA_INTEGRITY_VIOLATION_CODES.contains(classCode)) {
117117
}
118118
return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex);
119119
}
120-
else if (DATA_ACCESS_RESOURCE_FAILURE_CODES.contains(classCode)) {
121-
return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex);
122-
}
123-
else if (TRANSIENT_DATA_ACCESS_RESOURCE_CODES.contains(classCode)) {
124-
return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
125-
}
126120
else if (PESSIMISTIC_LOCKING_FAILURE_CODES.contains(classCode)) {
127121
if (indicatesCannotAcquireLock(sqlState)) {
128122
return new CannotAcquireLockException(buildMessage(task, sql, ex), ex);
129123
}
130124
return new PessimisticLockingFailureException(buildMessage(task, sql, ex), ex);
131125
}
126+
else if (DATA_ACCESS_RESOURCE_FAILURE_CODES.contains(classCode)) {
127+
if (indicatesQueryTimeout(sqlState)) {
128+
return new QueryTimeoutException(buildMessage(task, sql, ex), ex);
129+
}
130+
return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex);
131+
}
132+
else if (TRANSIENT_DATA_ACCESS_RESOURCE_CODES.contains(classCode)) {
133+
return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
134+
}
132135
}
133136

134137
// For MySQL: exception class name indicating a timeout?
@@ -184,4 +187,13 @@ static boolean indicatesCannotAcquireLock(@Nullable String sqlState) {
184187
return "40001".equals(sqlState);
185188
}
186189

190+
/**
191+
* Check whether the given SQL state indicates a {@link QueryTimeoutException},
192+
* with SQL state 57014 as a specific indication.
193+
* @param sqlState the SQL state value
194+
*/
195+
static boolean indicatesQueryTimeout(@Nullable String sqlState) {
196+
return "57014".equals(sqlState);
197+
}
198+
187199
}

spring-jdbc/src/test/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslatorTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.springframework.dao.DataIntegrityViolationException;
2727
import org.springframework.dao.DuplicateKeyException;
2828
import org.springframework.dao.PessimisticLockingFailureException;
29+
import org.springframework.dao.QueryTimeoutException;
2930
import org.springframework.dao.TransientDataAccessResourceException;
3031
import org.springframework.jdbc.BadSqlGrammarException;
3132
import org.springframework.lang.Nullable;
@@ -109,6 +110,11 @@ void translateCannotAcquireLock() {
109110
assertTranslation("40001", CannotAcquireLockException.class);
110111
}
111112

113+
@Test
114+
void translateQueryTimeout() {
115+
assertTranslation("57014", QueryTimeoutException.class);
116+
}
117+
112118
@Test
113119
void translateUncategorized() {
114120
assertTranslation("00000000", null);

0 commit comments

Comments
 (0)