Skip to content

Commit 34391ed

Browse files
committed
done handling index column as normal value. done retreiving date/time values
1 parent f472b44 commit 34391ed

File tree

5 files changed

+167
-29
lines changed

5 files changed

+167
-29
lines changed

client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/ValueConverters.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
import java.math.BigDecimal;
66
import java.math.BigInteger;
7-
import java.util.Arrays;
7+
import java.sql.Date;
8+
import java.sql.Time;
9+
import java.sql.Timestamp;
10+
import java.time.ZonedDateTime;
811
import java.util.Collections;
9-
import java.util.List;
1012
import java.util.Map;
1113
import java.util.function.Function;
1214

@@ -100,6 +102,10 @@ public ValueConverters() {
100102
stringMapBuilder.put(byte[].class, this::convertStringToBytes);
101103
mapBuilder.put(String.class, stringMapBuilder.build());
102104

105+
mapBuilder.put(java.sql.Date.class, ImmutableMap.of(java.sql.Date.class, this::conveSqlDateToSqlDate));
106+
mapBuilder.put(Time.class, ImmutableMap.of(Time.class, this::conveSqlTimeToSqlTime));
107+
mapBuilder.put(Timestamp.class, ImmutableMap.of(Timestamp.class, this::conveSqlTimestampToSqlTimestamp));
108+
103109
classConverters = mapBuilder.build();
104110
}
105111

@@ -194,6 +200,39 @@ public BigDecimal convertNumberToBigDecimal(Object value) {
194200
return BigDecimal.valueOf(((Number) value).doubleValue());
195201
}
196202

