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 <pickjog@gmail.com>
This commit is contained in:
junhyeong9812
2026-09-05 14:50:26 +02:00
committed by Sam Brannen
parent 35d8c4d06f
commit 6e260bc78e
2 changed files with 15 additions and 1 deletions
@@ -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) {
@@ -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);