Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
1. Pipeline: Improve "alter transmission rule": verify STREAM_CHANNEL TYPE NAME - [#36864](https://github.com/apache/shardingsphere/pull/36864)
1. Pipeline: InventoryDumperContextSplitter supports multi-columns unique key first integer column splitting - [#36935](https://github.com/apache/shardingsphere/pull/36935)
1. Encrypt: Support handling show create view result decoration in encrypt - [#37299](https://github.com/apache/shardingsphere/pull/37299)
1. JDBC: Enhance ResultSetUtils to support flexible string date/time conversions - [37424](https://github.com/apache/shardingsphere/pull/37424)

### Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,25 @@
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Optional;

/**
* Result set utility class.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class ResultSetUtils {

private static final DateTimeFormatter LOOSE_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(
"[yyyy-MM-dd][yyyy_MM_dd][yyyyMMdd][yyyy-M-d][MM/dd/yy][yyMMdd]"
+ "['T'][ ]"
+ "[HH:mm:ss][HHmmss][HH:mm][HHmm]"
+ "[.SSSSSSSSS][.SSSSSSSS][.SSSSSSS][.SSSSSS][.SSSSS][.SSSS][.SSS][.SS][.S]"
+ "[ ]"
+ "[XXXXX][XXXX][XXX][XX][X]");

/**
* Convert value via expected class type.
*
Expand Down Expand Up @@ -88,13 +99,34 @@ public static Object convertValue(final Object value, final Class<?> convertType
if (String.class.equals(convertType)) {
return value.toString();
}
if (value instanceof String) {
Optional<Object> result = convertStringValue((String) value, convertType);
if (result.isPresent()) {
return result.get();
}
}
try {
return convertType.cast(value);
} catch (final ClassCastException ignored) {
throw new SQLFeatureNotSupportedException("getObject with type, cannot convert " + value.getClass().getName() + ":" + value + " to " + convertType.getName());
}
}

private static Optional<Object> convertStringValue(final String value, final Class<?> convertType) {
if (Timestamp.class.equals(convertType)) {
TemporalAccessor temporalAccessor = LOOSE_DATE_TIME_FORMATTER.parseBest(value, LocalDateTime::from, LocalDate::from);
LocalDateTime localDateTime = (temporalAccessor instanceof LocalDateTime) ? (LocalDateTime) temporalAccessor : ((LocalDate) temporalAccessor).atStartOfDay();
return Optional.of(Timestamp.valueOf(localDateTime));
}
if (java.sql.Date.class.equals(convertType)) {
return Optional.of(java.sql.Date.valueOf(LocalDate.from(LOOSE_DATE_TIME_FORMATTER.parse(value))));
}
if (java.sql.Time.class.equals(convertType)) {
return Optional.of(java.sql.Time.valueOf(LocalTime.from(LOOSE_DATE_TIME_FORMATTER.parse(value))));
}
return Optional.empty();
}

private static Object convertNullValue(final Class<?> convertType) {
switch (convertType.getName()) {
case "boolean":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,165 @@ void assertConvertDateValueToLocalDateWithCurrentDate() throws SQLException {
java.sql.Date sqlDate = new java.sql.Date(now.getTime());
assertThat(result, is(sqlDate.toLocalDate()));
}

@Test
void assertConvertStringValueToTimestamp() throws SQLException {
String dateTimeStr = "2021-12-23 19:30:45";
Timestamp result = (Timestamp) ResultSetUtils.convertValue(dateTimeStr, Timestamp.class);
assertThat(result, is(Timestamp.valueOf(LocalDateTime.of(2021, 12, 23, 19, 30, 45))));
}

@Test
void assertConvertStringValueToTimestampWithISOFormat() throws SQLException {
String dateTimeStr = "2021-12-23T19:30:45";
Timestamp result = (Timestamp) ResultSetUtils.convertValue(dateTimeStr, Timestamp.class);
assertThat(result, is(Timestamp.valueOf(LocalDateTime.of(2021, 12, 23, 19, 30, 45))));
}

@Test
void assertConvertStringValueToTimestampWithMilliseconds() throws SQLException {
String dateTimeStr = "2021-12-23 19:30:45.123";
Timestamp result = (Timestamp) ResultSetUtils.convertValue(dateTimeStr, Timestamp.class);
Timestamp expected = Timestamp.valueOf(LocalDateTime.of(2021, 12, 23, 19, 30, 45, 123000000));
assertThat(result, is(expected));
}

@Test
void assertConvertStringValueToTimestampWithDateOnly() throws SQLException {
String dateStr = "2021-12-23";
Timestamp result = (Timestamp) ResultSetUtils.convertValue(dateStr, Timestamp.class);
assertThat(result, is(Timestamp.valueOf(LocalDateTime.of(2021, 12, 23, 0, 0, 0))));
}

@Test
void assertConvertStringValueToTimestampWithCompactFormat() throws SQLException {
String dateTimeStr = "20211223 193045";
Timestamp result = (Timestamp) ResultSetUtils.convertValue(dateTimeStr, Timestamp.class);
assertThat(result, is(Timestamp.valueOf(LocalDateTime.of(2021, 12, 23, 19, 30, 45))));
}

@Test
void assertConvertStringValueToTimestampWithUnderscoreFormat() throws SQLException {
String dateTimeStr = "2021_12_23 19:30:45";
Timestamp result = (Timestamp) ResultSetUtils.convertValue(dateTimeStr, Timestamp.class);
assertThat(result, is(Timestamp.valueOf(LocalDateTime.of(2021, 12, 23, 19, 30, 45))));
}

@Test
void assertConvertStringValueToSqlDate() throws SQLException {
String dateStr = "2021-12-23";
java.sql.Date result = (java.sql.Date) ResultSetUtils.convertValue(dateStr, java.sql.Date.class);
assertThat(result, is(java.sql.Date.valueOf(LocalDate.of(2021, 12, 23))));
}

@Test
void assertConvertStringValueToSqlDateWithCompactFormat() throws SQLException {
String dateStr = "20211223";
java.sql.Date result = (java.sql.Date) ResultSetUtils.convertValue(dateStr, java.sql.Date.class);
assertThat(result, is(java.sql.Date.valueOf(LocalDate.of(2021, 12, 23))));
}

@Test
void assertConvertStringValueToSqlDateWithUnderscoreFormat() throws SQLException {
String dateStr = "2021_12_23";
java.sql.Date result = (java.sql.Date) ResultSetUtils.convertValue(dateStr, java.sql.Date.class);
assertThat(result, is(java.sql.Date.valueOf(LocalDate.of(2021, 12, 23))));
}

@Test
void assertConvertStringValueToSqlDateWithSlashFormat() throws SQLException {
String dateStr = "12/23/21";
java.sql.Date result = (java.sql.Date) ResultSetUtils.convertValue(dateStr, java.sql.Date.class);
assertThat(result, is(java.sql.Date.valueOf(LocalDate.of(2021, 12, 23))));
}

@Test
void assertConvertStringValueToSqlDateWithSingleDigitMonth() throws SQLException {
String dateStr = "2021-1-5";
java.sql.Date result = (java.sql.Date) ResultSetUtils.convertValue(dateStr, java.sql.Date.class);
assertThat(result, is(java.sql.Date.valueOf(LocalDate.of(2021, 1, 5))));
}

@Test
void assertConvertStringValueToSqlTime() throws SQLException {
String timeStr = "19:30:45";
Time result = (Time) ResultSetUtils.convertValue(timeStr, Time.class);
assertThat(result, is(Time.valueOf(LocalTime.of(19, 30, 45))));
}

@Test
void assertConvertStringValueToSqlTimeWithMilliseconds() throws SQLException {
String timeStr = "19:30:45.123";
Time result = (Time) ResultSetUtils.convertValue(timeStr, Time.class);
LocalTime localTime = LocalTime.of(19, 30, 45, 123000000);
assertThat(result, is(Time.valueOf(localTime)));
}

@Test
void assertConvertStringValueToSqlTimeWithShortFormat() throws SQLException {
String timeStr = "19:30";
Time result = (Time) ResultSetUtils.convertValue(timeStr, Time.class);
assertThat(result, is(Time.valueOf(LocalTime.of(19, 30, 0))));
}

@Test
void assertConvertStringValueWithUnsupportedTypeReturnsString() throws SQLException {
String value = "test string";
String result = (String) ResultSetUtils.convertValue(value, String.class);
assertThat(result, is("test string"));
}

@Test
void assertConvertStringValueWithInvalidTimestampFormat() {
String invalidDateStr = "invalid-date-time";
assertThrows(Exception.class, () -> ResultSetUtils.convertValue(invalidDateStr, Timestamp.class));
}

@Test
void assertConvertStringValueWithInvalidDateFormat() {
String invalidDateStr = "not-a-date";
assertThrows(Exception.class, () -> ResultSetUtils.convertValue(invalidDateStr, java.sql.Date.class));
}

@Test
void assertConvertStringValueWithInvalidTimeFormat() {
String invalidTimeStr = "not-a-time";
assertThrows(Exception.class, () -> ResultSetUtils.convertValue(invalidTimeStr, Time.class));
}

@Test
void assertConvertStringValueToTimestampWithEpoch() throws SQLException {
String dateTimeStr = "1970-01-01 00:00:00";
Timestamp result = (Timestamp) ResultSetUtils.convertValue(dateTimeStr, Timestamp.class);
assertThat(result, is(Timestamp.valueOf(LocalDateTime.of(1970, 1, 1, 0, 0, 0))));
}

@Test
void assertConvertStringValueToTimestampWithNanoseconds() throws SQLException {
String dateTimeStr = "2021-12-23 19:30:45.123456789";
Timestamp result = (Timestamp) ResultSetUtils.convertValue(dateTimeStr, Timestamp.class);
Timestamp expected = Timestamp.valueOf(LocalDateTime.of(2021, 12, 23, 19, 30, 45, 123456789));
assertThat(result, is(expected));
}

@Test
void assertConvertStringValueToSqlDateWithEpoch() throws SQLException {
String dateStr = "1970-01-01";
java.sql.Date result = (java.sql.Date) ResultSetUtils.convertValue(dateStr, java.sql.Date.class);
assertThat(result, is(java.sql.Date.valueOf(LocalDate.of(1970, 1, 1))));
}

@Test
void assertConvertStringValueToSqlTimeMidnight() throws SQLException {
String timeStr = "00:00:00";
Time result = (Time) ResultSetUtils.convertValue(timeStr, Time.class);
assertThat(result, is(Time.valueOf(LocalTime.of(0, 0, 0))));
}

@Test
void assertConvertStringValueToSqlTimeEndOfDay() throws SQLException {
String timeStr = "23:59:59";
Time result = (Time) ResultSetUtils.convertValue(timeStr, Time.class);
assertThat(result, is(Time.valueOf(LocalTime.of(23, 59, 59))));
}
}
Loading