Skip to content

Commit 4cbf494

Browse files
committed
Merge branch 'main' into v2_json_support
2 parents 3012dba + 897edce commit 4cbf494

39 files changed

+7677
-88
lines changed

clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseServerForTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ public class ClickHouseServerForTest {
172172
ClickHouseProtocol.TCP.getDefaultSecurePort(),
173173
ClickHouseProtocol.POSTGRESQL.getDefaultPort())
174174
.withClasspathResourceMapping("containers/clickhouse-server", customDirectory, BindMode.READ_ONLY)
175+
.withClasspathResourceMapping("empty.csv", "/var/lib/clickhouse/user_files/empty.csv", BindMode.READ_ONLY)
175176
.withFileSystemBind(System.getProperty("java.io.tmpdir"), getClickHouseContainerTmpDir(),
176177
BindMode.READ_WRITE)
177178
.withNetwork(network)

clickhouse-client/src/test/resources/empty.csv

Whitespace-only changes.

client-v2/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
<artifactId>jackson-core</artifactId>
6767
<version>2.17.2</version>
6868
</dependency>
69+
6970
<!-- Test Dependencies -->
7071
<dependency>
7172
<groupId>com.google.code.gson</groupId>

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

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ protected void setSchema(TableSchema schema) {
236236
for (int i = 0; i < columns.length; i++) {
237237
ClickHouseColumn column = columns[i];
238238

239-
Map<NumberType, Function<Number, ?>> converters = new HashMap<>();
239+
Map<NumberType, Function<Object, ?>> converters = new HashMap<>();
240240
switch (column.getDataType()) {
241241
case Int8:
242242
case Int16:
@@ -305,9 +305,9 @@ public String getString(int index) {
305305

306306
private <T> T readNumberValue(String colName, NumberType targetType) {
307307
int colIndex = schema.nameToIndex(colName);
308-
Function<Number, Number> converter = (Function<Number, Number>) convertions[colIndex].get(targetType);
308+
Function<Object, Object> converter = (Function<Object, Object>) convertions[colIndex].get(targetType);
309309
if (converter != null) {
310-
Number value = readValue(colName);
310+
Object value = readValue(colName);
311311
if (value == null) {
312312
throw new NullValueException("Column " + colName + " has null value and it cannot be cast to " +
313313
targetType.getTypeName());
@@ -471,17 +471,25 @@ public ClickHouseGeoMultiPolygonValue getGeoMultiPolygon(String colName) {
471471

472472
@Override
473473
public <T> List<T> getList(String colName) {
474-
BinaryStreamReader.ArrayValue array = readValue(colName);
475-
return array.asList();
474+
try {
475+
BinaryStreamReader.ArrayValue array = readValue(colName);
476+
return array.asList();
477+
} catch (ClassCastException e) {
478+
throw new ClientException("Column is not of array type", e);
479+
}
476480
}
477481

478482

479483
private <T> T getPrimitiveArray(String colName) {
480-
BinaryStreamReader.ArrayValue array = readValue(colName);
481-
if (array.itemType.isPrimitive()) {
482-
return (T) array.array;
483-
} else {
484-
throw new ClientException("Array is not of primitive type");
484+
try {
485+
BinaryStreamReader.ArrayValue array = readValue(colName);
486+
if (array.itemType.isPrimitive()) {
487+
return (T) array.array;
488+
} else {
489+
throw new ClientException("Array is not of primitive type");
490+
}
491+
} catch (ClassCastException e) {
492+
throw new ClientException("Column is not of array type", e);
485493
}
486494
}
487495

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

Lines changed: 104 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -585,73 +585,140 @@ public static void writeBoolean(OutputStream output, boolean value) throws IOExc
585585

586586
public static class NumberConverter {
587587

588-
public static byte toByte(Number value) {
589-
if (value.byteValue() == value.shortValue()) {
590-
return value.byteValue();
588+
public static byte toByte(Object value) {
589+
if (value instanceof Number) {
590+
Number number = (Number) value;
591+
if (number.byteValue() == number.shortValue()) {
592+
return number.byteValue();
593+
} else {
594+
throw new ArithmeticException("integer overflow: " + value + " cannot be presented as byte");
595+
}
596+
} else if (value instanceof Boolean) {
597+
return (byte) ((Boolean) value ? 1 : 0);
598+
} else if (value instanceof String) {
599+
return Byte.parseByte(value.toString());
591600
} else {
592-
throw new ArithmeticException("integer overflow: " + value + " cannot be presented as byte");
601+
throw new IllegalArgumentException("Cannot convert " + value + " to byte value");
593602
}
594603
}
595604

596-
public static short toShort(Number value) {
597-
if (value.shortValue() == value.intValue()) {
598-
return value.shortValue();
605+
public static short toShort(Object value) {
606+
if (value instanceof Number) {
607+
Number number = (Number) value;
608+
if (number.shortValue() == number.intValue()) {
609+
return number.shortValue();
610+
} else {
611+
throw new ArithmeticException("integer overflow: " + value + " cannot be presented as short");
612+
}
613+
} else if (value instanceof Boolean) {
614+
return (short) ((Boolean) value ? 1 : 0);
615+
} else if ( value instanceof String) {
616+
return Short.parseShort(value.toString());
599617
} else {
600-
throw new ArithmeticException("integer overflow: " + value + " cannot be presented as short");
618+
throw new IllegalArgumentException("Cannot convert " + value + " to short value");
601619
}
602620
}
603621

604-
public static int toInt(Number value) {
605-
if (value.intValue() == value.longValue()) {
606-
return value.intValue();
622+
public static int toInt(Object value) {
623+
if (value instanceof Number) {
624+
Number number = (Number) value;
625+
if (number.intValue() == number.longValue()) {
626+
return number.intValue();
627+
} else {
628+
throw new ArithmeticException("integer overflow: " + value + " cannot be presented as int");
629+
}
630+
} else if (value instanceof Boolean) {
631+
return (Boolean) value ? 1 : 0;
632+
} else if (value instanceof String) {
633+
return Integer.parseInt((String) value);
607634
} else {
608-
throw new ArithmeticException("integer overflow: " + value + " cannot be presented as int");
635+
throw new IllegalArgumentException("Cannot convert " + value + " to int value");
609636
}
610637
}
611638

612-
public static long toLong(Number value) {
613-
if (value.longValue() == value.doubleValue()) {
614-
return value.longValue();
639+
public static long toLong(Object value) {
640+
if (value instanceof Number) {
641+
Number number = (Number) value;
642+
if (number.longValue() == number.doubleValue()) {
643+
return number.longValue();
644+
} else {
645+
throw new ArithmeticException("integer overflow: " + value + " cannot be presented as long");
646+
}
647+
} else if (value instanceof Boolean) {
648+
return (Boolean) value ? 1 : 0;
649+
} else if (value instanceof String) {
650+
return Long.parseLong((String) value);
615651
} else {
616-
throw new ArithmeticException("integer overflow: " + value + " cannot be presented as long");
652+
throw new IllegalArgumentException("Cannot convert " + value + " to long value");
617653
}
618654
}
619655

620-
621-
public static BigInteger toBigInteger(Number value) {
622-
return value instanceof BigInteger ? (BigInteger) value : BigInteger.valueOf(value.longValue());
623-
}
624-
625-
public static BigInteger toBigInteger(String value) {
626-
return new BigInteger(value);
656+
public static BigInteger toBigInteger(Object value) {
657+
if (value instanceof BigInteger) {
658+
return (BigInteger) value;
659+
} else if (value instanceof Number) {
660+
return BigInteger.valueOf(((Number) value).longValue());
661+
} else if (value instanceof Boolean) {
662+
return (Boolean) value ? BigInteger.ONE : BigInteger.ZERO;
663+
} else if (value instanceof String) {
664+
return new BigInteger((String) value);
665+
} else {
666+
throw new IllegalArgumentException("Cannot convert " + value + " to BigInteger value");
667+
}
627668
}
628669

629-
public static float toFloat(Number value) {
670+
public static float toFloat(Object value) {
630671
if (value instanceof Float) {
631672
return (Float) value;
632-
} else if (value.floatValue() == value.doubleValue()) {
633-
return value.floatValue();
673+
} else if (value instanceof Number) {
674+
Number number = (Number) value;
675+
if (number.floatValue() == number.doubleValue()) {
676+
return number.floatValue();
677+
} else {
678+
throw new ArithmeticException("float overflow: " + value + " cannot be presented as float");
679+
}
680+
} else if (value instanceof Boolean) {
681+
return (Boolean) value ? 1.0f : 0.0f;
682+
} else if (value instanceof String ) {
683+
return Float.parseFloat((String) value);
634684
} else {
635-
throw new ArithmeticException("float overflow: " + value + " cannot be presented as float");
685+
throw new IllegalArgumentException("Cannot convert " + value + " to float value");
636686
}
637687
}
638688

639-
public static double toDouble(Number value) {
689+
public static double toDouble(Object value) {
640690
if (value instanceof Double) {
641691
return (Double) value;
642-
} else if (value.doubleValue() == value.floatValue()) {
643-
return value.doubleValue();
692+
} else if (value instanceof Number) {
693+
Number number = (Number) value;
694+
if (number.doubleValue() == number.floatValue()) {
695+
return number.doubleValue();
696+
} else {
697+
throw new ArithmeticException("double overflow: " + value + " cannot be presented as double");
698+
}
699+
} else if (value instanceof Boolean) {
700+
return (Boolean) value ? 1.0 : 0.0;
701+
} else if (value instanceof String) {
702+
return Double.parseDouble((String) value);
644703
} else {
645-
throw new ArithmeticException("double overflow: " + value + " cannot be presented as double");
704+
throw new IllegalArgumentException("Cannot convert " + value + " to double value");
646705
}
647706
}
648707

649-
public static BigDecimal toBigDecimal(Number value) {
650-
return value instanceof BigDecimal ? (BigDecimal) value : BigDecimal.valueOf(value.doubleValue());
651-
}
652-
653-
public static BigDecimal toBigDecimal(String value) {
654-
return new BigDecimal(value);
708+
public static BigDecimal toBigDecimal(Object value) {
709+
if (value instanceof BigDecimal) {
710+
return (BigDecimal) value;
711+
} else if (value instanceof BigInteger) {
712+
return new BigDecimal((BigInteger) value);
713+
} else if (value instanceof Number) {
714+
return BigDecimal.valueOf(((Number) value).doubleValue());
715+
} else if (value instanceof String) {
716+
return new BigDecimal((String) value);
717+
} else if (value instanceof Boolean) {
718+
return (Boolean) value ? BigDecimal.ONE : BigDecimal.ZERO;
719+
} else {
720+
throw new IllegalArgumentException("Cannot convert " + value + " to BigDecimal value");
721+
}
655722
}
656723
}
657724
}

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

Lines changed: 50 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
import java.net.NoRouteToHostException;
6464
import java.net.URI;
6565
import java.net.URISyntaxException;
66-
import java.net.URLEncoder;
6766
import java.net.UnknownHostException;
6867
import java.nio.charset.StandardCharsets;
6968
import java.security.NoSuchAlgorithmException;
@@ -288,32 +287,49 @@ public Exception readError(ClassicHttpResponse httpResponse) {
288287

289288
byte [] buffer = new byte[ERROR_BODY_BUFFER_SIZE];
290289
byte [] lookUpStr = String.format(ERROR_CODE_PREFIX_PATTERN, serverCode).getBytes(StandardCharsets.UTF_8);
290+
StringBuilder msgBuilder = new StringBuilder();
291+
boolean found = false;
291292
while (true) {
292293
int rBytes = body.read(buffer);
293294
if (rBytes == -1) {
294295
break;
295-
} else {
296-
for (int i = 0; i < rBytes; i++) {
297-
if (buffer[i] == lookUpStr[0]) {
298-
boolean found = true;
299-
for (int j = 1; j < Math.min(rBytes - i, lookUpStr.length); j++) {
300-
if (buffer[i + j] != lookUpStr[j]) {
301-
found = false;
302-
break;
303-
}
304-
}
305-
if (found) {
296+
}
306297

307-
return new ServerException(serverCode, new String(buffer, i, rBytes - i, StandardCharsets.UTF_8));
298+
for (int i = 0; i < rBytes; i++) {
299+
if (buffer[i] == lookUpStr[0]) {
300+
found = true;
301+
for (int j = 1; j < Math.min(rBytes - i, lookUpStr.length); j++) {
302+
if (buffer[i + j] != lookUpStr[j]) {
303+
found = false;
304+
break;
308305
}
309306
}
307+
if (found) {
308+
msgBuilder.append(new String(buffer, i, rBytes - i, StandardCharsets.UTF_8));
309+
break;
310+
}
310311
}
311312
}
313+
314+
if (found) {
315+
break;
316+
}
312317
}
313318

319+
while (true) {
320+
int rBytes = body.read(buffer);
321+
if (rBytes == -1) {
322+
break;
323+
}
324+
msgBuilder.append(new String(buffer, 0, rBytes, StandardCharsets.UTF_8));
325+
}
326+
327+
String msg = msgBuilder.toString().replaceAll("\\s+", " ").replaceAll("\\\\n", " ")
328+
.replaceAll("\\\\/", "/");
329+
return new ServerException(serverCode, msg);
330+
} catch (Exception e) {
331+
LOG.error("Failed to read error message", e);
314332
return new ServerException(serverCode, String.format(ERROR_CODE_PREFIX_PATTERN, serverCode) + " <Unreadable error message>");
315-
} catch (IOException e) {
316-
throw new ClientException("Failed to read response body", e);
317333
}
318334
}
319335

@@ -500,26 +516,28 @@ private void addQueryParams(URIBuilder req, Map<String, String> chConfig, Map<St
500516
}
501517

502518
private HttpEntity wrapEntity(HttpEntity httpEntity, int httpStatus, boolean isResponse) {
503-
504-
switch (httpStatus) {
505-
case HttpStatus.SC_OK:
506-
case HttpStatus.SC_CREATED:
507-
case HttpStatus.SC_ACCEPTED:
508-
case HttpStatus.SC_NO_CONTENT:
509-
case HttpStatus.SC_PARTIAL_CONTENT:
510-
case HttpStatus.SC_RESET_CONTENT:
511-
case HttpStatus.SC_NOT_MODIFIED:
512-
case HttpStatus.SC_BAD_REQUEST:
513-
boolean serverCompression = chConfiguration.getOrDefault(ClickHouseClientOption.COMPRESS.getKey(), "false").equalsIgnoreCase("true");
514-
boolean clientCompression = chConfiguration.getOrDefault(ClickHouseClientOption.DECOMPRESS.getKey(), "false").equalsIgnoreCase("true");
515-
boolean useHttpCompression = chConfiguration.getOrDefault("client.use_http_compression", "false").equalsIgnoreCase("true");
516-
if (serverCompression || clientCompression) {
519+
boolean serverCompression = MapUtils.getFlag(chConfiguration, ClickHouseClientOption.COMPRESS.getKey(), false);
520+
boolean clientCompression = MapUtils.getFlag(chConfiguration, ClickHouseClientOption.DECOMPRESS.getKey(), false);
521+
522+
if (serverCompression || clientCompression) {
523+
// Server doesn't compress certain errors like 403
524+
switch (httpStatus) {
525+
case HttpStatus.SC_OK:
526+
case HttpStatus.SC_CREATED:
527+
case HttpStatus.SC_ACCEPTED:
528+
case HttpStatus.SC_NO_CONTENT:
529+
case HttpStatus.SC_PARTIAL_CONTENT:
530+
case HttpStatus.SC_RESET_CONTENT:
531+
case HttpStatus.SC_NOT_MODIFIED:
532+
case HttpStatus.SC_BAD_REQUEST:
533+
case HttpStatus.SC_INTERNAL_SERVER_ERROR:
534+
boolean useHttpCompression = MapUtils.getFlag(chConfiguration, "client.use_http_compression", false);
517535
return new LZ4Entity(httpEntity, useHttpCompression, serverCompression, clientCompression,
518536
MapUtils.getInt(chConfiguration, "compression.lz4.uncompressed_buffer_size"), isResponse);
519-
}
520-
default:
521-
return httpEntity;
537+
}
522538
}
539+
540+
return httpEntity;
523541
}
524542

525543
public static int getHeaderInt(Header header, int defaultValue) {

0 commit comments

Comments
 (0)