203+
// Date & Time converters
204+
205+
public java.sql.Date convertZonedDateTimeToSqlDate(Object value) {
206+
// Date is stored without time zone information and should be treated as UTC
207+
ZonedDateTime zonedDateTime = (ZonedDateTime) value;
208+
Date date = Date.valueOf(zonedDateTime.toLocalDate());
209+
return date;
210+
}
211+
212+
public Time convertZonedDateTimeToSqlTime(Object value) {
213+
// Time is stored without time zone information and should be treated as UTC
214+
ZonedDateTime zonedDateTime = (ZonedDateTime) value;
215+
Time time = Time.valueOf(zonedDateTime.toLocalTime());
216+
return time;
217+
}
218+
219+
public Timestamp convertZonedDateTimeToSqlTimestamp(Object value) {
220+
ZonedDateTime zonedDateTime = (ZonedDateTime) value;
221+
return Timestamp.valueOf(zonedDateTime.toLocalDateTime());
222+
}
223+
224+
public java.sql.Date conveSqlDateToSqlDate(Object value) {
225+
return (java.sql.Date) value;
226+
}
227+
228+
public Time conveSqlTimeToSqlTime(Object value) {
229+
return (Time) value;
230+
}
231+
232+
public Timestamp conveSqlTimestampToSqlTimestamp(Object value) {
233+
return (Timestamp) value;
234+
}
235+
197236
/**
198237
* Returns the converter map for the given source type.
199238
* Map contains target type and converter function. For example, if source type is boolean then map will contain all

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.sql.JDBCType;
2121
import java.sql.SQLException;
2222
import java.sql.SQLType;
23+
import java.sql.Time;
2324
import java.sql.Types;
2425
import java.time.*;
2526
import java.time.chrono.ChronoZonedDateTime;
@@ -79,6 +80,8 @@ private static Map<ClickHouseDataType, SQLType> generateTypeMap() {
7980
map.put(ClickHouseDataType.DateTime, JDBCType.TIMESTAMP);
8081
map.put(ClickHouseDataType.DateTime32, JDBCType.TIMESTAMP);
8182
map.put(ClickHouseDataType.DateTime64, JDBCType.TIMESTAMP);
83+
map.put(ClickHouseDataType.Time, JDBCType.TIME);
84+
map.put(ClickHouseDataType.Time64, JDBCType.TIME);
8285
map.put(ClickHouseDataType.Array, JDBCType.ARRAY);
8386
map.put(ClickHouseDataType.Nested, JDBCType.ARRAY);
8487
map.put(ClickHouseDataType.Map, JDBCType.JAVA_OBJECT);

jdbc-v2/src/main/java/com/clickhouse/jdbc/types/ArrayResultSet.java

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.sql.Statement;
3131
import java.sql.Time;
3232
import java.sql.Timestamp;
33+
import java.time.ZonedDateTime;
3334
import java.util.Arrays;
3435
import java.util.Calendar;
3536
import java.util.List;
@@ -49,8 +50,8 @@ public class ArrayResultSet implements ResultSet {
4950
private int fetchDirection = ResultSet.FETCH_FORWARD;
5051
private int fetchSize = 0;
5152
private boolean wasNull = false;
52-
private Map<Class<?>, Function<Object, Object>> converterMap;
53-
53+
private final Map<Class<?>, Function<Object, Object>> converterMap;
54+
private final Map<Class<?>, Function<Object, Object>> indexConverterMap;
5455
private final ClickHouseDataType componentDataType;
5556
private final Class<?> defaultClass;
5657
private final ClickHouseColumn column;
@@ -68,8 +69,9 @@ public ArrayResultSet(Object array, ClickHouseColumn column) {
6869
, "", "", "", JdbcUtils.DATA_TYPE_CLASS_MAP);
6970
this.componentDataType = valueColumn.getDataType();
7071
this.defaultClass = JdbcUtils.DATA_TYPE_CLASS_MAP.get(componentDataType);
72+
ValueConverters converters = new ValueConverters();
73+
indexConverterMap = converters.getConvertersForType(Integer.class);
7174
if (this.length > 1) {
72-
ValueConverters converters = new ValueConverters();
7375
Class<?> itemClass = array.getClass().getComponentType();
7476
if (itemClass == null) {
7577
itemClass = java.lang.reflect.Array.get(array, 0).getClass();
@@ -105,17 +107,23 @@ private void checkRowPosition() throws SQLException {
105107
private Object getValueAsObject(int columnIndex, Class<?> type, Object defaultValue) throws SQLException {
106108
checkColumnIndex(columnIndex);
107109
checkRowPosition();
110+
111+
Object value;
112+
Map<Class<?>, Function<Object, Object>> valueConverterMap;
108113
if (columnIndex == 1) {
109-
return pos;
114+
value = pos + 1;
115+
valueConverterMap = indexConverterMap;
116+
} else {
117+
value = java.lang.reflect.Array.get(array, pos);
118+
valueConverterMap = converterMap;
110119
}
111120

112-
Object value = java.lang.reflect.Array.get(array, pos);
113-
if (value != null && type == Array.class) {
121+
if (columnIndex != 1 && value != null && type == Array.class) {
114122
ClickHouseColumn nestedColumn = column.getArrayNestedLevel() == 1 ? column.getArrayBaseColumn() : column.getNestedColumns().get(0);
115123
return new com.clickhouse.jdbc.types.Array(nestedColumn, JdbcUtils.arrayToObjectArray(value));
116124
} else if (value != null && type != Object.class) {
117125
// if there is something to convert. type == Object.class means no conversion
118-
Function<Object, Object> converter = converterMap.get(type);
126+
Function<Object, Object> converter = valueConverterMap.get(type);
119127
if (converter != null) {
120128
value = converter.apply(value);
121129
} else {
@@ -238,16 +246,12 @@ public Date getDate(int columnIndex) throws SQLException {
238246

239247
@Override
240248
public Time getTime(int columnIndex) throws SQLException {
241-
checkColumnIndex(columnIndex);
242-
checkRowPosition();
243249
throwUnsupportedIndexOperation(columnIndex, "getTime");
244250
return (Time) getValueAsObject(columnIndex, Time.class, null);
245251
}
246252

247253
@Override
248254
public Timestamp getTimestamp(int columnIndex) throws SQLException {
249-
checkColumnIndex(columnIndex);
250-
checkRowPosition();
251255
throwUnsupportedIndexOperation(columnIndex, "getTimestamp");
252256
return (Timestamp) getValueAsObject(columnIndex, Timestamp.class, null);
253257
}
@@ -389,7 +393,8 @@ public ResultSetMetaData getMetaData() throws SQLException {
389393

390394
@Override
391395
public Object getObject(int columnIndex) throws SQLException {
392-
return getObject(columnIndex, defaultClass);
396+
Class<?> targetType = columnIndex == 1 ? Integer.class : defaultClass;
397+
return getObject(columnIndex, targetType);
393398
}
394399

395400
@Override
@@ -832,8 +837,6 @@ public Clob getClob(int columnIndex) throws SQLException {
832837

833838
@Override
834839
public Array getArray(int columnIndex) throws SQLException {
835-
checkColumnIndex(columnIndex);
836-
checkRowPosition();
837840
throwUnsupportedIndexOperation(columnIndex, "getArray");
838841
return (Array) getValueAsObject(columnIndex, Array.class, null);
839842
}
@@ -891,8 +894,6 @@ public Time getTime(String columnLabel, Calendar cal) throws SQLException {
891894

892895
@Override
893896
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
894-
checkColumnIndex(columnIndex);
895-
checkRowPosition();
896897
throwUnsupportedIndexOperation(columnIndex, "getTimestamp");
897898
return (Timestamp) getValueAsObject(columnIndex, Timestamp.class, null);
898899
}
@@ -1216,16 +1217,6 @@ public void updateNClob(String columnLabel, Reader reader) throws SQLException {
12161217
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
12171218
checkColumnIndex(columnIndex);
12181219
checkRowPosition();
1219-
if (columnIndex == 1) {
1220-
if (Number.class.isAssignableFrom(type)) {
1221-
return (T) pos;
1222-
} else if (String.class.isAssignableFrom(type)) {
1223-
return (T) String.valueOf(pos);
1224-
} else {
1225-
throw new SQLException("INDEX column cannot be converted to non-number value");
1226-
}
1227-
}
1228-
12291220
return (T) getValueAsObject(columnIndex, type, null);
12301221
}
12311222

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

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.clickhouse.jdbc;
22

3+
import com.clickhouse.client.api.ClientConfigProperties;
4+
import com.clickhouse.data.ClickHouseVersion;
35
import org.testng.Assert;
46
import org.testng.annotations.Test;
57

@@ -364,7 +366,6 @@ public void testGetMetadata() throws SQLException {
364366

365367
@Test(groups = {"integration"})
366368
public void testGetResultSetFromArray() throws Exception {
367-
368369
try (Connection conn = getJdbcConnection(); Statement stmt = conn.createStatement()) {
369370
try (ResultSet rs = stmt.executeQuery("select [1, 2, 3, 4]::Array(UInt16) as v")) {
370371
assertTrue(rs.next());
@@ -386,4 +387,91 @@ public void testGetResultSetFromArray() throws Exception {
386387
}
387388
}
388389
}
390+
391+
@Test(groups = {"integration"})
392+
public void testGetResultSetFromArrayDate() throws Exception {
393+
try (Connection conn = getJdbcConnection(); Statement stmt = conn.createStatement()) {
394+
// date array
395+
try (ResultSet rs = stmt.executeQuery("select [toDate('2020-01-01'), toDate('2020-01-02')] as v")) {
396+
397+
assertTrue(rs.next());
398+
Array array = rs.getArray("v");
399+
Assert.assertNotNull(array);
400+
Assert.assertEquals(array.getBaseType(), Types.DATE);
401+
Assert.assertEquals(array.getBaseTypeName(), "Date");
402+
403+
Object[] resultArray = (Object[]) array.getArray();
404+
Assert.assertEquals(resultArray.length, 2);
405+
Assert.assertEquals(resultArray[0], Date.valueOf("2020-01-01"));
406+
Assert.assertEquals(resultArray[1], Date.valueOf("2020-01-02"));
407+
408+
ResultSet rs2 = array.getResultSet();
409+
final String valueColumn = rs2.getMetaData().getColumnName(2);
410+
for (int i = 0; i < resultArray.length; i++) {
411+
rs2.next();
412+
Assert.assertEquals(rs2.getDate(valueColumn), resultArray[i]);
413+
}
414+
}
415+
}
416+
}
417+
418+
@Test(groups = {"integration"}, enabled = false)
419+
public void testGetResultSetFromArrayTime() throws Exception {
420+
if (ClickHouseVersion.of(getServerVersion()).check("(,25.5]")) {
421+
return; // Time64 introduced in 25.6
422+
}
423+
424+
Properties properties = new Properties();
425+
properties.put(ClientConfigProperties.serverSetting("allow_experimental_time_time64_type"), "1");
426+
try (Connection conn = getJdbcConnection(properties); Statement stmt = conn.createStatement()) {
427+
// time array
428+
try (ResultSet rs = stmt.executeQuery("select ['14:30:25'::Time, '17:30:25'::Time] as v")) {
429+
430+
assertTrue(rs.next());
431+
Array array = rs.getArray("v");
432+
Assert.assertNotNull(array);
433+
Assert.assertEquals(array.getBaseType(), Types.TIME);
434+
Assert.assertEquals(array.getBaseTypeName(), "Time");
435+
436+
Object[] resultArray = (Object[]) array.getArray();
437+
Assert.assertEquals(resultArray.length, 2);
438+
Assert.assertEquals(resultArray[0], Time.valueOf("14:30:25"));
439+
Assert.assertEquals(resultArray[1], Time.valueOf("17:30:25"));
440+
441+
ResultSet rs2 = array.getResultSet();
442+
final String valueColumn = rs2.getMetaData().getColumnName(2);
443+
for (int i = 0; i < resultArray.length; i++) {
444+
rs2.next();
445+
Assert.assertEquals(rs2.getTime(valueColumn), resultArray[i]);
446+
}
447+
}
448+
}
449+
}
450+
451+
@Test(groups = {"integration"})
452+
public void testGetResultSetFromArrayTimestamp() throws Exception {
453+
try (Connection conn = getJdbcConnection(); Statement stmt = conn.createStatement()) {
454+
// timestamp array
455+
try (ResultSet rs = stmt.executeQuery("select [toDateTime('2020-01-01 00:00:00'), toDateTime('2020-01-01 00:00:01')] as v")) {
456+
457+
assertTrue(rs.next());
458+
Array array = rs.getArray("v");
459+
Assert.assertNotNull(array);
460+
Assert.assertEquals(array.getBaseType(), Types.TIMESTAMP);
461+
Assert.assertEquals(array.getBaseTypeName(), "DateTime");
462+
463+
Object[] resultArray = (Object[]) array.getArray();
464+
Assert.assertEquals(resultArray.length, 2);
465+
Assert.assertEquals(resultArray[0], Timestamp.valueOf("2020-01-01 00:00:00"));
466+
Assert.assertEquals(resultArray[1], Timestamp.valueOf("2020-01-01 00:00:01"));
467+
468+
ResultSet rs2 = array.getResultSet();
469+
final String valueColumn = rs2.getMetaData().getColumnName(2);
470+
for (int i = 0; i < resultArray.length; i++) {
471+
rs2.next();
472+
Assert.assertEquals(rs2.getTimestamp(valueColumn), resultArray[i]);
473+
}
474+
}
475+
}
476+
}
389477
}

jdbc-v2/src/test/java/com/clickhouse/jdbc/types/ArrayResultSetTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,4 +412,21 @@ public void testReadOnlyException() throws Throwable {
412412
Assert.assertThrows(SQLException.class, op);
413413
}
414414
}
415+
416+
@Test
417+
void testIndexColumn() throws Exception {
418+
Integer[] array = {1, null, 3, 4, 5};
419+
ArrayResultSet rs = new ArrayResultSet(array, ClickHouseColumn.parse("v Array(Int32)").get(0));
420+
421+
final String indexColumn = rs.getMetaData().getColumnName(1);
422+
Assert.assertEquals(indexColumn, "INDEX");
423+
rs.next();
424+
assertEquals(rs.getObject(indexColumn), 1);
425+
assertEquals(rs.getObject(indexColumn, String.class), "1");
426+
assertEquals(rs.getObject(indexColumn, Long.class), 1L);
427+
assertEquals(rs.getObject(indexColumn, Integer.class), 1);
428+
assertEquals(rs.getObject(indexColumn, Short.class), (short) 1);
429+
assertEquals(rs.getObject(indexColumn, Byte.class), (byte) 1);
430+
431+
}
415432
}

0 commit comments

Comments
 (0)