WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 53609c5

Browse files
authored
Merge pull request #2682 from ClickHouse/jdbc_time_datatype_convertion
[jdbc-v2] Handling Time Time64 in JDBC
2 parents 81b12e7 + 9c3fe16 commit 53609c5

File tree

3 files changed

+65
-27
lines changed

3 files changed

+65
-27
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: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
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;
67
import com.clickhouse.data.ClickHouseDataType;
78
import com.clickhouse.data.Tuple;
8-
import com.clickhouse.data.format.BinaryStreamUtils;
9-
import com.clickhouse.jdbc.PreparedStatementImpl;
109
import com.clickhouse.jdbc.types.Array;
1110
import com.google.common.collect.ImmutableMap;
12-
import org.slf4j.Logger;
1311

14-
import java.awt.*;
1512
import java.math.BigInteger;
1613
import java.net.Inet4Address;
1714
import java.net.Inet6Address;
@@ -20,12 +17,14 @@
2017
import java.sql.JDBCType;
2118
import java.sql.SQLException;
2219
import java.sql.SQLType;
23-
import java.sql.Types;
24-
import java.time.*;
25-
import java.time.chrono.ChronoZonedDateTime;
20+
import java.sql.Time;
21+
import java.time.Instant;
22+
import java.time.LocalDate;
23+
import java.time.LocalDateTime;
24+
import java.time.LocalTime;
25+
import java.time.OffsetDateTime;
26+
import java.time.ZonedDateTime;
2627
import java.time.temporal.TemporalAccessor;
27-
import java.util.ArrayList;
28-
import java.util.Arrays;
2928
import java.util.Collections;
3029
import java.util.EnumSet;
3130
import java.util.HashMap;
@@ -35,7 +34,6 @@
3534
import java.util.Stack;
3635
import java.util.TreeMap;
3736
import java.util.function.Function;
38-
import java.util.stream.Collectors;
3937

4038
public class JdbcUtils {
4139
//Define a map to store the mapping between ClickHouse data types and SQL data types
@@ -297,10 +295,10 @@ public static Object convert(Object value, Class<?> type, ClickHouseColumn colum
297295
return new Array(column, arrayValue.getArrayOfObjects());
298296
}
299297

300-
return convertObject(value, type);
298+
return convertObject(value, type, column);
301299
}
302300

303-
public static Object convertObject(Object value, Class<?> type) throws SQLException {
301+
public static Object convertObject(Object value, Class<?> type, ClickHouseColumn column) throws SQLException {
304302
if (value == null || type == null) {
305303
return value;
306304
}
@@ -343,6 +341,11 @@ public static Object convertObject(Object value, Class<?> type) throws SQLExcept
343341
} else if (type == java.sql.Time.class) {
344342
return java.sql.Time.valueOf(LocalTime.from(temporalValue));
345343
}
344+
} else if (type == Time.class && value instanceof Integer) { // Time
345+
return new Time((Integer) value * 1000L);
346+
} else if (type == Time.class && value instanceof Long) { // Time64
347+
Instant instant = DataTypeUtils.instantFromTime64Integer(column.getScale(), (Long) value);
348+
return new Time(instant.getEpochSecond() * 1000L + instant.getNano() / 1_000_000);
346349
} else if (type == Inet4Address.class && value instanceof Inet6Address) {
347350
// Convert Inet6Address to Inet4Address
348351
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 conversion is not supported
663+
assertThrows(SQLException.class, () -> rs.getObject(col, LocalTime.class));
664+
}
650665
assertFalse(rs.next());
651666
}
652667
}

0 commit comments

Comments
 (0)