Skip to content

Commit cfe6315

Browse files
committed
fixed issue with nested arrays
1 parent 235880b commit cfe6315

File tree

2 files changed

+64
-8
lines changed

2 files changed

+64
-8
lines changed

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

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.clickhouse.data.ClickHouseDataType;
77
import com.clickhouse.data.Tuple;
88
import com.clickhouse.data.format.BinaryStreamUtils;
9+
import com.clickhouse.jdbc.PreparedStatementImpl;
910
import com.clickhouse.jdbc.types.Array;
1011
import com.google.common.collect.ImmutableMap;
1112
import org.slf4j.Logger;
@@ -31,7 +32,9 @@
3132
import java.util.List;
3233
import java.util.Map;
3334
import java.util.Set;
35+
import java.util.Stack;
3436
import java.util.TreeMap;
37+
import java.util.function.Function;
3538
import java.util.stream.Collectors;
3639

3740
public class JdbcUtils {
@@ -85,6 +88,8 @@ private static Map<ClickHouseDataType, SQLType> generateTypeMap() {
8588
map.put(ClickHouseDataType.LineString, JDBCType.ARRAY);
8689
map.put(ClickHouseDataType.MultiPolygon, JDBCType.ARRAY);
8790
map.put(ClickHouseDataType.MultiLineString, JDBCType.ARRAY);
91+
map.put(ClickHouseDataType.Tuple, JDBCType.OTHER);
92+
map.put(ClickHouseDataType.Nothing, JDBCType.OTHER);
8893
return ImmutableMap.copyOf(map);
8994
}
9095

@@ -169,6 +174,8 @@ private static Map<ClickHouseDataType, Class<?>> getDataTypeClassMap() {
169174
default:
170175
map.put(e.getKey(), Object.class);
171176
}
177+
} else if (e.getValue().equals(JDBCType.STRUCT)) {
178+
map.put(e.getKey(), Object.class);
172179
} else {
173180
map.put(e.getKey(), SQL_TYPE_TO_CLASS_MAP.get(e.getValue()));
174181
}
@@ -255,12 +262,12 @@ public static Object convert(Object value, Class<?> type, ClickHouseColumn colum
255262
if (value instanceof List<?>) {
256263
List<?> listValue = (List<?>) value;
257264
if (type != java.sql.Array.class) {
258-
return convertList(listValue, type);
265+
return convertList(listValue, type, column.getArrayNestedLevel());
259266
}
260267

261268
if (column != null && column.getArrayBaseColumn() != null) {
262269
ClickHouseDataType baseType = column.getArrayBaseColumn().getDataType();
263-
Object[] convertedValues = convertList(listValue, convertToJavaClass(baseType));
270+
Object[] convertedValues = convertList(listValue, convertToJavaClass(baseType), column.getArrayNestedLevel());
264271
return new Array(column, convertedValues);
265272
}
266273

@@ -348,17 +355,41 @@ public static Object convertObject(Object value, Class<?> type) throws SQLExcept
348355
throw new SQLException("Unsupported conversion from " + value.getClass().getName() + " to " + type.getName(), ExceptionUtils.SQL_STATE_DATA_EXCEPTION);
349356
}
350357

351-
public static <T> T[] convertList(List<?> values, Class<T> type) throws SQLException {
358+
public static <T> T[] convertList(List<?> values, Class<T> type, int dimensions) throws SQLException {
352359
if (values == null) {
353360
return null;
354361
}
355362
if (values.isEmpty()) {
356363
return (T[]) java.lang.reflect.Array.newInstance(type, 0);
357364
}
358-
T[] convertedValues = (T[]) java.lang.reflect.Array.newInstance(type, values.size());
359-
for (int i = 0; i < values.size(); i++) {
360-
convertedValues[i] = (T) convert(values.get(i), type);
365+
366+
367+
int[] arrayDimensions = new int[dimensions];
368+
arrayDimensions[0] = values.size();
369+
T[] convertedValues = (T[]) java.lang.reflect.Array.newInstance(type, arrayDimensions);
370+
Stack<ArrayProcessingCursor> stack = new Stack<>();
371+
stack.push(new ArrayProcessingCursor(convertedValues, values, 0, values.size()));
372+
373+
while (!stack.isEmpty()) {
374+
ArrayProcessingCursor cursor = stack.pop();
375+
376+
for (int i = 0; i < cursor.size; i++) {
377+
Object value = cursor.getValue(i);
378+
if (value == null) {
379+
continue; // no need to set null value
380+
} else if (value instanceof List<?>) {
381+
List<?> srcList = (List<?>) value;
382+
arrayDimensions = new int[Math.max(dimensions - stack.size() - 1, 1)];
383+
arrayDimensions[0] = srcList.size();
384+
T[] targetArray = (T[]) java.lang.reflect.Array.newInstance(type, arrayDimensions);
385+
stack.push(new ArrayProcessingCursor(targetArray, value, 0, srcList.size()));
386+
java.lang.reflect.Array.set(cursor.targetArray, i, targetArray);
387+
} else {
388+
java.lang.reflect.Array.set(cursor.targetArray, i, convert(value, type));
389+
}
390+
}
361391
}
392+
362393
return convertedValues;
363394
}
364395

@@ -373,6 +404,31 @@ public static <T> T[] convertArray(Object[] values, Class<T> type) throws SQLExc
373404
return convertedValues;
374405
}
375406

407+
private static final class ArrayProcessingCursor {
408+
private final Object targetArray;
409+
private final Object srcArray;
410+
private final int pos;
411+
private final int size;
412+
private final Function<Integer, Object> valueGetter;
413+
414+
public ArrayProcessingCursor(Object targetArray, Object srcArray, int pos, int size) {
415+
this.targetArray = targetArray;
416+
this.srcArray = srcArray;
417+
this.pos = pos;
418+
this.size = size;
419+
if (srcArray instanceof List<?>) {
420+
List<?> list = (List<?>) srcArray;
421+
this.valueGetter = list::get;
422+
} else {
423+
this.valueGetter = (i) -> java.lang.reflect.Array.get(srcArray, i);
424+
}
425+
}
426+
427+
public Object getValue(int i) {
428+
return valueGetter.apply(i);
429+
}
430+
}
431+
376432
private static Object[] arrayToObjectArray(Object array) {
377433
if (array == null) {
378434
return null;

jdbc-v2/src/test/java/com/clickhouse/jdbc/internal/JdbcUtilsTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,13 @@ public void testConvertArray() throws Exception {
6767
public void testConvertList() throws Exception {
6868
ClickHouseColumn column = ClickHouseColumn.of("arr", "Array(Int32)");
6969
List<Integer> src = Arrays.asList(1, 2, 3);
70-
Integer[] dst = JdbcUtils.convertList(src, Integer.class);
70+
Integer[] dst = JdbcUtils.convertList(src, Integer.class, 1);
7171
assertEquals(dst.length, src.size());
7272
assertEquals(dst[0], src.get(0));
7373
assertEquals(dst[1], src.get(1));
7474
assertEquals(dst[2], src.get(2));
7575

76-
assertNull(JdbcUtils.convertList(null, Integer.class));
76+
assertNull(JdbcUtils.convertList(null, Integer.class, 1));
7777
}
7878

7979

0 commit comments

Comments
 (0)