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 f9e0a492f4af..264f9ec28336 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 @@ -81,6 +81,11 @@ public void translateDuplicateKeyMSSQL2() { doTest("23000", 2627, DuplicateKeyException.class); } + @Test + public void translateDuplicateKeySapHana() { + doTest("23000", 301, DuplicateKeyException.class); + } + @Test public void translateDataAccessResourceFailure() { doTest("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 4c7e07683d3c..fcbe5303d627 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 @@ -16,6 +16,8 @@ package org.springframework.r2dbc.connection; +import java.util.Set; + import io.r2dbc.spi.Connection; import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.R2dbcBadGrammarException; @@ -69,6 +71,14 @@ public abstract class ConnectionFactoryUtils { */ public static final int CONNECTION_SYNCHRONIZATION_ORDER = 1000; + private static final Set DUPLICATE_KEY_ERROR_CODES = Set.of( + 1, // Oracle + 301, // Sap Hana + 1062, // MySQL/MariaDB + 2601, // MS SQL Server + 2627 // MS SQL Server + ); + /** * Obtain a {@link Connection} from the given {@link ConnectionFactory}. @@ -255,8 +265,7 @@ else if (ex instanceof R2dbcNonTransientException) { */ static boolean indicatesDuplicateKey(@Nullable String sqlState, int errorCode) { return ("23505".equals(sqlState) || - ("23000".equals(sqlState) && - (errorCode == 1 || errorCode == 1062 || errorCode == 2601 || errorCode == 2627))); + ("23000".equals(sqlState) && DUPLICATE_KEY_ERROR_CODES.contains(errorCode))); } /** diff --git a/spring-r2dbc/src/test/java/org/springframework/r2dbc/connection/ConnectionFactoryUtilsUnitTests.java b/spring-r2dbc/src/test/java/org/springframework/r2dbc/connection/ConnectionFactoryUtilsUnitTests.java index 9292f11dd377..5c8cb206a2a8 100644 --- a/spring-r2dbc/src/test/java/org/springframework/r2dbc/connection/ConnectionFactoryUtilsUnitTests.java +++ b/spring-r2dbc/src/test/java/org/springframework/r2dbc/connection/ConnectionFactoryUtilsUnitTests.java @@ -100,6 +100,10 @@ public void shouldTranslateIntegrityViolationException() { new R2dbcDataIntegrityViolationException("reason", "23000", 1)); assertThat(exception).isExactlyInstanceOf(DuplicateKeyException.class); + exception = ConnectionFactoryUtils.convertR2dbcException("", "", + new R2dbcDataIntegrityViolationException("reason", "23000", 301)); + assertThat(exception).isExactlyInstanceOf(DuplicateKeyException.class); + exception = ConnectionFactoryUtils.convertR2dbcException("", "", new R2dbcDataIntegrityViolationException("reason", "23000", 1062)); assertThat(exception).isExactlyInstanceOf(DuplicateKeyException.class);