Skip to content

Commit bbc1af2

Browse files
authored
Merge pull request #2668 from ClickHouse/jdbc_impl_getResultSet_in_Array
Jdbc impl get result set in array
2 parents 53609c5 + c6c2f85 commit bbc1af2

File tree

8 files changed

+2198
-11
lines changed

8 files changed

+2198
-11
lines changed
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
package com.clickhouse.client.api.data_formats.internal;
2+
3+
import com.google.common.collect.ImmutableMap;
4+
5+
import java.math.BigDecimal;
6+
import java.math.BigInteger;
7+
import java.net.MalformedURLException;
8+
import java.net.URL;
9+
import java.sql.Date;
10+
import java.sql.Time;
11+
import java.sql.Timestamp;
12+
import java.util.Collections;
13+
import java.util.Map;
14+
import java.util.function.Function;
15+
16+
public final class ValueConverters {
17+
18+
19+
// <source type, <target type, converter>>
20+
private final Map<Class<?>, Map<Class<?>, Function<Object, Object>>> classConverters;
21+
22+
// <target type, converter>
23+
private final ImmutableMap<Class<?>, Function<Object, Object>> numberConverters;
24+
25+
public ValueConverters() {
26+
27+
28+
ImmutableMap.Builder<Class<?>, Function<Object, Object>> numberConvertersBuilder = ImmutableMap.builder();
29+
numberConvertersBuilder.put(String.class, this::convertNumberToString);
30+
numberConvertersBuilder.put(Boolean.class, this::convertNumberToBoolean);
31+
numberConvertersBuilder.put(byte.class, this::convertNumberToByte);
32+
numberConvertersBuilder.put(short.class, this::convertNumberToShort);
33+
numberConvertersBuilder.put(int.class, this::convertNumberToInt);
34+
numberConvertersBuilder.put(long.class, this::convertNumberToLong);
35+
numberConvertersBuilder.put(float.class, this::convertNumberToFloat);
36+
numberConvertersBuilder.put(double.class, this::convertNumberToDouble);
37+
numberConvertersBuilder.put(Byte.class, this::convertNumberToByte);
38+
numberConvertersBuilder.put(Short.class, this::convertNumberToShort);
39+
numberConvertersBuilder.put(Integer.class, this::convertNumberToInt);
40+
numberConvertersBuilder.put(Long.class, this::convertNumberToLong);
41+
numberConvertersBuilder.put(Float.class, this::convertNumberToFloat);
42+
numberConvertersBuilder.put(Double.class, this::convertNumberToDouble);
43+
numberConvertersBuilder.put(BigInteger.class, this::convertNumberToBigInteger);
44+
numberConvertersBuilder.put(BigDecimal.class, this::convertNumberToBigDecimal);
45+
46+
numberConverters = numberConvertersBuilder.build();
47+
48+
49+
ImmutableMap.Builder<Class<?>, Map<Class<?>, Function<Object, Object>>> mapBuilder = ImmutableMap.builder();
50+
51+
mapBuilder.put(byte.class, numberConverters);
52+
mapBuilder.put(short.class, numberConverters);
53+
mapBuilder.put(int.class, numberConverters);
54+
mapBuilder.put(long.class, numberConverters);
55+
mapBuilder.put(float.class, numberConverters);
56+
mapBuilder.put(double.class, numberConverters);
57+
mapBuilder.put(Byte.class, numberConverters);
58+
mapBuilder.put(Short.class, numberConverters);
59+
mapBuilder.put(Integer.class, numberConverters);
60+
mapBuilder.put(Long.class, numberConverters);
61+
mapBuilder.put(Float.class, numberConverters);
62+
mapBuilder.put(Double.class, numberConverters);
63+
mapBuilder.put(BigInteger.class, numberConverters);
64+
mapBuilder.put(BigDecimal.class, numberConverters);
65+
66+
ImmutableMap.Builder<Class<?>, Function<Object, Object>> booleanMapBuilder = ImmutableMap.builder();
67+
booleanMapBuilder.put(byte.class, this::convertBooleanToNumber);
68+
booleanMapBuilder.put(short.class, this::convertBooleanToNumber);
69+
booleanMapBuilder.put(int.class, this::convertBooleanToNumber);
70+
booleanMapBuilder.put(long.class, this::convertBooleanToNumber);
71+
booleanMapBuilder.put(float.class, this::convertBooleanToNumber);
72+
booleanMapBuilder.put(double.class, this::convertBooleanToNumber);
73+
booleanMapBuilder.put(Byte.class, this::convertBooleanToNumber);
74+
booleanMapBuilder.put(Short.class, this::convertBooleanToNumber);
75+
booleanMapBuilder.put(Integer.class, this::convertBooleanToNumber);
76+
booleanMapBuilder.put(Long.class, this::convertBooleanToNumber);
77+
booleanMapBuilder.put(Float.class, this::convertBooleanToNumber);
78+
booleanMapBuilder.put(Double.class, this::convertBooleanToNumber);
79+
booleanMapBuilder.put(BigInteger.class, this::convertBooleanToNumber);
80+
booleanMapBuilder.put(BigDecimal.class, this::convertBooleanToNumber);
81+
booleanMapBuilder.put(String.class, this::convertBooleanToString);
82+
booleanMapBuilder.put(Boolean.class, this::convertBooleanToBoolean);
83+
booleanMapBuilder.put(boolean.class, this::convertBooleanToBoolean);
84+
85+
mapBuilder.put(Boolean.class, booleanMapBuilder.build());
86+
mapBuilder.put(boolean.class, booleanMapBuilder.build());
87+
88+
ImmutableMap.Builder<Class<?>, Function<Object, Object>> stringMapBuilder = ImmutableMap.builder();
89+
stringMapBuilder.put(byte.class, this::convertStringToByte);
90+
stringMapBuilder.put(short.class, this::convertStringToShort);
91+
stringMapBuilder.put(int.class, this::convertStringToInt);
92+
stringMapBuilder.put(long.class, this::convertStringToLong);
93+
stringMapBuilder.put(float.class, this::convertStringToFloat);
94+
stringMapBuilder.put(double.class, this::convertStringToDouble);
95+
stringMapBuilder.put(Byte.class, this::convertStringToByte);
96+
stringMapBuilder.put(Short.class, this::convertStringToShort);
97+
stringMapBuilder.put(Integer.class, this::convertStringToInt);
98+
stringMapBuilder.put(Long.class, this::convertStringToLong);
99+
stringMapBuilder.put(Float.class, this::convertStringToFloat);
100+
stringMapBuilder.put(Double.class, this::convertStringToDouble);
101+
stringMapBuilder.put(Boolean.class, this::convertStringToBoolean);
102+
stringMapBuilder.put(String.class, this::convertStringToString);
103+
stringMapBuilder.put(byte[].class, this::convertStringToBytes);
104+
stringMapBuilder.put(URL.class, this::convertStringToURL);
105+
mapBuilder.put(String.class, stringMapBuilder.build());
106+
107+
mapBuilder.put(java.sql.Date.class, ImmutableMap.of(java.sql.Date.class, this::convertSqlDateToSqlDate,
108+
String.class, this::convertDateToString));
109+
mapBuilder.put(Time.class, ImmutableMap.of(Time.class, this::convertSqlTimeToSqlTime,
110+
String.class, this::convertTimeToString));
111+
mapBuilder.put(Timestamp.class, ImmutableMap.of(Timestamp.class, this::convertSqlTimestampToSqlTimestamp,
112+
String.class, this::convertTimestampToString));
113+
114+
classConverters = mapBuilder.build();
115+
}
116+
117+
// Boolean to any
118+
public Boolean convertBooleanToBoolean(Object value) {
119+
return (Boolean) value;
120+
}
121+
122+
public Number convertBooleanToNumber(Object value) {
123+
return ((Boolean) value) ? 1L : 0L;
124+
}
125+
126+
public String convertBooleanToString(Object value) {
127+
return String.valueOf(value);
128+
}
129+
130+
// String to any
131+
public String convertStringToString(Object value) {
132+
return (String) value;
133+
}
134+
135+
public byte[] convertStringToBytes(Object value) {
136+
return ((String) value).getBytes();
137+
}
138+
139+
public boolean convertStringToBoolean(Object value) {
140+
return Boolean.parseBoolean((String) value);
141+
}
142+
143+
public byte convertStringToByte(Object value) {
144+
return Byte.parseByte((String) value);
145+
}
146+
147+
public short convertStringToShort(Object value) {
148+
return Short.parseShort((String) value);
149+
}
150+
151+
public int convertStringToInt(Object value) {
152+
return Integer.parseInt((String) value);
153+
}
154+
155+
public long convertStringToLong(Object value) {
156+
return Long.parseLong((String) value);
157+
}
158+
159+
public float convertStringToFloat(Object value) {
160+
return Float.parseFloat((String) value);
161+
}
162+
163+
public double convertStringToDouble(Object value) {
164+
return Double.parseDouble((String) value);
165+
}
166+
167+
public URL convertStringToURL(Object value) {
168+
try {
169+
return new URL((String) value);
170+
} catch (MalformedURLException e) {
171+
throw new RuntimeException(e);
172+
}
173+
}
174+
175+
// Number to any
176+
public String convertNumberToString(Object value) {
177+
return String.valueOf(value);
178+
}
179+
180+
public boolean convertNumberToBoolean(Object value) {
181+
return ((Number) value).floatValue() != 0.0f;
182+
}
183+
184+
public byte convertNumberToByte(Object value) {
185+
return ((Number) value).byteValue();
186+
}
187+
188+
public short convertNumberToShort(Object value) {
189+
return ((Number) value).shortValue();
190+
}
191+
192+
public int convertNumberToInt(Object value) {
193+
return ((Number) value).intValue();
194+
}
195+
196+
public long convertNumberToLong(Object value) {
197+
return ((Number) value).longValue();
198+
}
199+
200+
public float convertNumberToFloat(Object value) {
201+
return ((Number) value).floatValue();
202+
}
203+
204+
public double convertNumberToDouble(Object value) {
205+
return ((Number) value).doubleValue();
206+
}
207+
208+
public BigInteger convertNumberToBigInteger(Object value) {
209+
return BigInteger.valueOf(((Number) value).longValue());
210+
}
211+
212+
public BigDecimal convertNumberToBigDecimal(Object value) {
213+
return BigDecimal.valueOf(((Number) value).doubleValue());
214+
}
215+
216+
// Date & Time converters
217+
public java.sql.Date convertSqlDateToSqlDate(Object value) {
218+
return (java.sql.Date) value;
219+
}
220+
221+
public Time convertSqlTimeToSqlTime(Object value) {
222+
return (Time) value;
223+
}
224+
225+
public Timestamp convertSqlTimestampToSqlTimestamp(Object value) {
226+
return (Timestamp) value;
227+
}
228+
229+
public String convertDateToString(Object value) {
230+
return value.toString();
231+
}
232+
233+
public String convertTimeToString(Object value) {
234+
return value.toString();
235+
}
236+
237+
public String convertTimestampToString(Object value) {
238+
return value.toString();
239+
}
240+
241+
/**
242+
* Returns the converter map for the given source type.
243+
* Map contains target type and converter function. For example, if source type is boolean then map will contain all
244+
* converters that support converting boolean to target type.
245+
* @param type - source type
246+
* @return - map of target type and converter function
247+
*/
248+
public Map<Class<?>, Function<Object, Object>> getConvertersForType(Class<?> type) {
249+
return classConverters.getOrDefault(type, Collections.emptyMap());
250+
}
251+
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ private static Map<ClickHouseDataType, SQLType> generateTypeMap() {
7777
map.put(ClickHouseDataType.DateTime, JDBCType.TIMESTAMP);
7878
map.put(ClickHouseDataType.DateTime32, JDBCType.TIMESTAMP);
7979
map.put(ClickHouseDataType.DateTime64, JDBCType.TIMESTAMP);
80+
map.put(ClickHouseDataType.Time, JDBCType.TIME);
81+
map.put(ClickHouseDataType.Time64, JDBCType.TIME);
8082
map.put(ClickHouseDataType.Array, JDBCType.ARRAY);
8183
map.put(ClickHouseDataType.Nested, JDBCType.ARRAY);
8284
map.put(ClickHouseDataType.Map, JDBCType.JAVA_OBJECT);
@@ -106,7 +108,7 @@ private static Map<SQLType, Class<?>> generateClassMap() {
106108
map.put(JDBCType.INTEGER, Integer.class);
107109
map.put(JDBCType.BIGINT, Long.class);
108110
map.put(JDBCType.REAL, Float.class);
109-
map.put(JDBCType.FLOAT, Double.class);
111+
map.put(JDBCType.FLOAT, Float.class);
110112
map.put(JDBCType.DOUBLE, Double.class);
111113
map.put(JDBCType.BINARY, byte[].class);
112114
map.put(JDBCType.VARBINARY, byte[].class);
@@ -457,7 +459,7 @@ public Object getValue(int i) {
457459
}
458460
}
459461

460-
private static Object[] arrayToObjectArray(Object array) {
462+
public static Object[] arrayToObjectArray(Object array) {
461463
if (array == null) {
462464
return null;
463465
}

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class Array implements java.sql.Array {
2222
private final String elementTypeName;
2323
private boolean valid;
2424
private final ClickHouseDataType baseDataType;
25+
private ArrayResultSet arrayResultSet;
2526

2627
public Array(ClickHouseColumn column, Object[] elements) throws SQLException {
2728
this.column = column;
@@ -88,8 +89,12 @@ public Object getArray(long index, int count, Map<String, Class<?>> map) throws
8889
}
8990

9091
@Override
91-
public ResultSet getResultSet() throws SQLException {
92-
throw new SQLFeatureNotSupportedException("getResultSet() is not supported", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED);
92+
public synchronized ResultSet getResultSet() throws SQLException {
93+
ensureValid();
94+
if (arrayResultSet == null) {
95+
arrayResultSet = new ArrayResultSet(array, column);
96+
}
97+
return arrayResultSet;
9398
}
9499

95100
@Override
@@ -99,7 +104,8 @@ public ResultSet getResultSet(Map<String, Class<?>> map) throws SQLException {
99104

100105
@Override
101106
public ResultSet getResultSet(long index, int count) throws SQLException {
102-
throw new SQLFeatureNotSupportedException("getResultSet(long, int) is not supported", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED);
107+
ensureValid();
108+
return new ArrayResultSet(getArray(index, count), column);
103109
}
104110

105111
@Override

0 commit comments

Comments
 (0)