com.clickhouse.client.data.ClickHouseRowBinaryProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of clickhouse-client Show documentation
Show all versions of clickhouse-client Show documentation
Unified Java client for ClickHouse
package com.clickhouse.client.data;
import java.io.EOFException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Map.Entry;
import java.util.function.Supplier;
import com.clickhouse.client.ClickHouseAggregateFunction;
import com.clickhouse.client.ClickHouseChecker;
import com.clickhouse.client.ClickHouseColumn;
import com.clickhouse.client.ClickHouseConfig;
import com.clickhouse.client.ClickHouseDataProcessor;
import com.clickhouse.client.ClickHouseDataType;
import com.clickhouse.client.ClickHouseDeserializer;
import com.clickhouse.client.ClickHouseFormat;
import com.clickhouse.client.ClickHouseInputStream;
import com.clickhouse.client.ClickHouseRecord;
import com.clickhouse.client.ClickHouseSerializer;
import com.clickhouse.client.ClickHouseUtils;
import com.clickhouse.client.ClickHouseValue;
import com.clickhouse.client.ClickHouseValues;
/**
* Data processor for handling {@link ClickHouseFormat#RowBinary} and
* {@link ClickHouseFormat#RowBinaryWithNamesAndTypes} two formats.
*/
public class ClickHouseRowBinaryProcessor extends ClickHouseDataProcessor {
public static class MappedFunctions {
private static final MappedFunctions instance = new MappedFunctions();
private void writeArray(ClickHouseValue value, ClickHouseConfig config, ClickHouseColumn column,
OutputStream output) throws IOException {
ClickHouseColumn nestedColumn = column.getNestedColumns().get(0);
ClickHouseColumn baseColumn = column.getArrayBaseColumn();
int level = column.getArrayNestedLevel();
Class> javaClass = baseColumn.getDataType().getPrimitiveClass();
if (level > 1 || !javaClass.isPrimitive()) {
Object[] array = value.asArray();
ClickHouseValue v = ClickHouseValues.newValue(config, nestedColumn);
int length = array.length;
BinaryStreamUtils.writeVarInt(output, length);
for (int i = 0; i < length; i++) {
serialize(v.update(array[i]), config, nestedColumn, output);
}
} else {
ClickHouseValue v = ClickHouseValues.newValue(config, baseColumn);
if (byte.class == javaClass) {
byte[] array = (byte[]) value.asObject();
int length = array.length;
BinaryStreamUtils.writeVarInt(output, length);
for (int i = 0; i < length; i++) {
serialize(v.update(array[i]), config, baseColumn, output);
}
} else if (short.class == javaClass) {
short[] array = (short[]) value.asObject();
int length = array.length;
BinaryStreamUtils.writeVarInt(output, length);
for (int i = 0; i < length; i++) {
serialize(v.update(array[i]), config, baseColumn, output);
}
} else if (int.class == javaClass) {
int[] array = (int[]) value.asObject();
int length = array.length;
BinaryStreamUtils.writeVarInt(output, length);
for (int i = 0; i < length; i++) {
serialize(v.update(array[i]), config, baseColumn, output);
}
} else if (long.class == javaClass) {
long[] array = (long[]) value.asObject();
int length = array.length;
BinaryStreamUtils.writeVarInt(output, length);
for (int i = 0; i < length; i++) {
serialize(v.update(array[i]), config, baseColumn, output);
}
} else if (float.class == javaClass) {
float[] array = (float[]) value.asObject();
int length = array.length;
BinaryStreamUtils.writeVarInt(output, length);
for (int i = 0; i < length; i++) {
serialize(v.update(array[i]), config, baseColumn, output);
}
} else if (double.class == javaClass) {
double[] array = (double[]) value.asObject();
int length = array.length;
BinaryStreamUtils.writeVarInt(output, length);
for (int i = 0; i < length; i++) {
serialize(v.update(array[i]), config, baseColumn, output);
}
} else {
throw new IllegalArgumentException("Unsupported primitive type: " + javaClass);
}
}
}
private ClickHouseValue readArray(ClickHouseValue ref, ClickHouseConfig config, ClickHouseColumn nestedColumn,
ClickHouseColumn baseColumn, ClickHouseInputStream input, int length, int level) throws IOException {
Class> javaClass = baseColumn.getDataType().getPrimitiveClass();
if (level > 1 || !javaClass.isPrimitive()) {
Object[] array = (Object[]) ClickHouseValues.createPrimitiveArray(javaClass, length, level);
for (int i = 0; i < length; i++) {
array[i] = deserialize(null, config, nestedColumn, input).asObject();
}
ref.update(array);
} else {
if (byte.class == javaClass) {
byte[] array = new byte[length];
for (int i = 0; i < length; i++) {
array[i] = deserialize(null, config, baseColumn, input).asByte();
}
ref.update(array);
} else if (short.class == javaClass) {
short[] array = new short[length];
for (int i = 0; i < length; i++) {
array[i] = deserialize(null, config, baseColumn, input).asShort();
}
ref.update(array);
} else if (int.class == javaClass) {
int[] array = new int[length];
for (int i = 0; i < length; i++) {
array[i] = deserialize(null, config, baseColumn, input).asInteger();
}
ref.update(array);
} else if (long.class == javaClass) {
long[] array = new long[length];
for (int i = 0; i < length; i++) {
array[i] = deserialize(null, config, baseColumn, input).asLong();
}
ref.update(array);
} else if (float.class == javaClass) {
float[] array = new float[length];
for (int i = 0; i < length; i++) {
array[i] = deserialize(null, config, baseColumn, input).asFloat();
}
ref.update(array);
} else if (double.class == javaClass) {
double[] array = new double[length];
for (int i = 0; i < length; i++) {
array[i] = deserialize(null, config, baseColumn, input).asDouble();
}
ref.update(array);
} else {
throw new IllegalArgumentException("Unsupported primitive type: " + javaClass);
}
}
return ref;
}
private final Map> aggDeserializers;
private final Map> aggSerializers;
private final Map> deserializers;
private final Map> serializers;
private void buildMappingsForAggregateFunctions() {
// aggregate functions
// buildAggMappings(aggDeserializers, aggSerializers,
// (r, f, c, i) -> {
// BinaryStreamUtils.readInt8(i); // always 1?
// return deserialize(r, f, c.getNestedColumns().get(0), i);
// },
// (v, f, c, o) -> {
// // no that simple:
// // * select anyState(n) from (select '5' where 0) => FFFF
// // * select anyState(n) from (select '5') => 0200 0000 3500
// BinaryStreamUtils.writeInt8(o, (byte) 1);
// serialize(v, f, c.getNestedColumns().get(0), o);
// }, ClickHouseAggregateFunction.any);
buildAggMappings(aggDeserializers, aggSerializers,
(r, f, c, i) -> ClickHouseBitmapValue
.of(BinaryStreamUtils.readBitmap(i, c.getNestedColumns().get(0).getDataType())),
(v, f, c, o) -> BinaryStreamUtils.writeBitmap(o, v.asObject(ClickHouseBitmap.class)),
ClickHouseAggregateFunction.groupBitmap);
// now the data type
buildMappings(deserializers, serializers, (r, f, c, i) -> aggDeserializers
.getOrDefault(c.getAggregateFunction(), ClickHouseDeserializer.NOT_SUPPORTED)
.deserialize(r, f, c, i),
(v, f, c, o) -> aggSerializers
.getOrDefault(c.getAggregateFunction(), ClickHouseSerializer.NOT_SUPPORTED)
.serialize(v, f, c, o),
ClickHouseDataType.AggregateFunction);
}
private void buildMappingsForDataTypes() {
// enums
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseEnumValue.of(r, c.getEnumConstants(), BinaryStreamUtils.readInt8(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInt8(o, v.asByte()), ClickHouseDataType.Enum,
ClickHouseDataType.Enum8);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseEnumValue.of(r, c.getEnumConstants(), BinaryStreamUtils.readInt16(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInt16(o, v.asShort()), ClickHouseDataType.Enum16);
// bool and numbers
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseBoolValue.of(r, BinaryStreamUtils.readBoolean(i)),
(v, f, c, o) -> BinaryStreamUtils.writeBoolean(o, v.asBoolean()), ClickHouseDataType.Bool);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseByteValue.of(r, BinaryStreamUtils.readInt8(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInt8(o, v.asByte()), ClickHouseDataType.Int8);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseShortValue.of(r, BinaryStreamUtils.readUnsignedInt8(i)),
(v, f, c, o) -> BinaryStreamUtils.writeUnsignedInt8(o, v.asInteger()), ClickHouseDataType.UInt8);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseShortValue.of(r, BinaryStreamUtils.readInt16(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInt16(o, v.asShort()), ClickHouseDataType.Int16);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseIntegerValue.of(r, BinaryStreamUtils.readUnsignedInt16(i)),
(v, f, c, o) -> BinaryStreamUtils.writeUnsignedInt16(o, v.asInteger()), ClickHouseDataType.UInt16);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseIntegerValue.of(r, BinaryStreamUtils.readInt32(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInt32(o, v.asInteger()), ClickHouseDataType.Int32);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseLongValue.of(r, false, BinaryStreamUtils.readUnsignedInt32(i)),
(v, f, c, o) -> BinaryStreamUtils.writeUnsignedInt32(o, v.asLong()), ClickHouseDataType.UInt32);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseLongValue.of(r, false, BinaryStreamUtils.readInt64(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInt64(o, v.asLong()), ClickHouseDataType.IntervalYear,
ClickHouseDataType.IntervalQuarter, ClickHouseDataType.IntervalMonth,
ClickHouseDataType.IntervalWeek, ClickHouseDataType.IntervalDay, ClickHouseDataType.IntervalHour,
ClickHouseDataType.IntervalMinute, ClickHouseDataType.IntervalSecond, ClickHouseDataType.Int64);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseLongValue.of(r, true, BinaryStreamUtils.readInt64(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInt64(o, v.asLong()), ClickHouseDataType.UInt64);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseBigIntegerValue.of(r, BinaryStreamUtils.readInt128(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInt128(o, v.asBigInteger()), ClickHouseDataType.Int128);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseBigIntegerValue.of(r, BinaryStreamUtils.readUnsignedInt128(i)),
(v, f, c, o) -> BinaryStreamUtils.writeUnsignedInt128(o, v.asBigInteger()),
ClickHouseDataType.UInt128);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseBigIntegerValue.of(r, BinaryStreamUtils.readInt256(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInt256(o, v.asBigInteger()), ClickHouseDataType.Int256);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseBigIntegerValue.of(r, BinaryStreamUtils.readUnsignedInt256(i)),
(v, f, c, o) -> BinaryStreamUtils.writeUnsignedInt256(o, v.asBigInteger()),
ClickHouseDataType.UInt256);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseFloatValue.of(r, BinaryStreamUtils.readFloat32(i)),
(v, f, c, o) -> BinaryStreamUtils.writeFloat32(o, v.asFloat()), ClickHouseDataType.Float32);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseDoubleValue.of(r, BinaryStreamUtils.readFloat64(i)),
(v, f, c, o) -> BinaryStreamUtils.writeFloat64(o, v.asDouble()), ClickHouseDataType.Float64);
// decimals
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseBigDecimalValue.of(r,
BinaryStreamUtils.readDecimal(i, c.getPrecision(), c.getScale())),
(v, f, c, o) -> BinaryStreamUtils.writeDecimal(o, v.asBigDecimal(c.getScale()), c.getPrecision(),
c.getScale()),
ClickHouseDataType.Decimal);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseBigDecimalValue.of(r, BinaryStreamUtils.readDecimal32(i, c.getScale())),
(v, f, c, o) -> BinaryStreamUtils.writeDecimal32(o, v.asBigDecimal(c.getScale()), c.getScale()),
ClickHouseDataType.Decimal32);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseBigDecimalValue.of(r, BinaryStreamUtils.readDecimal64(i, c.getScale())),
(v, f, c, o) -> BinaryStreamUtils.writeDecimal64(o, v.asBigDecimal(c.getScale()), c.getScale()),
ClickHouseDataType.Decimal64);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseBigDecimalValue.of(r, BinaryStreamUtils.readDecimal128(i, c.getScale())),
(v, f, c, o) -> BinaryStreamUtils.writeDecimal128(o, v.asBigDecimal(c.getScale()), c.getScale()),
ClickHouseDataType.Decimal128);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseBigDecimalValue.of(r, BinaryStreamUtils.readDecimal256(i, c.getScale())),
(v, f, c, o) -> BinaryStreamUtils.writeDecimal256(o, v.asBigDecimal(c.getScale()), c.getScale()),
ClickHouseDataType.Decimal256);
// date, time, datetime and IPs
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseDateValue.of(r,
BinaryStreamUtils.readDate(i, f.getTimeZoneForDate())),
(v, f, c, o) -> BinaryStreamUtils.writeDate(o, v.asDate(), f.getTimeZoneForDate()),
ClickHouseDataType.Date);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseDateValue.of(r,
BinaryStreamUtils.readDate32(i, f.getTimeZoneForDate())),
(v, f, c, o) -> BinaryStreamUtils.writeDate(o, v.asDate(), f.getTimeZoneForDate()),
ClickHouseDataType.Date32);
buildMappings(deserializers, serializers, (r, f, c, i) -> c.getTimeZone() == null
? ClickHouseDateTimeValue.of(r,
(c.getScale() > 0 ? BinaryStreamUtils.readDateTime64(i, c.getScale(), f.getUseTimeZone())
: BinaryStreamUtils.readDateTime(i, f.getUseTimeZone())),
c.getScale(), f.getUseTimeZone())
: ClickHouseOffsetDateTimeValue.of(r,
(c.getScale() > 0 ? BinaryStreamUtils.readDateTime64(i, c.getScale(), c.getTimeZone())
: BinaryStreamUtils.readDateTime(i, c.getTimeZone())),
c.getScale(), c.getTimeZone()),
(v, f, c, o) -> BinaryStreamUtils.writeDateTime(o, v.asDateTime(), c.getScale(),
c.getTimeZoneOrDefault(f.getUseTimeZone())),
ClickHouseDataType.DateTime);
buildMappings(deserializers, serializers,
(r, f, c, i) -> c.getTimeZone() == null
? ClickHouseDateTimeValue.of(r, BinaryStreamUtils.readDateTime(i, f.getUseTimeZone()), 0,
f.getUseTimeZone())
: ClickHouseOffsetDateTimeValue.of(r, BinaryStreamUtils.readDateTime(i, c.getTimeZone()), 0,
c.getTimeZone()),
(v, f, c, o) -> BinaryStreamUtils.writeDateTime32(o, v.asDateTime(),
c.getTimeZoneOrDefault(f.getUseTimeZone())),
ClickHouseDataType.DateTime32);
buildMappings(deserializers, serializers,
(r, f, c, i) -> c.getTimeZone() == null ? ClickHouseDateTimeValue.of(r,
BinaryStreamUtils.readDateTime64(i, c.getScale(), f.getUseTimeZone()), c.getScale(),
f.getUseTimeZone())
: ClickHouseOffsetDateTimeValue.of(r,
BinaryStreamUtils.readDateTime64(i, c.getScale(), c.getTimeZone()), c.getScale(),
c.getTimeZone()),
(v, f, c, o) -> BinaryStreamUtils.writeDateTime64(o, v.asDateTime(), c.getScale(),
c.getTimeZoneOrDefault(f.getUseTimeZone())),
ClickHouseDataType.DateTime64);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseIpv4Value.of(r, BinaryStreamUtils.readInet4Address(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInet4Address(o, v.asInet4Address()),
ClickHouseDataType.IPv4);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseIpv6Value.of(r, BinaryStreamUtils.readInet6Address(i)),
(v, f, c, o) -> BinaryStreamUtils.writeInet6Address(o, v.asInet6Address()),
ClickHouseDataType.IPv6);
// string and uuid
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseStringValue.of(r, BinaryStreamUtils.readFixedString(i, c.getPrecision())),
(v, f, c, o) -> BinaryStreamUtils.writeFixedString(o, v.asString(c.getPrecision()),
c.getPrecision()),
ClickHouseDataType.FixedString);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseStringValue.of(r, i.readUnicodeString()),
(v, f, c, o) -> BinaryStreamUtils.writeString(o, v.asString()), ClickHouseDataType.String);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseUuidValue.of(r, BinaryStreamUtils.readUuid(i)),
(v, f, c, o) -> BinaryStreamUtils.writeUuid(o, v.asUuid()), ClickHouseDataType.UUID);
// geo types
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseGeoPointValue.of(r, BinaryStreamUtils.readGeoPoint(i)),
(v, f, c, o) -> BinaryStreamUtils.writeGeoPoint(o, v.asObject(double[].class)),
ClickHouseDataType.Point);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseGeoRingValue.of(r, BinaryStreamUtils.readGeoRing(i)),
(v, f, c, o) -> BinaryStreamUtils.writeGeoRing(o, v.asObject(double[][].class)),
ClickHouseDataType.Ring);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseGeoPolygonValue.of(r, BinaryStreamUtils.readGeoPolygon(i)),
(v, f, c, o) -> BinaryStreamUtils.writeGeoPolygon(o, v.asObject(double[][][].class)),
ClickHouseDataType.Polygon);
buildMappings(deserializers, serializers,
(r, f, c, i) -> ClickHouseGeoMultiPolygonValue.of(r, BinaryStreamUtils.readGeoMultiPolygon(i)),
(v, f, c, o) -> BinaryStreamUtils.writeGeoMultiPolygon(o, v.asObject(double[][][][].class)),
ClickHouseDataType.MultiPolygon);
// advanced types
buildMappings(deserializers, serializers, (r, f, c, i) -> {
int length = BinaryStreamUtils.readVarInt(i);
if (r == null) {
r = ClickHouseValues.newValue(f, c);
}
return readArray(r, f, c.getNestedColumns().get(0), c.getArrayBaseColumn(), i, length,
c.getArrayNestedLevel());
}, this::writeArray, ClickHouseDataType.Array);
buildMappings(deserializers, serializers, (r, f, c, i) -> {
Map