From db9e938ec452510e4c33680ce95f3de4228a4743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Kv=C3=ADdera?= Date: Mon, 1 Sep 2025 13:05:31 +0200 Subject: [PATCH] Detect Informix error codes as DuplicateKeyException MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes gh-35400 Signed-off-by: Lukáš Kvídera --- .../SQLStateSQLExceptionTranslator.java | 4 +- .../SQLStateSQLExceptionTranslatorTests.java | 10 ++++ .../connection/ConnectionFactoryUtils.java | 4 +- .../ConnectionFactoryUtilsTests.java | 55 ++++++++++--------- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslator.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslator.java index 4b962d02ecb..daecc4f2090 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslator.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslator.java @@ -94,7 +94,9 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException 301, // SAP HANA 1062, // MySQL/MariaDB 2601, // MS SQL Server - 2627 // MS SQL Server + 2627, // MS SQL Server + -239, // Informix + -268 // Informix ); diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslatorTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslatorTests.java index 94abeccca32..263eb8f829d 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslatorTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslatorTests.java @@ -90,6 +90,16 @@ class SQLStateSQLExceptionTranslatorTests { assertTranslation("23000", 301, DuplicateKeyException.class); } + @Test + void translateDuplicateKeyInformix1() { + assertTranslation("23000", -239, DuplicateKeyException.class); + } + + @Test + void translateDuplicateKeyInformix2() { + assertTranslation("23000", -268, DuplicateKeyException.class); + } + @Test void translateDataAccessResourceFailure() { assertTranslation("53", DataAccessResourceFailureException.class); diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionFactoryUtils.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionFactoryUtils.java index 8741f89067f..33d8a7619b8 100644 --- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionFactoryUtils.java +++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionFactoryUtils.java @@ -76,7 +76,9 @@ public abstract class ConnectionFactoryUtils { 301, // SAP HANA 1062, // MySQL/MariaDB 2601, // MS SQL Server - 2627 // MS SQL Server + 2627, // MS SQL Server + -239, // Informix + -268 // Informix ); diff --git a/spring-r2dbc/src/test/java/org/springframework/r2dbc/connection/ConnectionFactoryUtilsTests.java b/spring-r2dbc/src/test/java/org/springframework/r2dbc/connection/ConnectionFactoryUtilsTests.java index 49861f0a4e8..902d4ce8514 100644 --- a/spring-r2dbc/src/test/java/org/springframework/r2dbc/connection/ConnectionFactoryUtilsTests.java +++ b/spring-r2dbc/src/test/java/org/springframework/r2dbc/connection/ConnectionFactoryUtilsTests.java @@ -25,7 +25,9 @@ import io.r2dbc.spi.R2dbcRollbackException; import io.r2dbc.spi.R2dbcTimeoutException; import io.r2dbc.spi.R2dbcTransientResourceException; import org.junit.jupiter.api.Test; - +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.springframework.dao.CannotAcquireLockException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.DataIntegrityViolationException; @@ -37,8 +39,12 @@ import org.springframework.dao.TransientDataAccessResourceException; import org.springframework.r2dbc.BadSqlGrammarException; import org.springframework.r2dbc.UncategorizedR2dbcException; +import java.util.stream.Stream; + import static org.assertj.core.api.Assertions.assertThat; + + /** * Tests for {@link ConnectionFactoryUtils}. * @@ -86,35 +92,32 @@ class ConnectionFactoryUtilsTests { assertThat(exception).isExactlyInstanceOf(DataAccessResourceFailureException.class); } + private static Stream duplicateKeyErrorCodes() { + return Stream.of( + Arguments.of("Oracle", "23505", 0), + Arguments.of("Oracle", "23000", 1), + Arguments.of("SAP HANA", "23000", 301), + Arguments.of("MySQL/MariaDB", "23000", 1062), + Arguments.of("MS SQL Server", "23000", 2601), + Arguments.of("MS SQL Server", "23000", 2627), + Arguments.of("Informix", "23000", -239), + Arguments.of("Informix", "23000", -268) + ); + } + + @ParameterizedTest + @MethodSource("duplicateKeyErrorCodes") + void shouldTranslateIntegrityViolationException(final String db, String sqlState, final int errorCode) { + Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "", + new R2dbcDataIntegrityViolationException("reason", sqlState, errorCode)); + assertThat(exception).as(db).isExactlyInstanceOf(DuplicateKeyException.class); + } + @Test - void shouldTranslateIntegrityViolationException() { + void shouldTranslateGenericIntegrityViolationException() { Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "", new R2dbcDataIntegrityViolationException()); assertThat(exception).isExactlyInstanceOf(DataIntegrityViolationException.class); - - exception = ConnectionFactoryUtils.convertR2dbcException("", "", - new R2dbcDataIntegrityViolationException("reason", "23505")); - assertThat(exception).isExactlyInstanceOf(DuplicateKeyException.class); - - exception = ConnectionFactoryUtils.convertR2dbcException("", "", - new R2dbcDataIntegrityViolationException("reason", "23000", 1)); - assertThat(exception).as("Oracle").isExactlyInstanceOf(DuplicateKeyException.class); - - exception = ConnectionFactoryUtils.convertR2dbcException("", "", - new R2dbcDataIntegrityViolationException("reason", "23000", 301)); - assertThat(exception).as("SAP HANA").isExactlyInstanceOf(DuplicateKeyException.class); - - exception = ConnectionFactoryUtils.convertR2dbcException("", "", - new R2dbcDataIntegrityViolationException("reason", "23000", 1062)); - assertThat(exception).as("MySQL/MariaDB").isExactlyInstanceOf(DuplicateKeyException.class); - - exception = ConnectionFactoryUtils.convertR2dbcException("", "", - new R2dbcDataIntegrityViolationException("reason", "23000", 2601)); - assertThat(exception).as("MS SQL Server").isExactlyInstanceOf(DuplicateKeyException.class); - - exception = ConnectionFactoryUtils.convertR2dbcException("", "", - new R2dbcDataIntegrityViolationException("reason", "23000", 2627)); - assertThat(exception).as("MS SQL Server").isExactlyInstanceOf(DuplicateKeyException.class); } @Test