Skip to content

Commit 3b0a353

Browse files
authored
Merge pull request #868 from ClickHouse/develop
Merge patch7
2 parents 13e98e2 + 0585961 commit 3b0a353

24 files changed

+641
-65
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ Note: in general, the new driver(v0.3.2) is a few times faster with less memory
112112
<groupId>com.clickhouse</groupId>
113113
<!-- or clickhouse-grpc-client if you prefer gRPC -->
114114
<artifactId>clickhouse-http-client</artifactId>
115-
<version>0.3.2-patch6</version>
115+
<version>0.3.2-patch7</version>
116116
</dependency>
117117
```
118118

@@ -148,7 +148,7 @@ try (ClickHouseClient client = ClickHouseClient.newInstance(preferredProtocol);
148148
<!-- will stop using ru.yandex.clickhouse starting from 0.4.0 -->
149149
<groupId>com.clickhouse</groupId>
150150
<artifactId>clickhouse-jdbc</artifactId>
151-
<version>0.3.2-patch6</version>
151+
<version>0.3.2-patch7</version>
152152
<!-- below is only needed when all you want is a shaded jar -->
153153
<classifier>http</classifier>
154154
<exclusions>

clickhouse-benchmark/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<properties>
1919
<legacy-driver.version>0.3.1-patch</legacy-driver.version>
2020
<clickhouse4j-driver.version>1.4.4</clickhouse4j-driver.version>
21-
<native-driver.version>2.6.4</native-driver.version>
21+
<native-driver.version>2.6.5</native-driver.version>
2222
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
2323
<jmh.version>1.34</jmh.version>
2424
<shade.name>benchmarks</shade.name>

clickhouse-client/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Async Java client for ClickHouse. `clickhouse-client` is an abstract module, so
99
<dependency>
1010
<groupId>com.clickhouse</groupId>
1111
<artifactId>clickhouse-http-client</artifactId>
12-
<version>0.3.2-patch6</version>
12+
<version>0.3.2-patch7</version>
1313
</dependency>
1414
```
1515

