Skip to content

Commit 597ad85

Browse files
committed
added Time/Tim64 convertion to Time and handling other types
1 parent 81b12e7 commit 597ad85

File tree

3 files changed

+58
-17
lines changed

3 files changed

+58
-17
lines changed

jdbc-v2/src/main/java/com/clickhouse/jdbc/ResultSetImpl.java

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.sql.Statement;
3434
import java.sql.Time;
3535
import java.sql.Timestamp;
36+
import java.time.Instant;
3637
import java.time.ZonedDateTime;
3738
import java.util.Calendar;
3839
import java.util.Collections;
@@ -1035,18 +1036,37 @@ public Time getTime(int columnIndex, Calendar cal) throws SQLException {
10351036
@Override
10361037
public Time getTime(String columnLabel, Calendar cal) throws SQLException {
10371038
checkClosed();
1039+
10381040
try {
1039-
ZonedDateTime zdt = reader.getZonedDateTime(columnLabel);
1040-
if (zdt == null) {
1041-
wasNull = true;
1042-
return null;
1041+
ClickHouseColumn column = getSchema().getColumnByName(columnLabel);
1042+
switch (column.getDataType()) {
1043+
case Time:
1044+
case Time64:
1045+
Instant instant = reader.getInstant(columnLabel);
1046+
if (instant == null) {
1047+
wasNull = true;
1048+
return null;
1049+
}
1050+
wasNull = false;
1051+
return new Time(instant.getEpochSecond() * 1000L + instant.getNano() / 1_000_000);
1052+
case DateTime:
1053+
case DateTime32:
1054+
case DateTime64:
1055+
ZonedDateTime zdt = reader.getZonedDateTime(columnLabel);
1056+
if (zdt == null) {
1057+
wasNull = true;
1058+
return null;
1059+
}
1060+
wasNull = false;
1061+
1062+
Calendar c = (Calendar) (cal != null ? cal : defaultCalendar).clone();
1063+
c.clear();
1064+
c.set(1970, Calendar.JANUARY, 1, zdt.getHour(), zdt.getMinute(), zdt.getSecond());
1065+
return new Time(c.getTimeInMillis());
1066+
default:
1067+
throw new SQLException("Column \"" + columnLabel + "\" is not a time type.");
10431068
}
1044-
wasNull = false;
10451069

1046-
Calendar c = (Calendar) (cal != null ? cal : defaultCalendar).clone();
1047-
c.clear();
1048-
c.set(1970, Calendar.JANUARY, 1, zdt.getHour(), zdt.getMinute(), zdt.getSecond());
1049-
return new Time(c.getTimeInMillis());
10501070
} catch (Exception e) {
10511071
throw ExceptionUtils.toSqlState(String.format("Method: getTime(\"%s\") encountered an exception.", columnLabel), String.format("SQL: [%s]", parentStatement.getLastStatementSql()), e);
10521072
}

jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcUtils.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.clickhouse.jdbc.internal;
22

3+
import com.clickhouse.client.api.DataTypeUtils;
34
import com.clickhouse.client.api.data_formats.internal.BinaryStreamReader;
45
import com.clickhouse.client.api.data_formats.internal.InetAddressConverter;
56
import com.clickhouse.data.ClickHouseColumn;
@@ -20,6 +21,7 @@
2021
import java.sql.JDBCType;
2122
import java.sql.SQLException;
2223
import java.sql.SQLType;
24+
import java.sql.Time;
2325
import java.sql.Types;
2426
import java.time.*;
2527
import java.time.chrono.ChronoZonedDateTime;
@@ -297,10 +299,10 @@ public static Object convert(Object value, Class<?> type, ClickHouseColumn colum
297299
return new Array(column, arrayValue.getArrayOfObjects());
298300
}
299301

300-
return convertObject(value, type);
302+
return convertObject(value, type, column);
301303
}
302304

303-
public static Object convertObject(Object value, Class<?> type) throws SQLException {
305+
public static Object convertObject(Object value, Class<?> type, ClickHouseColumn column) throws SQLException {
304306
if (value == null || type == null) {
305307
return value;
306308
}
@@ -343,6 +345,10 @@ public static Object convertObject(Object value, Class<?> type) throws SQLExcept
343345
} else if (type == java.sql.Time.class) {
344346
return java.sql.Time.valueOf(LocalTime.from(temporalValue));
345347
}
348+
} else if (type == Time.class && value instanceof Integer) { // Time
349+
return new Time((Integer) value * 1000L);
350+
} else if (type == Time.class && value instanceof Long) { // Time64
351+
return new Time((Long) value / 1_000_000);
346352
} else if (type == Inet4Address.class && value instanceof Inet6Address) {
347353
// Convert Inet6Address to Inet4Address
348354
return InetAddressConverter.convertToIpv4((InetAddress) value);

jdbc-v2/src/test/java/com/clickhouse/jdbc/DataTypeTests.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,17 @@
3232
import java.sql.ResultSetMetaData;
3333
import java.sql.SQLException;
3434
import java.sql.Statement;
35+
import java.sql.Time;
3536
import java.sql.Timestamp;
3637
import java.sql.Types;
3738
import java.text.DecimalFormat;
3839
import java.time.Instant;
3940
import java.time.LocalDate;
4041
import java.time.LocalDateTime;
42+
import java.time.LocalTime;
4143
import java.time.OffsetDateTime;
4244
import java.time.ZoneId;
45+
import java.time.ZoneOffset;
4346
import java.time.ZonedDateTime;
4447
import java.util.ArrayList;
4548
import java.util.Arrays;
@@ -635,18 +638,30 @@ public void testTimeTypes() throws SQLException {
635638
try (ResultSet rs = stmt.executeQuery("SELECT * FROM test_time64")) {
636639
assertTrue(rs.next());
637640
assertEquals(rs.getInt("order"), 1);
638-
// assertEquals(rs.getInt("time"), -(TimeUnit.HOURS.toSeconds(999) + TimeUnit.MINUTES.toSeconds(59) + 59));
639-
// assertEquals(rs.getInt("time64"), -(TimeUnit.HOURS.toSeconds(999) + TimeUnit.MINUTES.toSeconds(59) + 59));
641+
assertEquals(rs.getInt("time"), -(TimeUnit.HOURS.toSeconds(999) + TimeUnit.MINUTES.toSeconds(59) + 59));
642+
assertEquals(rs.getLong("time64"), -((TimeUnit.HOURS.toNanos(999) + TimeUnit.MINUTES.toNanos(59) + TimeUnit.SECONDS.toNanos(59)) + 999999999));
640643

641644
assertTrue(rs.next());
642645
assertEquals(rs.getInt("order"), 2);
643646
assertEquals(rs.getInt("time"), (TimeUnit.HOURS.toSeconds(999) + TimeUnit.MINUTES.toSeconds(59) + 59));
644647
assertEquals(rs.getLong("time64"), (TimeUnit.HOURS.toNanos(999) + TimeUnit.MINUTES.toNanos(59) + TimeUnit.SECONDS.toNanos(59)) + 999999999);
645648

646-
assertThrows(SQLException.class, () -> rs.getTime("time"));
647-
assertThrows(SQLException.class, () -> rs.getDate("time"));
648-
assertThrows(SQLException.class, () -> rs.getTimestamp("time"));
649-
649+
Time time = rs.getTime("time");
650+
assertEquals(time.getTime(), rs.getInt("time") * 1000L); // time is in seconds
651+
assertEquals(time.getTime(), rs.getObject("time", Time.class).getTime());
652+
Time time64 = rs.getTime("time64");
653+
assertEquals(time64.getTime(), rs.getLong("time64") / 1_000_000); // time64 is in nanoseconds
654+
assertEquals(time64, rs.getObject("time64", Time.class));
655+
656+
// time has no date part and cannot be converted to Date or Timestamp
657+
for (String col : Arrays.asList("time", "time64")) {
658+
assertThrows(SQLException.class, () -> rs.getDate(col));
659+
assertThrows(SQLException.class, () -> rs.getTimestamp(col));
660+
assertThrows(SQLException.class, () -> rs.getObject(col, Date.class));
661+
assertThrows(SQLException.class, () -> rs.getObject(col, Timestamp.class));
662+
// LocalTime requires ZoneId and date part
663+
assertThrows(SQLException.class, () -> rs.getObject(col, LocalTime.class));
664+
}
650665
assertFalse(rs.next());
651666
}
652667
}

0 commit comments

Comments
 (0)