Skip to content

Commit ec9f249

Browse files
authored
Merge pull request #1876 from ClickHouse/v2_fix_aggregate_function_serde
[client-v2] Fix Bitmap SerDe
2 parents 65bc28c + a0abab9 commit ec9f249

File tree

14 files changed

+195
-27
lines changed

14 files changed

+195
-27
lines changed

clickhouse-data/src/main/java/com/clickhouse/data/value/ClickHouseBitmap.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ public static ClickHouseBitmap deserialize(DataInputStream in, ClickHouseDataTyp
354354
byte[] bytes = new byte[2 + byteLen * cardinality];
355355
bytes[0] = (byte) flag;
356356
bytes[1] = cardinality;
357-
in.read(bytes, 2, bytes.length - 2);
357+
in.readFully(bytes, 2, bytes.length - 2);
358358

359359
rb = ClickHouseBitmap.deserialize(bytes, innerType);
360360
} else {

client-v2/src/main/java/com/clickhouse/client/api/Client.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.clickhouse.client.api.data_formats.internal.BinaryStreamReader;
1616
import com.clickhouse.client.api.data_formats.internal.MapBackedRecord;
1717
import com.clickhouse.client.api.data_formats.internal.ProcessParser;
18+
import com.clickhouse.client.api.data_formats.internal.SerializerUtils;
1819
import com.clickhouse.client.api.enums.Protocol;
1920
import com.clickhouse.client.api.enums.ProxyType;
2021
import com.clickhouse.client.api.insert.DataSerializationException;
@@ -26,7 +27,6 @@
2627
import com.clickhouse.client.api.internal.ClientV1AdaptorHelper;
2728
import com.clickhouse.client.api.internal.HttpAPIClientHelper;
2829
import com.clickhouse.client.api.internal.MapUtils;
29-
import com.clickhouse.client.api.internal.SerializerUtils;
3030
import com.clickhouse.client.api.internal.SettingsConverter;
3131
import com.clickhouse.client.api.internal.TableSchemaParser;
3232
import com.clickhouse.client.api.internal.ValidationUtils;
@@ -47,7 +47,6 @@
4747
import com.clickhouse.data.ClickHouseColumn;
4848
import com.clickhouse.data.ClickHouseDataType;
4949
import com.clickhouse.data.ClickHouseFormat;
50-
import com.clickhouse.data.format.BinaryStreamUtils;
5150
import org.apache.hc.client5.http.ConnectTimeoutException;
5251
import org.apache.hc.core5.concurrent.DefaultThreadFactory;
5352
import org.apache.hc.core5.http.ClassicHttpResponse;
@@ -1094,35 +1093,35 @@ public synchronized void register(Class<?> clazz, TableSchema schema) {
10941093

10951094
if (defaultsSupport) {
10961095
if (value != null) {//Because we now support defaults, we have to send nonNull
1097-
BinaryStreamUtils.writeNonNull(stream);//Write 0 for no default
1096+
SerializerUtils.writeNonNull(stream);//Write 0 for no default
10981097

10991098
if (column.isNullable()) {//If the column is nullable
1100-
BinaryStreamUtils.writeNonNull(stream);//Write 0 for not null
1099+
SerializerUtils.writeNonNull(stream);//Write 0 for not null
11011100
}
11021101
} else {//So if the object is null
11031102
if (column.hasDefault()) {
1104-
BinaryStreamUtils.writeNull(stream);//Send 1 for default
1103+
SerializerUtils.writeNull(stream);//Send 1 for default
11051104
return;
11061105
} else if (column.isNullable()) {//And the column is nullable
1107-
BinaryStreamUtils.writeNonNull(stream);
1108-
BinaryStreamUtils.writeNull(stream);//Then we send null, write 1
1106+
SerializerUtils.writeNonNull(stream);
1107+
SerializerUtils.writeNull(stream);//Then we send null, write 1
11091108
return;//And we're done
11101109
} else if (column.getDataType() == ClickHouseDataType.Array) {//If the column is an array
1111-
BinaryStreamUtils.writeNonNull(stream);//Then we send nonNull
1110+
SerializerUtils.writeNonNull(stream);//Then we send nonNull
11121111
} else {
11131112
throw new IllegalArgumentException(String.format("An attempt to write null into not nullable column '%s'", column.getColumnName()));
11141113
}
11151114
}
11161115
} else {
11171116
if (column.isNullable()) {
11181117
if (value == null) {
1119-
BinaryStreamUtils.writeNull(stream);
1118+
SerializerUtils.writeNull(stream);
11201119
return;
11211120
}
1122-
BinaryStreamUtils.writeNonNull(stream);
1121+
SerializerUtils.writeNonNull(stream);
11231122
} else if (value == null) {
11241123
if (column.getDataType() == ClickHouseDataType.Array) {
1125-
BinaryStreamUtils.writeNonNull(stream);
1124+
SerializerUtils.writeNonNull(stream);
11261125
} else {
11271126
throw new IllegalArgumentException(String.format("An attempt to write null into not nullable column '%s'", column.getColumnName()));
11281127
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.clickhouse.client.api.data_formats;
22

33
import com.clickhouse.client.api.metadata.TableSchema;
4+
import com.clickhouse.data.value.ClickHouseBitmap;
45
import com.clickhouse.data.value.ClickHouseGeoMultiPolygonValue;
56
import com.clickhouse.data.value.ClickHouseGeoPointValue;
67
import com.clickhouse.data.value.ClickHouseGeoPolygonValue;
@@ -519,4 +520,8 @@ public interface ClickHouseBinaryFormatReader extends AutoCloseable {
519520
LocalDateTime getLocalDateTime(int index);
520521

521522
TableSchema getSchema();
523+
524+
ClickHouseBitmap getClickHouseBitmap(String colName);
525+
526+
ClickHouseBitmap getClickHouseBitmap(int index);
522527
}

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
import com.clickhouse.client.api.ClientException;
44
import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
5-
import com.clickhouse.client.api.internal.SerializerUtils;
65
import com.clickhouse.client.api.metadata.TableSchema;
76
import com.clickhouse.client.api.query.NullValueException;
87
import com.clickhouse.client.api.query.POJOSetter;
98
import com.clickhouse.client.api.query.QuerySettings;
109
import com.clickhouse.client.config.ClickHouseClientOption;
1110
import com.clickhouse.data.ClickHouseColumn;
11+
import com.clickhouse.data.value.ClickHouseBitmap;
1212
import com.clickhouse.data.value.ClickHouseGeoMultiPolygonValue;
1313
import com.clickhouse.data.value.ClickHouseGeoPointValue;
1414
import com.clickhouse.data.value.ClickHouseGeoPolygonValue;
@@ -707,6 +707,16 @@ public LocalDateTime getLocalDateTime(int index) {
707707
return (LocalDateTime) value;
708708
}
709709

710+
@Override
711+
public ClickHouseBitmap getClickHouseBitmap(String colName) {
712+
return readValue(colName);
713+
}
714+
715+
@Override
716+
public ClickHouseBitmap getClickHouseBitmap(int index) {
717+
return readValue(index);
718+
}
719+
710720
@Override
711721
public void close() throws Exception {
712722
input.close();

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
44
import com.clickhouse.client.api.query.GenericRecord;
5+
import com.clickhouse.data.value.ClickHouseBitmap;
56
import com.clickhouse.data.value.ClickHouseGeoMultiPolygonValue;
67
import com.clickhouse.data.value.ClickHouseGeoPointValue;
78
import com.clickhouse.data.value.ClickHouseGeoPolygonValue;
@@ -356,4 +357,14 @@ public Object getObject(String colName) {
356357
public Object getObject(int index) {
357358
return reader.readValue(index);
358359
}
360+
361+
@Override
362+
public ClickHouseBitmap getClickHouseBitmap(String colName) {
363+
return reader.readValue(colName);
364+
}
365+
366+
@Override
367+
public ClickHouseBitmap getClickHouseBitmap(int index) {
368+
return reader.readValue(index);
369+
}
359370
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ public <T> T readValue(ClickHouseColumn column, Class<?> typeHint) throws IOExce
216216
return null;
217217
// case SimpleAggregateFunction:
218218
case AggregateFunction:
219-
return (T) ClickHouseBitmap.deserialize(input, column.getNestedColumns().get(0).getDataType());
219+
return (T) readBitmap( column);
220220
default:
221221
throw new IllegalArgumentException("Unsupported data type: " + column.getDataType());
222222
}
@@ -887,6 +887,11 @@ public static boolean isReadToPrimitive(ClickHouseDataType dataType) {
887887
return false;
888888
}
889889
}
890+
891+
private ClickHouseBitmap readBitmap(ClickHouseColumn column) throws IOException {
892+
return ClickHouseBitmap.deserialize(input, column.getNestedColumns().get(0).getDataType());
893+
}
894+
890895
/**
891896
* Byte allocator that caches preallocated byte arrays for small sizes.
892897
*/

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.clickhouse.client.api.query.NullValueException;
77
import com.clickhouse.data.ClickHouseColumn;
88
import com.clickhouse.data.value.ClickHouseArrayValue;
9+
import com.clickhouse.data.value.ClickHouseBitmap;
910
import com.clickhouse.data.value.ClickHouseGeoMultiPolygonValue;
1011
import com.clickhouse.data.value.ClickHouseGeoPointValue;
1112
import com.clickhouse.data.value.ClickHouseGeoPolygonValue;
@@ -486,6 +487,16 @@ public LocalDateTime getLocalDateTime(int index) {
486487
return (LocalDateTime) value;
487488
}
488489

490+
@Override
491+
public ClickHouseBitmap getClickHouseBitmap(String colName) {
492+
return readValue(colName);
493+
}
494+
495+
@Override
496+
public ClickHouseBitmap getClickHouseBitmap(int index) {
497+
return readValue(index);
498+
}
499+
489500
@Override
490501
public Object getObject(String colName) {
491502
return readValue(colName);

client-v2/src/main/java/com/clickhouse/client/api/internal/SerializerUtils.java renamed to client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/SerializerUtils.java

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
package com.clickhouse.client.api.internal;
1+
package com.clickhouse.client.api.data_formats.internal;
22

33
import com.clickhouse.client.api.Client;
44
import com.clickhouse.client.api.ClientException;
5-
import com.clickhouse.client.api.data_formats.internal.BinaryStreamReader;
65
import com.clickhouse.client.api.query.POJOSetter;
76
import com.clickhouse.data.ClickHouseAggregateFunction;
87
import com.clickhouse.data.ClickHouseColumn;
@@ -72,14 +71,14 @@ private static void serializeArrayData(OutputStream stream, Object value, ClickH
7271
//Serialize the array to the stream
7372
//The array is a list of values
7473
List<?> values = (List<?>) value;
75-
BinaryStreamUtils.writeVarInt(stream, values.size());
74+
writeVarInt(stream, values.size());
7675
for (Object val : values) {
7776
if (column.getArrayBaseColumn().isNullable()) {
7877
if (val == null) {
79-
BinaryStreamUtils.writeNull(stream);
78+
writeNull(stream);
8079
continue;
8180
}
82-
BinaryStreamUtils.writeNonNull(stream);
81+
writeNonNull(stream);
8382
}
8483
serializeData(stream, val, column.getArrayBaseColumn());
8584
}
@@ -107,7 +106,7 @@ private static void serializeMapData(OutputStream stream, Object value, ClickHou
107106
//Serialize the map to the stream
108107
//The map is a list of key-value pairs
109108
Map<?, ?> map = (Map<?, ?>) value;
110-
BinaryStreamUtils.writeVarInt(stream, map.size());
109+
writeVarInt(stream, map.size());
111110
map.forEach((key, val) -> {
112111
try {
113112
serializePrimitiveData(stream, key, Objects.requireNonNull(column.getKeyInfo()));
@@ -213,7 +212,13 @@ private static void serializePrimitiveData(OutputStream stream, Object value, Cl
213212

214213
private static void serializeAggregateFunction(OutputStream stream, Object value, ClickHouseColumn column) throws IOException {
215214
if (column.getAggregateFunction() == ClickHouseAggregateFunction.groupBitmap) {
216-
BinaryStreamUtils.writeBitmap(stream, (ClickHouseBitmap) value);
215+
if (value == null) {
216+
throw new IllegalArgumentException("Cannot serialize null value for aggregate function: " + column.getAggregateFunction());
217+
} else if (value instanceof ClickHouseBitmap) {
218+
stream.write(((ClickHouseBitmap)value).toBytes()); // TODO: review toBytes() implementation - it can be simplified
219+
} else {
220+
throw new IllegalArgumentException("Cannot serialize value of type " + value.getClass() + " for aggregate function: " + column.getAggregateFunction());
221+
}
217222
} else {
218223
throw new UnsupportedOperationException("Unsupported aggregate function: " + column.getAggregateFunction());
219224
}
@@ -548,6 +553,36 @@ public Class<?> defineClass(String name, byte[] code) throws ClassNotFoundExcept
548553
}
549554
}
550555

556+
public static void writeVarInt(OutputStream output, long value) throws IOException {
557+
// reference code https://github.com/ClickHouse/ClickHouse/blob/abe314feecd1647d7c2b952a25da7abf5c19f352/src/IO/VarInt.h#L187
558+
for (int i = 0; i < 9; i++) {
559+
byte b = (byte) (value & 0x7F);
560+
561+
if (value > 0x7F) {
562+
b |= 0x80;
563+
}
564+
565+
output.write(b);
566+
value >>= 7;
567+
568+
if (value == 0) {
569+
return;
570+
}
571+
}
572+
}
573+
574+
public static void writeNull(OutputStream output) throws IOException {
575+
writeBoolean(output, true);
576+
}
577+
578+
public static void writeNonNull(OutputStream output) throws IOException {
579+
writeBoolean(output, false);
580+
}
581+
582+
public static void writeBoolean(OutputStream output, boolean value) throws IOException {
583+
output.write(value ? 1 : 0);
584+
}
585+
551586
public static class NumberConverter {
552587

553588
public static byte toByte(Number value) {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.clickhouse.client.api.ConnectionInitiationException;
1111
import com.clickhouse.client.api.ConnectionReuseStrategy;
1212
import com.clickhouse.client.api.ServerException;
13+
import com.clickhouse.client.api.data_formats.internal.SerializerUtils;
1314
import com.clickhouse.client.api.enums.ProxyType;
1415
import com.clickhouse.client.config.ClickHouseClientOption;
1516
import com.clickhouse.client.config.ClickHouseDefaults;

client-v2/src/main/java/com/clickhouse/client/api/query/GenericRecord.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.clickhouse.client.api.query;
22

3+
import com.clickhouse.data.value.ClickHouseBitmap;
34
import com.clickhouse.data.value.ClickHouseGeoMultiPolygonValue;
45
import com.clickhouse.data.value.ClickHouseGeoPointValue;
56
import com.clickhouse.data.value.ClickHouseGeoPolygonValue;
@@ -489,4 +490,8 @@ public interface GenericRecord {
489490
Object getObject(String colName);
490491

491492
Object getObject(int index);
493+
494+
ClickHouseBitmap getClickHouseBitmap(String colName);
495+
496+
ClickHouseBitmap getClickHouseBitmap(int index);
492497
}

0 commit comments

Comments
 (0)