Skip to content

Commit f3e22cf

Browse files
refactor: unify and improve array component type resolution for primitive and nullable types in BinaryStreamReader
1 parent 8d13865 commit f3e22cf

2 files changed

Lines changed: 82 additions & 22 deletions

File tree

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

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -609,8 +609,8 @@ public ArrayValue readArray(ClickHouseColumn column) throws IOException {
609609
ArrayValue array;
610610
ClickHouseColumn itemTypeColumn = column.getNestedColumns().get(0);
611611
if (len == 0) {
612-
Class<?> itemClass = itemTypeColumn.getDataType().getPrimitiveClass();
613-
array = new ArrayValue(itemClass == null ? Object.class : itemClass, 0);
612+
Class<?> itemClass = resolveArrayItemClass(itemTypeColumn);
613+
array = new ArrayValue(itemClass, 0);
614614
} else if (column.getArrayNestedLevel() == 1) {
615615
array = readArrayItem(itemTypeColumn, len);
616616
} else {
@@ -626,7 +626,7 @@ public ArrayValue readArray(ClickHouseColumn column) throws IOException {
626626
public ArrayValue readArrayItem(ClickHouseColumn itemTypeColumn, int len) throws IOException {
627627
ArrayValue array;
628628
if (itemTypeColumn.isNullable()) {
629-
Class<?> itemClass = resolveNullableArrayItemClass(itemTypeColumn.getDataType());
629+
Class<?> itemClass = resolveArrayItemClass(itemTypeColumn);
630630
array = new ArrayValue(itemClass, len);
631631
for (int i = 0; i < len; i++) {
632632
array.set(i, readValue(itemTypeColumn));
@@ -673,30 +673,60 @@ public ArrayValue readArrayItem(ClickHouseColumn itemTypeColumn, int len) throws
673673
}
674674

675675
/**
676-
* Resolves the Java class that {@link #readValue} actually returns for a given data type
677-
* so that it can be used as the component type of a nullable array.
676+
* Resolves the Java class that {@link #readValue} actually returns for a given column
677+
* so that it can be used as the component type of an array.
678678
*
679679
* <p>For unsigned integer types, {@code readValue} widens the value (e.g. UInt8 → Short,
680-
* UInt32 → Long), so we use {@link ClickHouseDataType#getWiderObjectClass()} which mirrors
681-
* that widening. For Enum types, {@code readValue} returns {@link EnumValue} rather than the
682-
* declared {@code String.class}. All other types use {@link ClickHouseDataType#getObjectClass()}.
680+
* UInt32 → Long), so we use {@link ClickHouseDataType#getWiderObjectClass()} or
681+
* {@link ClickHouseDataType#getWiderPrimitiveClass()} which mirrors that widening.
682+
* For Enum types, {@code readValue} returns {@link EnumValue} rather than the
683+
* declared {@code String.class}. All other types use {@link ClickHouseDataType#getObjectClass()}
684+
* or {@link ClickHouseDataType#getPrimitiveClass()}.
683685
*
684-
* @param dataType the element data type of the array
686+
* @param itemTypeColumn the element column of the array
685687
* @return the Java class to use as the array component type; never {@code null}
686688
*/
687-
private static Class<?> resolveNullableArrayItemClass(ClickHouseDataType dataType) {
688-
switch (dataType) {
689-
case UInt8:
690-
case UInt16:
691-
case UInt32:
692-
case UInt64:
693-
return dataType.getWiderObjectClass();
694-
case Enum8:
695-
case Enum16:
696-
return EnumValue.class;
697-
default:
698-
Class<?> cls = dataType.getObjectClass();
699-
return cls == null ? Object.class : cls;
689+
private static Class<?> resolveArrayItemClass(ClickHouseColumn itemTypeColumn) {
690+
ClickHouseDataType dataType = itemTypeColumn.getDataType();
691+
if (itemTypeColumn.isNullable()) {
692+
switch (dataType) {
693+
case UInt8:
694+
case UInt16:
695+
case UInt32:
696+
case UInt64:
697+
return dataType.getWiderObjectClass();
698+
case Enum8:
699+
case Enum16:
700+
return EnumValue.class;
701+
default:
702+
Class<?> cls = dataType.getObjectClass();
703+
return cls == null ? Object.class : cls;
704+
}
705+
} else {
706+
switch (dataType) {
707+
case UInt8:
708+
case UInt16:
709+
case UInt32:
710+
case UInt64:
711+
return dataType.getWiderPrimitiveClass();
712+
case Enum8:
713+
case Enum16:
714+
return EnumValue.class;
715+
case Variant:
716+
case Dynamic:
717+
case Geometry:
718+
return Object.class;
719+
case Array:
720+
return ArrayValue.class;
721+
case Tuple:
722+
case Nested:
723+
return Object[].class;
724+
case Map:
725+
return Map.class;
726+
default:
727+
Class<?> cls = dataType.getPrimitiveClass();
728+
return cls == null ? Object.class : cls;
729+
}
700730
}
701731
}
702732

client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/BinaryStreamReaderTests.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,4 +275,34 @@ public void testNullableEnumArrayUsesEnumValueType() throws Exception {
275275
Assert.assertEquals(array.getArray().getClass().getComponentType(),
276276
BinaryStreamReader.EnumValue.class);
277277
}
278+
279+
@Test
280+
public void testEmptyArrayTypes() throws Exception {
281+
assertEmptyArrayComponentType("Array(UInt8)", short.class);
282+
assertEmptyArrayComponentType("Array(Nullable(UInt8))", Short.class);
283+
assertEmptyArrayComponentType("Array(String)", String.class);
284+
assertEmptyArrayComponentType("Array(Nullable(String))", String.class);
285+
assertEmptyArrayComponentType("Array(Enum8('a'=1))", BinaryStreamReader.EnumValue.class);
286+
assertEmptyArrayComponentType("Array(Nullable(Enum8('a'=1)))", BinaryStreamReader.EnumValue.class);
287+
assertEmptyArrayComponentType("Array(Variant(Int32, String))", Object.class);
288+
assertEmptyArrayComponentType("Array(Array(String))", BinaryStreamReader.ArrayValue.class);
289+
}
290+
291+
private void assertEmptyArrayComponentType(String columnType, Class<?> expectedComponentType) throws Exception {
292+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
293+
BinaryStreamUtils.writeVarInt(baos, 0);
294+
295+
BinaryStreamReader reader = new BinaryStreamReader(
296+
new ByteArrayInputStream(baos.toByteArray()),
297+
TimeZone.getTimeZone("UTC"),
298+
null,
299+
new BinaryStreamReader.CachingByteBufferAllocator(),
300+
false,
301+
null);
302+
303+
BinaryStreamReader.ArrayValue array = (BinaryStreamReader.ArrayValue) reader.readValue(
304+
ClickHouseColumn.of("v", columnType));
305+
306+
Assert.assertEquals(array.getArray().getClass().getComponentType(), expectedComponentType, "Failed for " + columnType);
307+
}
278308
}

0 commit comments

Comments
 (0)