Skip to content

Commit

Permalink
Fall back to plain setObject call for non-supported SQL type
Browse files Browse the repository at this point in the history
Closes gh-30556
  • Loading branch information
jhoeller committed Jun 3, 2023
1 parent 4b8adf2 commit d290625
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Types;
import java.time.LocalDate;
import java.time.LocalDateTime;
Expand Down Expand Up @@ -84,7 +85,7 @@ public abstract class StatementCreatorUtils {

private static final Log logger = LogFactory.getLog(StatementCreatorUtils.class);

private static final Map<Class<?>, Integer> javaTypeToSqlTypeMap = new HashMap<>(32);
private static final Map<Class<?>, Integer> javaTypeToSqlTypeMap = new HashMap<>(64);

static {
javaTypeToSqlTypeMap.put(boolean.class, Types.BOOLEAN);
Expand All @@ -106,8 +107,8 @@ public abstract class StatementCreatorUtils {
javaTypeToSqlTypeMap.put(LocalDate.class, Types.DATE);
javaTypeToSqlTypeMap.put(LocalTime.class, Types.TIME);
javaTypeToSqlTypeMap.put(LocalDateTime.class, Types.TIMESTAMP);
javaTypeToSqlTypeMap.put(OffsetDateTime.class, Types.TIMESTAMP_WITH_TIMEZONE);
javaTypeToSqlTypeMap.put(OffsetTime.class, Types.TIME_WITH_TIMEZONE);
javaTypeToSqlTypeMap.put(OffsetDateTime.class, Types.TIMESTAMP_WITH_TIMEZONE);
javaTypeToSqlTypeMap.put(java.sql.Date.class, Types.DATE);
javaTypeToSqlTypeMap.put(java.sql.Time.class, Types.TIME);
javaTypeToSqlTypeMap.put(java.sql.Timestamp.class, Types.TIMESTAMP);
Expand Down Expand Up @@ -290,7 +291,19 @@ else if (typeName != null) {
ps.setNull(paramIndex, sqlType, typeName);
}
else {
ps.setNull(paramIndex, sqlType);
// Fall back to generic setNull call.
try {
// Try generic setNull call with SQL type specified.
ps.setNull(paramIndex, sqlType);
}
catch (SQLFeatureNotSupportedException ex) {
if (sqlType == Types.NULL) {
throw ex;
}
// Fall back to generic setNull call without SQL type specified
// (e.g. for MySQL TIME_WITH_TIMEZONE / TIMESTAMP_WITH_TIMEZONE).
ps.setNull(paramIndex, Types.NULL);
}
}
}

Expand Down Expand Up @@ -415,8 +428,16 @@ else if (inValue instanceof Calendar cal) {
}
}
else {
// Fall back to generic setObject call with SQL type specified.
ps.setObject(paramIndex, inValue, sqlType);
// Fall back to generic setObject call.
try {
// Try generic setObject call with SQL type specified.
ps.setObject(paramIndex, inValue, sqlType);
}
catch (SQLFeatureNotSupportedException ex) {
// Fall back to generic setObject call without SQL type specified
// (e.g. for MySQL TIME_WITH_TIMEZONE / TIMESTAMP_WITH_TIMEZONE).
ps.setObject(paramIndex, inValue);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Types;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.GregorianCalendar;
import java.util.stream.Stream;
Expand All @@ -36,6 +38,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Named.named;
import static org.mockito.BDDMockito.doThrow;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
Expand Down Expand Up @@ -213,7 +216,6 @@ public void testSetParameterValueWithCalendarAndUnknownType() throws SQLExceptio
verify(preparedStatement).setTimestamp(1, new java.sql.Timestamp(cal.getTime().getTime()), cal);
}


@ParameterizedTest
@MethodSource("javaTimeTypes")
public void testSetParameterValueWithJavaTimeTypes(Object o, int sqlType) throws SQLException {
Expand Down Expand Up @@ -242,6 +244,23 @@ static Stream<Arguments> javaTimeTypes() {
);
}

@Test // gh-30556
public void testSetParameterValueWithOffsetDateTimeAndNotSupported() throws SQLException {
OffsetDateTime time = OffsetDateTime.now();
doThrow(new SQLFeatureNotSupportedException()).when(preparedStatement).setObject(1, time, Types.TIMESTAMP_WITH_TIMEZONE);
StatementCreatorUtils.setParameterValue(preparedStatement, 1, Types.TIMESTAMP_WITH_TIMEZONE, null, time);
verify(preparedStatement).setObject(1, time, Types.TIMESTAMP_WITH_TIMEZONE);
verify(preparedStatement).setObject(1, time);
}

@Test // gh-30556
public void testSetParameterValueWithNullAndNotSupported() throws SQLException {
doThrow(new SQLFeatureNotSupportedException()).when(preparedStatement).setNull(1, Types.TIMESTAMP_WITH_TIMEZONE);
StatementCreatorUtils.setParameterValue(preparedStatement, 1, Types.TIMESTAMP_WITH_TIMEZONE, null, null);
verify(preparedStatement).setNull(1, Types.TIMESTAMP_WITH_TIMEZONE);
verify(preparedStatement).setNull(1, Types.NULL);
}

@Test // SPR-8571
public void testSetParameterValueWithStringAndVendorSpecificType() throws SQLException {
Connection con = mock();
Expand Down

0 comments on commit d290625

Please sign in to comment.