clickhouse-client/src/main/java/com/clickhouse/client/AbstractClient.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import java.util.concurrent.CompletableFuture;
44
import java.util.concurrent.CompletionException;
55
import java.util.concurrent.ExecutorService;
6-
import java.util.concurrent.TimeUnit;
76
import java.util.concurrent.locks.ReadWriteLock;
87
import java.util.concurrent.locks.ReentrantReadWriteLock;
98

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClient.java

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.io.IOException;
55
import java.io.InputStream;
66
import java.io.OutputStream;
7+
import java.io.UncheckedIOException;
78
import java.util.ArrayList;
89
import java.util.LinkedList;
910
import java.util.List;
@@ -49,13 +50,12 @@ static ClickHouseClientBuilder builder() {
4950

5051
/**
5152
* Gets default {@link java.util.concurrent.ExecutorService} for static methods
52-
* like {@code dump()}, {@code load()}, {@code send()}, and {@code submit()}
53-
* when {@link com.clickhouse.client.config.ClickHouseDefaults#ASYNC} is
54-
* {@code true}. It will be shared among all client instances when
53+
* like {@code dump()}, {@code load()}, {@code send()}, and {@code submit()}. It
54+
* will be shared among all client instances when
5555
* {@link com.clickhouse.client.config.ClickHouseClientOption#MAX_THREADS_PER_CLIENT}
5656
* is less than or equals to zero.
5757
*
58-
* @return default executor service
58+
* @return non-null default executor service
5959
*/
6060
static ExecutorService getExecutorService() {
6161
return ClickHouseClientBuilder.defaultExecutor;
@@ -68,7 +68,7 @@ static ExecutorService getExecutorService() {
6868
*
6969
* @param <T> return type of the task
7070
* @param task non-null task
71-
* @return future object to get result
71+
* @return non-null future object to get result
7272
* @throws CompletionException when failed to complete the task
7373
*/
7474
static <T> CompletableFuture<T> submit(Callable<T> task) {
@@ -114,7 +114,7 @@ static <T> CompletableFuture<T> submit(Callable<T> task) {
114114
* @param format output format to use
115115
* @param compression compression algorithm to use
116116
* @param file output file
117-
* @return future object to get result
117+
* @return non-null future object to get result
118118
* @throws IllegalArgumentException if any of server, tableOrQuery, and output
119119
* is null
120120
* @throws CompletionException when error occurred during execution
@@ -592,7 +592,8 @@ default boolean accept(ClickHouseProtocol protocol) {
592592
* invoked(usually triggered by {@code request.execute()}).
593593
*
594594
* @param nodeFunc function to get a {@link ClickHouseNode} to connect to
595-
* @return request object holding references to this client and node provider
595+
* @return non-null request object holding references to this client and node
596+
* provider
596597
*/
597598
default ClickHouseRequest<?> connect(Function<ClickHouseNodeSelector, ClickHouseNode> nodeFunc) {
598599
return new ClickHouseRequest<>(this, ClickHouseChecker.nonNull(nodeFunc, "nodeFunc"), false);
@@ -609,17 +610,47 @@ default ClickHouseRequest<?> connect(Function<ClickHouseNodeSelector, ClickHouse
609610
* execution, meaning you're free to make any change to this
610611
* object(e.g. prepare for next call using different SQL
611612
* statement) without impacting the execution
612-
* @return future object to get result
613+
* @return non-null future object to get result
613614
* @throws CompletionException when error occurred during execution
614615
*/
615616
CompletableFuture<ClickHouseResponse> execute(ClickHouseRequest<?> request);
616617

618+
/**
619+
* Synchronous version of {@link #execute(ClickHouseRequest)}.
620+
*
621+
* @param request request object which will be sealed(immutable copy) upon
622+
* execution
623+
* @return non-null response
624+
* @throws ClickHouseException when error occurred during execution
625+
*/
626+
default ClickHouseResponse executeAndWait(ClickHouseRequest<?> request) throws ClickHouseException {
627+
final ClickHouseRequest<?> sealedRequest = request.seal();
628+
629+
try {
630+
return execute(sealedRequest).get();
631+
} catch (InterruptedException e) {
632+
Thread.currentThread().interrupt();
633+
throw ClickHouseException.forCancellation(e, sealedRequest.getServer());
634+
} catch (CancellationException e) {
635+
throw ClickHouseException.forCancellation(e, sealedRequest.getServer());
636+
} catch (CompletionException | ExecutionException | UncheckedIOException e) {
637+
Throwable cause = e.getCause();
638+
if (cause == null) {
639+
cause = e;
640+
}
641+
throw cause instanceof ClickHouseException ? (ClickHouseException) cause
642+
: ClickHouseException.of(cause, sealedRequest.getServer());
643+
} catch (RuntimeException e) { // unexpected
644+
throw ClickHouseException.of(e, sealedRequest.getServer());
645+
}
646+
}
647+
617648
/**
618649
* Gets the immutable configuration associated with this client. In most cases
619650
* it's the exact same one passed to {@link #init(ClickHouseConfig)} method for
620651
* initialization.
621652
*
622-
* @return configuration associated with this client
653+
* @return non-null configuration associated with this client
623654
*/
624655
ClickHouseConfig getConfig();
625656

@@ -650,25 +681,26 @@ default void init(ClickHouseConfig config) {
650681
}
651682

652683
/**
653-
* Tests if the given server is alive or not. Pay attention that it's a
654-
* synchronous call with minimum overhead(e.g. tiny buffer, no compression and
655-
* no deserialization etc).
684+
* Tests if the given server is alive or not. It always returns {@code false}
685+
* when server is {@code null} or timeout is less than one. Pay attention that
686+
* it's a synchronous call with minimum overhead(e.g. tiny buffer, no
687+
* compression and no deserialization etc).
656688
*
657-
* @param server server to test
658-
* @param timeout timeout in millisecond
689+
* @param server non-null server to test
690+
* @param timeout timeout in millisecond, should be greater than zero
659691
* @return true if the server is alive; false otherwise
660692
*/
661693
default boolean ping(ClickHouseNode server, int timeout) {
662-
if (server != null) {
694+
if (server != null && timeout > 0) {
663695
server = ClickHouseCluster.probe(server, timeout);
664-
665696
try (ClickHouseResponse resp = connect(server) // create request
666697
.option(ClickHouseClientOption.ASYNC, false) // use current thread
667698
.option(ClickHouseClientOption.CONNECTION_TIMEOUT, timeout)
668699
.option(ClickHouseClientOption.SOCKET_TIMEOUT, timeout)
669700
.option(ClickHouseClientOption.MAX_BUFFER_SIZE, 8) // actually 4 bytes should be enough
670701
.option(ClickHouseClientOption.MAX_QUEUED_BUFFERS, 1) // enough with only one buffer
671-
.format(ClickHouseFormat.TabSeparated).query("SELECT 1").execute()
702+
.format(ClickHouseFormat.TabSeparated)
703+
.query("SELECT 1 FORMAT TabSeparated").execute()
672704
.get(timeout, TimeUnit.MILLISECONDS)) {
673705
return true;
674706
} catch (Exception e) {

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseColumn.java

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ public final class ClickHouseColumn implements Serializable {
4242
private int arrayLevel;
4343
private ClickHouseColumn arrayBaseColumn;
4444

45+
private boolean fixedByteLength;
46+
private int estimatedByteLength;
47+
4548
private static ClickHouseColumn update(ClickHouseColumn column) {
4649
column.enumConstants = ClickHouseEnum.EMPTY;
4750
int size = column.parameters.size();
@@ -70,11 +73,17 @@ private static ClickHouseColumn update(ClickHouseColumn column) {
7073
if (size >= 2) { // same as DateTime64
7174
column.scale = Integer.parseInt(column.parameters.get(0));
7275
column.timeZone = TimeZone.getTimeZone(column.parameters.get(1).replace("'", ""));
76+
if (!column.nullable) {
77+
column.estimatedByteLength += ClickHouseDataType.DateTime64.getByteLength();
78+
}
7379
} else if (size == 1) { // same as DateTime32
7480
// unfortunately this will fall back to GMT if the time zone
7581
// cannot be resolved
7682
TimeZone tz = TimeZone.getTimeZone(column.parameters.get(0).replace("'", ""));
7783
column.timeZone = tz;
84+
if (!column.nullable) {
85+
column.estimatedByteLength += ClickHouseDataType.DateTime32.getByteLength();
86+
}
7887
}
7988
break;
8089
case DateTime32:
@@ -97,6 +106,18 @@ private static ClickHouseColumn update(ClickHouseColumn column) {
97106
if (size >= 2) {
98107
column.precision = Integer.parseInt(column.parameters.get(0));
99108
column.scale = Integer.parseInt(column.parameters.get(1));
109+
110+
if (!column.nullable) {
111+
if (column.precision > ClickHouseDataType.Decimal128.getMaxScale()) {
112+
column.estimatedByteLength += ClickHouseDataType.Decimal256.getByteLength();
113+
} else if (column.precision > ClickHouseDataType.Decimal64.getMaxScale()) {
114+
column.estimatedByteLength += ClickHouseDataType.Decimal128.getByteLength();
115+
} else if (column.precision > ClickHouseDataType.Decimal32.getMaxScale()) {
116+
column.estimatedByteLength += ClickHouseDataType.Decimal64.getByteLength();
117+
} else {
118+
column.estimatedByteLength += ClickHouseDataType.Decimal32.getByteLength();
119+
}
120+
}
100121
}
101122
break;
102123
case Decimal32:
@@ -110,6 +131,15 @@ private static ClickHouseColumn update(ClickHouseColumn column) {
110131
case FixedString:
111132
if (size > 0) {
112133
column.precision = Integer.parseInt(column.parameters.get(0));
134+
if (!column.nullable) {
135+
column.estimatedByteLength += column.precision;
136+
}
137+
}
138+
break;
139+
case String:
140+
column.fixedByteLength = false;
141+
if (!column.nullable) {
142+
column.estimatedByteLength += 1;
113143
}
114144
break;
115145
default:
@@ -129,6 +159,9 @@ protected static int readColumn(String args, int startIndex, int len, String nam
129159
boolean lowCardinality = false;
130160
int i = startIndex;
131161

162+
boolean fixedLength = true;
163+
int estimatedLength = 0;
164+
132165
if (args.startsWith(KEYWORD_LOW_CARDINALITY, i)) {
133166
lowCardinality = true;
134167
int index = args.indexOf('(', i + KEYWORD_LOW_CARDINALITY.length());
@@ -173,6 +206,8 @@ protected static int readColumn(String args, int startIndex, int len, String nam
173206
column = new ClickHouseColumn(ClickHouseDataType.valueOf(matchedKeyword), name,
174207
args.substring(startIndex, i), nullable, lowCardinality, params, nestedColumns);
175208
column.aggFuncType = aggFunc;
209+
fixedLength = false;
210+
estimatedLength++;
176211
} else if (args.startsWith(KEYWORD_ARRAY, i)) {
177212
int index = args.indexOf('(', i + KEYWORD_ARRAY.length());
178213
if (index < i) {
@@ -188,6 +223,8 @@ protected static int readColumn(String args, int startIndex, int len, String nam
188223
column = new ClickHouseColumn(ClickHouseDataType.Array, name, args.substring(startIndex, endIndex),
189224
nullable, lowCardinality, null, nestedColumns);
190225
i = endIndex;
226+
fixedLength = false;
227+
estimatedLength++;
191228
} else if (args.startsWith(KEYWORD_MAP, i)) {
192229
int index = args.indexOf('(', i + KEYWORD_MAP.length());
193230
if (index < i) {
@@ -210,6 +247,8 @@ protected static int readColumn(String args, int startIndex, int len, String nam
210247
column = new ClickHouseColumn(ClickHouseDataType.Map, name, args.substring(startIndex, endIndex), nullable,
211248
lowCardinality, null, nestedColumns);
212249
i = endIndex;
250+
fixedLength = false;
251+
estimatedLength++;
213252
} else if (args.startsWith(KEYWORD_NESTED, i)) {
214253
int index = args.indexOf('(', i + KEYWORD_NESTED.length());
215254
if (index < i) {
@@ -223,6 +262,8 @@ protected static int readColumn(String args, int startIndex, int len, String nam
223262
}
224263
column = new ClickHouseColumn(ClickHouseDataType.Nested, name, originalTypeName, nullable, lowCardinality,
225264
null, nestedColumns);
265+
fixedLength = false;
266+
estimatedLength++;
226267
} else if (args.startsWith(KEYWORD_TUPLE, i)) {
227268
int index = args.indexOf('(', i + KEYWORD_TUPLE.length());
228269
if (index < i) {
@@ -243,6 +284,12 @@ protected static int readColumn(String args, int startIndex, int len, String nam
243284
}
244285
column = new ClickHouseColumn(ClickHouseDataType.Tuple, name, args.substring(startIndex, endIndex),
245286
nullable, lowCardinality, null, nestedColumns);
287+
for (ClickHouseColumn n : nestedColumns) {
288+
estimatedLength += n.estimatedByteLength;
289+
if (!n.fixedByteLength) {
290+
fixedLength = false;
291+
}
292+
}
246293
}
247294

248295
if (column == null) {
@@ -298,6 +345,16 @@ protected static int readColumn(String args, int startIndex, int len, String nam
298345
builder.setLength(0);
299346
}
300347

348+
if (nullable) {
349+
fixedLength = false;
350+
estimatedLength++;
351+
} else if (column.dataType.getByteLength() == 0) {
352+
fixedLength = false;
353+
} else {
354+
estimatedLength += column.dataType.getByteLength();
355+
}
356+
column.fixedByteLength = fixedLength;
357+
column.estimatedByteLength = estimatedLength;
301358
list.add(update(column));
302359

303360
return i;
@@ -373,11 +430,6 @@ public static List<ClickHouseColumn> parse(String args) {
373430
return Collections.unmodifiableList(c);
374431
}
375432

376-
private ClickHouseColumn(String originalTypeName, String columnName) {
377-
this.originalTypeName = originalTypeName;
378-
this.columnName = columnName;
379-
}
380-
381433
private ClickHouseColumn(ClickHouseDataType dataType, String columnName, String originalTypeName, boolean nullable,
382434
boolean lowCardinality, List<String> parameters, List<ClickHouseColumn> nestedColumns) {
383435
this.aggFuncType = null;
@@ -403,6 +455,9 @@ private ClickHouseColumn(ClickHouseDataType dataType, String columnName, String
403455
list.addAll(nestedColumns);
404456
this.nested = Collections.unmodifiableList(list);
405457
}
458+
459+
this.fixedByteLength = false;
460+
this.estimatedByteLength = 0;
406461
}
407462

408463
public boolean isAggregateFunction() {
@@ -420,6 +475,10 @@ public boolean isEnum() {
420475
|| dataType == ClickHouseDataType.Enum16;
421476
}
422477

478+
public boolean isFixedLength() {
479+
return fixedByteLength;
480+
}
481+
423482
public boolean isMap() {
424483
return dataType == ClickHouseDataType.Map;
425484
}
@@ -448,6 +507,10 @@ public ClickHouseEnum getEnumConstants() {
448507
return enumConstants;
449508
}
450509

510+
public int getEstimatedLength() {
511+
return estimatedByteLength;
512+
}
513+
451514
public String getOriginalTypeName() {
452515
return originalTypeName;
453516
}
@@ -541,6 +604,8 @@ public int hashCode() {
541604
result = prime * result + precision;
542605
result = prime * result + scale;
543606
result = prime * result + ((timeZone == null) ? 0 : timeZone.hashCode());
607+
result = prime * result + (fixedByteLength ? 1231 : 1237);
608+
result = prime * result + estimatedByteLength;
544609
return result;
545610
}
546611

@@ -561,7 +626,8 @@ public boolean equals(Object obj) {
561626
&& Objects.equals(nested, other.nested) && nullable == other.nullable
562627
&& Objects.equals(originalTypeName, other.originalTypeName)
563628
&& Objects.equals(parameters, other.parameters) && precision == other.precision && scale == other.scale
564-
&& Objects.equals(timeZone, other.timeZone);
629+
&& Objects.equals(timeZone, other.timeZone) && fixedByteLength == other.fixedByteLength
630+
&& estimatedByteLength == other.estimatedByteLength;
565631
}
566632

567633
@Override

0 commit comments

Comments
 (0)