Skip to content

Commit e3e6f8c

Browse files
authored
Merge pull request #2747 from ClickHouse/02/15/26/array_getters_in_reader
Added getting arrays of objects and other types of arrays
2 parents b87bc28 + 4999fdd commit e3e6f8c

11 files changed

Lines changed: 1649 additions & 70 deletions

File tree

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

Lines changed: 88 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -240,74 +240,75 @@ public interface ClickHouseBinaryFormatReader extends AutoCloseable {
240240
ClickHouseGeoMultiPolygonValue getGeoMultiPolygon(String colName);
241241

242242
/**
243-
* Reads column with name `colName` as a string.
244-
*
243+
* @see #getList(int)
245244
* @param colName - column name
246-
* @return
245+
* @return list of values, or {@code null} if the value is null
247246
*/
248247
<T> List<T> getList(String colName);
249248

250249
/**
251-
* Reads column with name `colName` as a string.
252-
*
250+
* @see #getByteArray(int)
253251
* @param colName - column name
254-
* @return
252+
* @return array of bytes, or {@code null} if the value is null
255253
*/
256254
byte[] getByteArray(String colName);
257255

258256
/**
259-
* Reads column with name `colName` as a string.
260-
*
257+
* @see #getIntArray(int)
261258
* @param colName - column name
262-
* @return
259+
* @return array of int values, or {@code null} if the value is null
263260
*/
264261
int[] getIntArray(String colName);
265262

266263
/**
267-
* Reads column with name `colName` as a string.
268-
*
264+
* @see #getLongArray(int)
269265
* @param colName - column name
270-
* @return
266+
* @return array of long values, or {@code null} if the value is null
271267
*/
272268
long[] getLongArray(String colName);
273269

274270
/**
275-
* Reads column with name `colName` as a string.
276-
*
271+
* @see #getFloatArray(int)
277272
* @param colName - column name
278-
* @return
273+
* @return array of float values, or {@code null} if the value is null
279274
*/
280275
float[] getFloatArray(String colName);
281276

282277
/**
283-
* Reads column with name `colName` as a string.
284-
*
278+
* @see #getDoubleArray(int)
285279
* @param colName - column name
286-
* @return
280+
* @return array of double values, or {@code null} if the value is null
287281
*/
288282
double[] getDoubleArray(String colName);
289283

290284
/**
291-
*
292-
* @param colName
293-
* @return
285+
* @see #getBooleanArray(int)
286+
* @param colName - column name
287+
* @return array of boolean values, or {@code null} if the value is null
294288
*/
295289
boolean[] getBooleanArray(String colName);
296290

297291
/**
298-
*
299-
* @param colName
300-
* @return
292+
* @see #getShortArray(int)
293+
* @param colName - column name
294+
* @return array of short values, or {@code null} if the value is null
301295
*/
302296
short[] getShortArray(String colName);
303297

304298
/**
305-
*
306-
* @param colName
307-
* @return
299+
* @see #getStringArray(int)
300+
* @param colName - column name
301+
* @return array of string values, or {@code null} if the value is null
308302
*/
309303
String[] getStringArray(String colName);
310304

305+
/**
306+
* @see #getObjectArray(int)
307+
* @param colName - column name
308+
* @return array of objects, or {@code null} if the value is null
309+
*/
310+
Object[] getObjectArray(String colName);
311+
311312
/**
312313
* Reads column with name `colName` as a string.
313314
*
@@ -483,59 +484,100 @@ public interface ClickHouseBinaryFormatReader extends AutoCloseable {
483484
ClickHouseGeoMultiPolygonValue getGeoMultiPolygon(int index);
484485

485486
/**
486-
* Reads column with name `colName` as a string.
487+
* Returns the value of the specified column as a {@link List}. Suitable for reading Array columns of any type.
488+
* <p>For nested arrays (e.g. {@code Array(Array(Int64))}), returns a {@code List<List<Long>>}.
489+
* For nullable arrays (e.g. {@code Array(Nullable(Int32))}), list elements may be {@code null}.</p>
487490
*
488-
* @param index - column name
489-
* @return
491+
* @param index - column index (1-based)
492+
* @return list of values, or {@code null} if the value is null
493+
* @throws com.clickhouse.client.api.ClientException if the column is not an array type
490494
*/
491495
<T> List<T> getList(int index);
492496

493497
/**
494-
* Reads column with name `colName` as a string.
498+
* Returns the value of the specified column as a {@code byte[]}. Suitable for 1D Array columns only.
495499
*
496-
* @param index - column name
497-
* @return
500+
* @param index - column index (1-based)
501+
* @return array of bytes, or {@code null} if the value is null
502+
* @throws com.clickhouse.client.api.ClientException if the value cannot be converted to a byte array
498503
*/
499504
byte[] getByteArray(int index);
500505

501506
/**
502-
* Reads column with name `colName` as a string.
507+
* Returns the value of the specified column as an {@code int[]}. Suitable for 1D Array columns only.
503508
*
504-
* @param index - column name
505-
* @return
509+
* @param index - column index (1-based)
510+
* @return array of int values, or {@code null} if the value is null
511+
* @throws com.clickhouse.client.api.ClientException if the value cannot be converted to an int array
506512
*/
507513
int[] getIntArray(int index);
508514

509515
/**
510-
* Reads column with name `colName` as a string.
516+
* Returns the value of the specified column as a {@code long[]}. Suitable for 1D Array columns only.
511517
*
512-
* @param index - column name
513-
* @return
518+
* @param index - column index (1-based)
519+
* @return array of long values, or {@code null} if the value is null
520+
* @throws com.clickhouse.client.api.ClientException if the value cannot be converted to a long array
514521
*/
515522
long[] getLongArray(int index);
516523

517524
/**
518-
* Reads column with name `colName` as a string.
525+
* Returns the value of the specified column as a {@code float[]}. Suitable for 1D Array columns only.
519526
*
520-
* @param index - column name
521-
* @return
527+
* @param index - column index (1-based)
528+
* @return array of float values, or {@code null} if the value is null
529+
* @throws com.clickhouse.client.api.ClientException if the value cannot be converted to a float array
522530
*/
523531
float[] getFloatArray(int index);
524532

525533
/**
526-
* Reads column with name `colName` as a string.
534+
* Returns the value of the specified column as a {@code double[]}. Suitable for 1D Array columns only.
527535
*
528-
* @param index - column name
529-
* @return
536+
* @param index - column index (1-based)
537+
* @return array of double values, or {@code null} if the value is null
538+
* @throws com.clickhouse.client.api.ClientException if the value cannot be converted to a double array
530539
*/
531540
double[] getDoubleArray(int index);
532541

542+
/**
543+
* Returns the value of the specified column as a {@code boolean[]}. Suitable for 1D Array columns only.
544+
*
545+
* @param index - column index (1-based)
546+
* @return array of boolean values, or {@code null} if the value is null
547+
* @throws com.clickhouse.client.api.ClientException if the value cannot be converted to a boolean array
548+
*/
533549
boolean[] getBooleanArray(int index);
534550

535-
short [] getShortArray(int index);
551+
/**
552+
* Returns the value of the specified column as a {@code short[]}. Suitable for 1D Array columns only.
553+
*
554+
* @param index - column index (1-based)
555+
* @return array of short values, or {@code null} if the value is null
556+
* @throws com.clickhouse.client.api.ClientException if the value cannot be converted to a short array
557+
*/
558+
short[] getShortArray(int index);
536559

560+
/**
561+
* Returns the value of the specified column as a {@code String[]}. Suitable for 1D Array columns only.
562+
* Cannot be used for none string element types.
563+
*
564+
* @param index - column index (1-based)
565+
* @return array of string values, or {@code null} if the value is null
566+
* @throws com.clickhouse.client.api.ClientException if the column is not an array type
567+
*/
537568
String[] getStringArray(int index);
538569

570+
/**
571+
* Returns the value of the specified column as an {@code Object[]}. Suitable for multidimensional Array columns.
572+
* Nested arrays are recursively converted to {@code Object[]}.
573+
* Note: result is not cached so avoid repetitive calls on same column.
574+
*
575+
* @param index - column index (1-based)
576+
* @return array of objects, or {@code null} if the value is null
577+
* @throws com.clickhouse.client.api.ClientException if the column is not an array type
578+
*/
579+
Object[] getObjectArray(int index);
580+
539581
Object[] getTuple(int index);
540582

541583
Object[] getTuple(String colName);

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

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,11 @@ public String[] getStringArray(String colName) {
562562
return getStringArray(schema.nameToColumnIndex(colName));
563563
}
564564

565+
@Override
566+
public Object[] getObjectArray(String colName) {
567+
return getObjectArray(schema.nameToColumnIndex(colName));
568+
}
569+
565570
@Override
566571
public boolean hasValue(int colIndex) {
567572
return currentRecord[colIndex - 1] != null;
@@ -816,16 +821,30 @@ public String[] getStringArray(int index) {
816821
}
817822
if (value instanceof BinaryStreamReader.ArrayValue) {
818823
BinaryStreamReader.ArrayValue array = (BinaryStreamReader.ArrayValue) value;
819-
int length = array.length;
820-
if (!array.itemType.equals(String.class))
821-
throw new ClientException("Not A String type.");
822-
String[] values = new String[length];
823-
for (int i = 0; i < length; i++) {
824-
values[i] = (String)((BinaryStreamReader.ArrayValue) value).get(i);
824+
if (array.itemType == String.class) {
825+
return (String[]) array.getArray();
826+
} else if (array.itemType == BinaryStreamReader.EnumValue.class) {
827+
BinaryStreamReader.EnumValue[] enumValues = (BinaryStreamReader.EnumValue[]) array.getArray();
828+
return Arrays.stream(enumValues).map(BinaryStreamReader.EnumValue::getName).toArray(String[]::new);
829+
} else {
830+
throw new ClientException("Not an array of strings");
825831
}
826-
return values;
827832
}
828-
throw new ClientException("Not ArrayValue type.");
833+
throw new ClientException("Column is not of array type");
834+
}
835+
836+
@Override
837+
public Object[] getObjectArray(int index) {
838+
Object value = readValue(index);
839+
if (value == null) {
840+
return null;
841+
}
842+
if (value instanceof BinaryStreamReader.ArrayValue) {
843+
return ((BinaryStreamReader.ArrayValue) value).toObjectArray();
844+
} else if (value instanceof List<?>) {
845+
return ((List<?>) value).toArray(new Object[0]);
846+
}
847+
throw new ClientException("Column is not of array type");
829848
}
830849

831850
@Override

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ public String[] getStringArray(String colName) {
175175
return reader.getStringArray(colName);
176176
}
177177

178+
@Override
179+
public Object[] getObjectArray(String colName) {
180+
return reader.getObjectArray(colName);
181+
}
182+
178183
@Override
179184
public String getString(int index) {
180185
return reader.getString(index);
@@ -335,6 +340,11 @@ public String[] getStringArray(int index) {
335340
return reader.getStringArray(index);
336341
}
337342

343+
@Override
344+
public Object[] getObjectArray(int index) {
345+
return reader.getObjectArray(index);
346+
}
347+
338348
@Override
339349
public Object[] getTuple(int index) {
340350
return reader.getTuple(index);

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

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -604,15 +604,14 @@ public static byte[] readNBytesLE(InputStream input, byte[] buffer, int offset,
604604
*/
605605
public ArrayValue readArray(ClickHouseColumn column) throws IOException {
606606
int len = readVarInt(input);
607-
if (len == 0) {
608-
return new ArrayValue(Object.class, 0);
609-
}
610607

611608
ArrayValue array;
612609
ClickHouseColumn itemTypeColumn = column.getNestedColumns().get(0);
613-
if (column.getArrayNestedLevel() == 1) {
610+
if (len == 0) {
611+
Class<?> itemClass = itemTypeColumn.getDataType().getPrimitiveClass();
612+
array = new ArrayValue(itemClass == null ? Object.class : itemClass, 0);
613+
} else if (column.getArrayNestedLevel() == 1) {
614614
array = readArrayItem(itemTypeColumn, len);
615-
616615
} else {
617616
array = new ArrayValue(ArrayValue.class, len);
618617
for (int i = 0; i < len; i++) {
@@ -645,6 +644,10 @@ public ArrayValue readArrayItem(ClickHouseColumn itemTypeColumn, int len) throws
645644
itemClass = long.class;
646645
} else if (firstValue instanceof Boolean) {
647646
itemClass = boolean.class;
647+
} else if (firstValue instanceof Float) {
648+
itemClass = float.class;
649+
} else if (firstValue instanceof Double) {
650+
itemClass = double.class;
648651
}
649652

650653
array = new ArrayValue(itemClass, len);
@@ -752,6 +755,23 @@ public Object[] getArrayOfObjects() {
752755
return (Object[]) array;
753756
}
754757
}
758+
759+
/**
760+
* Returns array of objects, recursively converting nested ArrayValue elements to Object[].
761+
* This is useful for nested arrays (e.g. Array(Array(Int64))) where elements are ArrayValue instances.
762+
*
763+
* @return Object[] with nested ArrayValue elements converted to Object[]
764+
*/
765+
public Object[] toObjectArray() {
766+
Object[] result = new Object[length];
767+
for (int i = 0; i < length; i++) {
768+
Object item = get(i);
769+
result[i] = (item instanceof ArrayValue) ? ((ArrayValue) item).toObjectArray() : item;
770+
}
771+
return result;
772+
}
773+
774+
755775
}
756776

757777
public static class EnumValue extends Number {
@@ -785,6 +805,10 @@ public double doubleValue() {
785805
return value;
786806
}
787807

808+
public String getName() {
809+
return name;
810+
}
811+
788812
@Override
789813
public String toString() {
790814
return name;

0 commit comments

Comments
 (0)