Merge branch '6.2.x'

This commit is contained in:
Sam Brannen 2025-09-03 16:29:55 +02:00
commit 80a7371510
4 changed files with 48 additions and 30 deletions

View File

@ -95,7 +95,9 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
301, // SAP HANA 301, // SAP HANA
1062, // MySQL/MariaDB 1062, // MySQL/MariaDB
2601, // MS SQL Server 2601, // MS SQL Server
2627 // MS SQL Server 2627, // MS SQL Server
-239, // Informix
-268 // Informix
); );

View File

@ -90,6 +90,16 @@ class SQLStateSQLExceptionTranslatorTests {
assertTranslation("23000", 301, DuplicateKeyException.class); assertTranslation("23000", 301, DuplicateKeyException.class);
} }
@Test
void translateDuplicateKeyInformix1() {
assertTranslation("23000", -239, DuplicateKeyException.class);
}
@Test
void translateDuplicateKeyInformix2() {
assertTranslation("23000", -268, DuplicateKeyException.class);
}
@Test @Test
void translateDataAccessResourceFailure() { void translateDataAccessResourceFailure() {
assertTranslation("53", DataAccessResourceFailureException.class); assertTranslation("53", DataAccessResourceFailureException.class);

View File

@ -76,7 +76,9 @@ public abstract class ConnectionFactoryUtils {
301, // SAP HANA 301, // SAP HANA
1062, // MySQL/MariaDB 1062, // MySQL/MariaDB
2601, // MS SQL Server 2601, // MS SQL Server
2627 // MS SQL Server 2627, // MS SQL Server
-239, // Informix
-268 // Informix
); );

View File

@ -16,6 +16,8 @@
package org.springframework.r2dbc.connection; package org.springframework.r2dbc.connection;
import java.util.List;
import io.r2dbc.spi.R2dbcBadGrammarException; import io.r2dbc.spi.R2dbcBadGrammarException;
import io.r2dbc.spi.R2dbcDataIntegrityViolationException; import io.r2dbc.spi.R2dbcDataIntegrityViolationException;
import io.r2dbc.spi.R2dbcException; import io.r2dbc.spi.R2dbcException;
@ -25,6 +27,9 @@ import io.r2dbc.spi.R2dbcRollbackException;
import io.r2dbc.spi.R2dbcTimeoutException; import io.r2dbc.spi.R2dbcTimeoutException;
import io.r2dbc.spi.R2dbcTransientResourceException; import io.r2dbc.spi.R2dbcTransientResourceException;
import org.junit.jupiter.api.Test; 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.FieldSource;
import org.springframework.dao.CannotAcquireLockException; import org.springframework.dao.CannotAcquireLockException;
import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.DataAccessResourceFailureException;
@ -38,6 +43,7 @@ import org.springframework.r2dbc.BadSqlGrammarException;
import org.springframework.r2dbc.UncategorizedR2dbcException; import org.springframework.r2dbc.UncategorizedR2dbcException;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.params.provider.Arguments.arguments;
/** /**
* Tests for {@link ConnectionFactoryUtils}. * Tests for {@link ConnectionFactoryUtils}.
@ -91,30 +97,25 @@ class ConnectionFactoryUtilsTests {
Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "", Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "",
new R2dbcDataIntegrityViolationException()); new R2dbcDataIntegrityViolationException());
assertThat(exception).isExactlyInstanceOf(DataIntegrityViolationException.class); assertThat(exception).isExactlyInstanceOf(DataIntegrityViolationException.class);
}
exception = ConnectionFactoryUtils.convertR2dbcException("", "", static final List<Arguments> duplicateKeyErrorCodes = List.of(
new R2dbcDataIntegrityViolationException("reason", "23505")); arguments("Oracle", "23505", 0),
assertThat(exception).isExactlyInstanceOf(DuplicateKeyException.class); arguments("Oracle", "23000", 1),
arguments("SAP HANA", "23000", 301),
arguments("MySQL/MariaDB", "23000", 1062),
arguments("MS SQL Server", "23000", 2601),
arguments("MS SQL Server", "23000", 2627),
arguments("Informix", "23000", -239),
arguments("Informix", "23000", -268)
);
exception = ConnectionFactoryUtils.convertR2dbcException("", "", @ParameterizedTest
new R2dbcDataIntegrityViolationException("reason", "23000", 1)); @FieldSource("duplicateKeyErrorCodes")
assertThat(exception).as("Oracle").isExactlyInstanceOf(DuplicateKeyException.class); void shouldTranslateIntegrityViolationExceptionToDuplicateKeyException(String db, String sqlState, int errorCode) {
Exception exception = ConnectionFactoryUtils.convertR2dbcException("", "",
exception = ConnectionFactoryUtils.convertR2dbcException("", "", new R2dbcDataIntegrityViolationException("reason", sqlState, errorCode));
new R2dbcDataIntegrityViolationException("reason", "23000", 301)); assertThat(exception).as(db).isExactlyInstanceOf(DuplicateKeyException.class);
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 @Test
@ -135,24 +136,27 @@ class ConnectionFactoryUtilsTests {
void messageGeneration() { void messageGeneration() {
Exception exception = ConnectionFactoryUtils.convertR2dbcException("TASK", Exception exception = ConnectionFactoryUtils.convertR2dbcException("TASK",
"SOME-SQL", new R2dbcTransientResourceException("MESSAGE")); "SOME-SQL", new R2dbcTransientResourceException("MESSAGE"));
assertThat(exception).isExactlyInstanceOf( assertThat(exception)
TransientDataAccessResourceException.class).hasMessage("TASK; SQL [SOME-SQL]; MESSAGE"); .isExactlyInstanceOf(TransientDataAccessResourceException.class)
.hasMessage("TASK; SQL [SOME-SQL]; MESSAGE");
} }
@Test @Test
void messageGenerationNullSQL() { void messageGenerationNullSQL() {
Exception exception = ConnectionFactoryUtils.convertR2dbcException("TASK", null, Exception exception = ConnectionFactoryUtils.convertR2dbcException("TASK", null,
new R2dbcTransientResourceException("MESSAGE")); new R2dbcTransientResourceException("MESSAGE"));
assertThat(exception).isExactlyInstanceOf( assertThat(exception)
TransientDataAccessResourceException.class).hasMessage("TASK; MESSAGE"); .isExactlyInstanceOf(TransientDataAccessResourceException.class)
.hasMessage("TASK; MESSAGE");
} }
@Test @Test
void messageGenerationNullMessage() { void messageGenerationNullMessage() {
Exception exception = ConnectionFactoryUtils.convertR2dbcException("TASK", Exception exception = ConnectionFactoryUtils.convertR2dbcException("TASK",
"SOME-SQL", new R2dbcTransientResourceException()); "SOME-SQL", new R2dbcTransientResourceException());
assertThat(exception).isExactlyInstanceOf( assertThat(exception)
TransientDataAccessResourceException.class).hasMessage("TASK; SQL [SOME-SQL]; null"); .isExactlyInstanceOf(TransientDataAccessResourceException.class)
.hasMessage("TASK; SQL [SOME-SQL]; null");
} }