From 6e260bc78eb1ea01f056f910446f633172b36a54 Mon Sep 17 00:00:00 2001 From: junhyeong9812 Date: Fri, 4 Sep 2026 09:03:37 +0900 Subject: [PATCH] Sort duplicate key codes in SQLErrorCodes Every error code setter in SQLErrorCodes sorts its array with StringUtils.sortStringArray, and CustomSQLErrorCodesTranslation does the same, because SQLErrorCodeSQLExceptionTranslator looks the codes up with Arrays.binarySearch. setDuplicateKeyCodes was the only setter that stored the supplied array as-is. With an unsorted list of duplicate key codes, the binary search finds or misses a code depending on where the values happen to sit: for codes it misses, the translator silently falls through to the SQLState fallback and reports a DataIntegrityViolationException, or fails to translate at all, instead of the configured DuplicateKeyException. The default sql-error-codes.xml is not affected since its lists are already sorted; the mismatch surfaces for custom configurations, for example codes of different digit lengths listed in numeric order. setDuplicateKeyCodes now sorts the array like all sibling setters. The new test covers an unsorted custom list whose codes previously hit or missed depending on their position. Closes gh-37235 Signed-off-by: junhyeong9812 --- .../jdbc/support/SQLErrorCodes.java | 2 +- .../SQLErrorCodeSQLExceptionTranslatorTests.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java index 34d4ca66108..e2276c3c4c5 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java @@ -123,7 +123,7 @@ public class SQLErrorCodes { } public void setDuplicateKeyCodes(String... duplicateKeyCodes) { - this.duplicateKeyCodes = duplicateKeyCodes; + this.duplicateKeyCodes = StringUtils.sortStringArray(duplicateKeyCodes); } public void setDataIntegrityViolationCodes(String... dataIntegrityViolationCodes) { diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java index 1f02db5aca6..3e96ff7f33f 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java @@ -107,6 +107,20 @@ class SQLErrorCodeSQLExceptionTranslatorTests { .hasCause(sqlException); } + @Test // gh-37235 + void duplicateKeyCodesDeclaredInUnsortedOrder() { + SQLErrorCodes errorCodes = new SQLErrorCodes(); + errorCodes.setDuplicateKeyCodes("90002", "1586", "1062"); + SQLErrorCodeSQLExceptionTranslator unsortedCodesTranslator = new SQLErrorCodeSQLExceptionTranslator(errorCodes); + + for (int errorCode : new int[] {90002, 1586, 1062}) { + SQLException sqlException = new SQLException("", "", errorCode); + assertThat(unsortedCodesTranslator.translate("task", "SQL", sqlException)) + .isInstanceOf(DuplicateKeyException.class) + .hasCause(sqlException); + } + } + @Test void batchExceptionTranslation() { SQLException badSqlEx = new SQLException("", "", 1);