diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index 2644b40d8..00e801904 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -4,7 +4,6 @@ on:
pull_request_target:
branches:
- master
- - develop
types:
- opened
- synchronize
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 109932927..15e8fd27d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -34,8 +34,14 @@ jobs:
matrix:
# most recent LTS releases as well as latest stable builds
clickhouse: ["21.3", "21.8", "latest"]
+ protocol: ["http", "grpc"]
+ exclude:
+ - clickhouse: "21.3"
+ protocol: grpc
+ - clickhouse: "21.8"
+ protocol: grpc
fail-fast: false
- name: Build against ClickHouse ${{ matrix.clickhouse }}
+ name: Build against ClickHouse ${{ matrix.clickhouse }} (${{ matrix.protocol }})
steps:
- name: Check out Git repository
uses: actions/checkout@v2
@@ -82,4 +88,4 @@ jobs:
${{ runner.os }}-build-
- name: Build
run: |
- mvn --batch-mode --update-snapshots -Drelease -DclickhouseVersion=${{ matrix.clickhouse }} verify
+ mvn --batch-mode --update-snapshots -Drelease -DclickhouseVersion=${{ matrix.clickhouse }} -Dprotocol=${{ matrix.protocol }} verify
diff --git a/.github/workflows/timezone.yml b/.github/workflows/timezone.yml
index eb193d7b9..7909156a0 100644
--- a/.github/workflows/timezone.yml
+++ b/.github/workflows/timezone.yml
@@ -34,7 +34,7 @@ jobs:
serverTz: ["Asia/Chongqing", "America/Los_Angeles", "Etc/UTC", "Europe/Berlin", "Europe/Moscow"]
clientTz: ["Asia/Chongqing", "America/Los_Angeles", "Etc/UTC", "Europe/Berlin", "Europe/Moscow"]
fail-fast: false
- name: "Test TimeZones - Server: ${{ matrix.serverTz }}, Client: ${{ matrix.clientTz }}"
+ name: "TimeZone(C/S): ${{ matrix.clientTz }} vs. ${{ matrix.serverTz }}"
steps:
- name: Check out Git repository
uses: actions/checkout@v2
diff --git a/README.md b/README.md
index 6472dc75d..d4daa2f9f 100644
--- a/README.md
+++ b/README.md
@@ -99,7 +99,7 @@ Java 8 or higher is required in order to use Java client([clickhouse-client](htt
com.clickhouse
clickhouse-http-client
- 0.3.2-patch3
+ 0.3.2-patch4
```
@@ -135,7 +135,7 @@ try (ClickHouseClient client = ClickHouseClient.newInstance(preferredProtocol);
com.clickhouse
clickhouse-jdbc
- 0.3.2-patch3
+ 0.3.2-patch4
http
diff --git a/clickhouse-benchmark/pom.xml b/clickhouse-benchmark/pom.xml
index d6300ac0b..a7a13612f 100644
--- a/clickhouse-benchmark/pom.xml
+++ b/clickhouse-benchmark/pom.xml
@@ -17,9 +17,9 @@
1.4.4
- 2.6.3
+ 2.6.4
UTF-8
- 1.33
+ 1.34
benchmarks
diff --git a/clickhouse-client/README.md b/clickhouse-client/README.md
index 9f465c47e..9cdf8bf44 100644
--- a/clickhouse-client/README.md
+++ b/clickhouse-client/README.md
@@ -9,7 +9,7 @@ Async Java client for ClickHouse. `clickhouse-client` is an abstract module, so
com.clickhouse
clickhouse-http-client
- 0.3.2-patch3
+ 0.3.2-patch4
```
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClient.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClient.java
index 1a1ff15f6..322ed6e50 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClient.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClient.java
@@ -76,6 +76,8 @@ static CompletableFuture submit(Callable task) {
return (boolean) ClickHouseDefaults.ASYNC.getEffectiveDefaultValue() ? CompletableFuture.supplyAsync(() -> {
try {
return task.call();
+ } catch (ClickHouseException e) {
+ throw new CompletionException(e);
} catch (CompletionException e) {
throw e;
} catch (Exception e) {
@@ -88,6 +90,8 @@ static CompletableFuture submit(Callable task) {
throw new CompletionException(cause);
}
}, getExecutorService()) : CompletableFuture.completedFuture(task.call());
+ } catch (ClickHouseException e) {
+ throw new CompletionException(e);
} catch (CompletionException e) {
throw e;
} catch (Exception e) {
@@ -463,9 +467,9 @@ static CompletableFuture> send(ClickHouseNode se
*/
static CompletableFuture> send(ClickHouseNode server, String sql,
ClickHouseValue[] templates, Object[]... params) {
- int len = templates == null ? 0 : templates.length;
- int size = params == null ? 0 : params.length;
- if (templates == null || templates.length == 0 || params == null || params.length == 0) {
+ int len = templates != null ? templates.length : 0;
+ int size = params != null ? params.length : 0;
+ if (len == 0 || size == 0) {
throw new IllegalArgumentException("Non-empty templates and parameters are required");
}
@@ -473,7 +477,7 @@ static CompletableFuture> send(ClickHouseNode se
final ClickHouseNode theServer = ClickHouseCluster.probe(server);
return submit(() -> {
- List list = new ArrayList<>(params.length);
+ List list = new ArrayList<>(size);
// set async to false so that we don't have to create additional thread
try (ClickHouseClient client = ClickHouseClient.builder()
@@ -484,13 +488,13 @@ static CompletableFuture> send(ClickHouseNode se
for (int i = 0; i < size; i++) {
Object[] o = params[i];
String[] arr = new String[len];
- for (int j = 0, slen = o == null ? 0 : o.length; j < slen; j++) {
- if (j < len) {
- arr[j] = ClickHouseValues.NULL_EXPR;
- } else {
- ClickHouseValue v = templates[j];
+ for (int j = 0, olen = o == null ? 0 : o.length; j < len; j++) {
+ ClickHouseValue v = templates[j];
+ if (j < olen) {
arr[j] = v != null ? v.update(o[j]).toSqlExpression()
: ClickHouseValues.convertToSqlExpression(o[j]);
+ } else {
+ arr[j] = v != null ? v.resetToNullOrEmpty().toSqlExpression() : ClickHouseValues.NULL_EXPR;
}
}
try (ClickHouseResponse resp = request.params(arr).execute().get()) {
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseCluster.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseCluster.java
index d07bb05cf..48b229d81 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseCluster.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseCluster.java
@@ -5,6 +5,7 @@
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.net.Socket;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -176,7 +177,7 @@ public static ClickHouseNode probe(ClickHouseNode node, int timeout) {
client.connect(address, timeout);
client.setSoTimeout(timeout);
OutputStream out = client.getOutputStream();
- out.write("GET /ping HTTP/1.1\r\n\r\n".getBytes());
+ out.write("GET /ping HTTP/1.1\r\n\r\n".getBytes(StandardCharsets.US_ASCII));
out.flush();
byte[] buf = new byte[12]; // HTTP/1.x xxx
if (client.getInputStream().read(buf) == buf.length) {
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseRequest.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseRequest.java
index 4c75e6722..6ab9cb3da 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseRequest.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseRequest.java
@@ -1213,7 +1213,7 @@ public SelfT use(String database) {
checkSealed();
Object oldValue = options.put(ClickHouseClientOption.DATABASE,
- ClickHouseChecker.nonBlank(database, "database"));
+ ClickHouseChecker.nonNull(database, "database"));
if (oldValue == null || !oldValue.equals(database)) {
resetCache();
}
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseUtils.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseUtils.java
index 2748f2ff7..fd9639fdc 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseUtils.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseUtils.java
@@ -30,6 +30,7 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadPoolExecutor;
+import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
@@ -1066,6 +1067,91 @@ public static int readEnumValues(String args, int startIndex, int len, Map readValueArray(String args, int startIndex, int len) {
+ List list = new LinkedList<>();
+ readValueArray(args, startIndex, len, list::add);
+ return list.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(list);
+ }
+
+ public static int readValueArray(String args, int startIndex, int len, Consumer func) {
+ char closeBracket = ']';
+ StringBuilder builder = new StringBuilder();
+ for (int i = startIndex; i < len; i++) {
+ char ch = args.charAt(i);
+ if (ch == '[') {
+ startIndex = i + 1;
+ break;
+ } else if (Character.isWhitespace(ch)) {
+ continue;
+ } else if (i + 1 < len) {
+ char nextCh = args.charAt(i + 1);
+ if (ch == '-' && nextCh == '-') {
+ i = skipSingleLineComment(args, i + 2, len) - 1;
+ } else if (ch == '/' && nextCh == '*') {
+ i = skipMultiLineComment(args, i + 2, len) - 1;
+ } else {
+ startIndex = i;
+ break;
+ }
+ } else {
+ startIndex = i;
+ break;
+ }
+ }
+
+ boolean hasNext = false;
+ for (int i = startIndex; i < len; i++) {
+ char ch = args.charAt(i);
+ if (Character.isWhitespace(ch)) {
+ continue;
+ } else if (ch == '\'') { // string
+ hasNext = false;
+ int endIndex = readNameOrQuotedString(args, i, len, builder);
+ func.accept(unescape(args.substring(i, endIndex)));
+ builder.setLength(0);
+ i = endIndex + 1;
+ } else if (ch == '[') { // array
+ hasNext = false;
+ int endIndex = skipContentsUntil(args, i + 1, len, ']');
+ func.accept(args.substring(i, endIndex));
+ builder.setLength(0);
+ i = endIndex;
+ } else if (ch == '(') { // tuple
+ hasNext = false;
+ int endIndex = skipContentsUntil(args, i + 1, len, ')');
+ func.accept(args.substring(i, endIndex));
+ builder.setLength(0);
+ i = endIndex;
+ } else if (ch == closeBracket) {
+ len = i + 1;
+ break;
+ } else if (ch == ',') {
+ hasNext = true;
+ String str = builder.toString();
+ func.accept(str.isEmpty() || ClickHouseValues.NULL_EXPR.equalsIgnoreCase(str) ? null : str);
+ builder.setLength(0);
+ } else if (i + 1 < len) {
+ char nextCh = args.charAt(i + 1);
+ if (ch == '-' && nextCh == '-') {
+ i = skipSingleLineComment(args, i + 2, len) - 1;
+ } else if (ch == '/' && nextCh == '*') {
+ i = skipMultiLineComment(args, i + 2, len) - 1;
+ } else {
+ builder.append(ch);
+ }
+ } else {
+ builder.append(ch);
+ }
+ }
+
+ if (hasNext || builder.length() > 0) {
+ String str = builder.toString();
+ func.accept(str.isEmpty() || ClickHouseValues.NULL_EXPR.equalsIgnoreCase(str) ? null : str);
+ }
+
+ return len;
+ }
+
public static int readParameters(String args, int startIndex, int len, List params) {
char closeBracket = ')'; // startIndex points to the openning bracket
Deque stack = new ArrayDeque<>();
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseVersion.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseVersion.java
index d2d603480..7f24011d1 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseVersion.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseVersion.java
@@ -79,6 +79,19 @@ public static ClickHouseVersion of(String version) {
return versionCache.get(version);
}
+ /**
+ * Creates a new version object using given numbers.
+ *
+ * @param yearOrMajor year or major vrsion
+ * @param more more version numbers if any
+ * @return version
+ */
+ public static ClickHouseVersion of(int yearOrMajor, int... more) {
+ int len = more != null ? more.length : 0;
+ return new ClickHouseVersion(false, yearOrMajor, len > 0 ? more[0] : 0, len > 1 ? more[1] : 0,
+ len > 2 ? more[2] : 0);
+ }
+
/**
* Parses given version without caching.
*
@@ -460,7 +473,7 @@ public boolean check(String range) {
break;
}
- result = nextCh == ')' ? isOlderThan(v2) : isOlderOrEqualTo(v2);
+ result = nextCh == ')' ? (latest || isOlderThan(v2)) : isOlderOrEqualTo(v2);
if (!result) {
break;
}
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseLongValue.java b/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseLongValue.java
index 568ce0386..64db3e867 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseLongValue.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseLongValue.java
@@ -12,6 +12,8 @@
* Wraper class of long.
*/
public class ClickHouseLongValue implements ClickHouseValue {
+ private static final BigInteger MASK = BigInteger.ONE.shiftLeft(Long.SIZE).subtract(BigInteger.ONE);
+
/**
* Create a new instance representing null value of long.
*
@@ -135,15 +137,13 @@ public long asLong() {
public BigInteger asBigInteger() {
if (isNull) {
return null;
- } else if (!unsigned || value >= 0L) {
- return BigInteger.valueOf(value);
}
- byte[] bytes = new byte[Long.BYTES];
- for (int i = 1; i <= Long.BYTES; i++) {
- bytes[Long.BYTES - i] = (byte) ((value >>> (i * Long.BYTES)) & 0xFF);
+ BigInteger v = BigInteger.valueOf(value);
+ if (unsigned && value < 0L) {
+ v = v.and(MASK);
}
- return new BigInteger(1, bytes);
+ return v;
}
@Override
@@ -256,7 +256,7 @@ public ClickHouseLongValue update(Enum> value) {
@Override
public ClickHouseLongValue update(String value) {
- return value == null ? resetToNullOrEmpty() : set(false, unsigned, Long.parseLong(value));
+ return value == null ? resetToNullOrEmpty() : set(false, unsigned, new BigInteger(value).longValue());
}
@Override
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseByteArrayValue.java b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseByteArrayValue.java
index 611185e1a..53f8d8b6d 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseByteArrayValue.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseByteArrayValue.java
@@ -21,6 +21,7 @@
import java.util.Map.Entry;
import com.clickhouse.client.ClickHouseChecker;
+import com.clickhouse.client.ClickHouseUtils;
import com.clickhouse.client.ClickHouseValue;
import com.clickhouse.client.ClickHouseValues;
import com.clickhouse.client.data.ClickHouseObjectValue;
@@ -403,7 +404,22 @@ public ClickHouseByteArrayValue update(Map, ?> value) {
@Override
public ClickHouseByteArrayValue update(String value) {
- return set(new byte[] { Byte.parseByte(value) });
+ if (ClickHouseChecker.isNullOrBlank(value)) {
+ set(ClickHouseValues.EMPTY_BYTE_ARRAY);
+ } else {
+ List list = ClickHouseUtils.readValueArray(value, 0, value.length());
+ if (list.isEmpty()) {
+ set(ClickHouseValues.EMPTY_BYTE_ARRAY);
+ } else {
+ byte[] arr = new byte[list.size()];
+ int index = 0;
+ for (String v : list) {
+ arr[index++] = Byte.parseByte(v);
+ }
+ set(arr);
+ }
+ }
+ return this;
}
@Override
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseDoubleArrayValue.java b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseDoubleArrayValue.java
index cbba6fd80..c1f251f90 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseDoubleArrayValue.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseDoubleArrayValue.java
@@ -21,6 +21,7 @@
import java.util.Map.Entry;
import com.clickhouse.client.ClickHouseChecker;
+import com.clickhouse.client.ClickHouseUtils;
import com.clickhouse.client.ClickHouseValue;
import com.clickhouse.client.ClickHouseValues;
import com.clickhouse.client.data.ClickHouseObjectValue;
@@ -399,7 +400,22 @@ public ClickHouseDoubleArrayValue update(Map, ?> value) {
@Override
public ClickHouseDoubleArrayValue update(String value) {
- return set(new double[] { Double.parseDouble(value) });
+ if (ClickHouseChecker.isNullOrBlank(value)) {
+ set(ClickHouseValues.EMPTY_DOUBLE_ARRAY);
+ } else {
+ List list = ClickHouseUtils.readValueArray(value, 0, value.length());
+ if (list.isEmpty()) {
+ set(ClickHouseValues.EMPTY_DOUBLE_ARRAY);
+ } else {
+ double[] arr = new double[list.size()];
+ int index = 0;
+ for (String v : list) {
+ arr[index++] = Double.parseDouble(v);
+ }
+ set(arr);
+ }
+ }
+ return this;
}
@Override
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseFloatArrayValue.java b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseFloatArrayValue.java
index b608df867..468759ae1 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseFloatArrayValue.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseFloatArrayValue.java
@@ -21,6 +21,7 @@
import java.util.Map.Entry;
import com.clickhouse.client.ClickHouseChecker;
+import com.clickhouse.client.ClickHouseUtils;
import com.clickhouse.client.ClickHouseValue;
import com.clickhouse.client.ClickHouseValues;
import com.clickhouse.client.data.ClickHouseObjectValue;
@@ -399,7 +400,22 @@ public ClickHouseFloatArrayValue update(Map, ?> value) {
@Override
public ClickHouseFloatArrayValue update(String value) {
- return set(new float[] { Float.parseFloat(value) });
+ if (ClickHouseChecker.isNullOrBlank(value)) {
+ set(ClickHouseValues.EMPTY_FLOAT_ARRAY);
+ } else {
+ List list = ClickHouseUtils.readValueArray(value, 0, value.length());
+ if (list.isEmpty()) {
+ set(ClickHouseValues.EMPTY_FLOAT_ARRAY);
+ } else {
+ float[] arr = new float[list.size()];
+ int index = 0;
+ for (String v : list) {
+ arr[index++] = Float.parseFloat(v);
+ }
+ set(arr);
+ }
+ }
+ return this;
}
@Override
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseIntArrayValue.java b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseIntArrayValue.java
index 955bc42ea..4ab644e6d 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseIntArrayValue.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseIntArrayValue.java
@@ -21,6 +21,7 @@
import java.util.Map.Entry;
import com.clickhouse.client.ClickHouseChecker;
+import com.clickhouse.client.ClickHouseUtils;
import com.clickhouse.client.ClickHouseValue;
import com.clickhouse.client.ClickHouseValues;
import com.clickhouse.client.data.ClickHouseObjectValue;
@@ -399,7 +400,22 @@ public ClickHouseIntArrayValue update(Map, ?> value) {
@Override
public ClickHouseIntArrayValue update(String value) {
- return set(new int[] { Integer.parseInt(value) });
+ if (ClickHouseChecker.isNullOrBlank(value)) {
+ set(ClickHouseValues.EMPTY_INT_ARRAY);
+ } else {
+ List list = ClickHouseUtils.readValueArray(value, 0, value.length());
+ if (list.isEmpty()) {
+ set(ClickHouseValues.EMPTY_INT_ARRAY);
+ } else {
+ int[] arr = new int[list.size()];
+ int index = 0;
+ for (String v : list) {
+ arr[index++] = Integer.parseInt(v);
+ }
+ set(arr);
+ }
+ }
+ return this;
}
@Override
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseLongArrayValue.java b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseLongArrayValue.java
index 6423b25f1..1e419aa78 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseLongArrayValue.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseLongArrayValue.java
@@ -21,6 +21,7 @@
import java.util.Map.Entry;
import com.clickhouse.client.ClickHouseChecker;
+import com.clickhouse.client.ClickHouseUtils;
import com.clickhouse.client.ClickHouseValue;
import com.clickhouse.client.ClickHouseValues;
import com.clickhouse.client.data.ClickHouseObjectValue;
@@ -399,7 +400,22 @@ public ClickHouseLongArrayValue update(Map, ?> value) {
@Override
public ClickHouseLongArrayValue update(String value) {
- return set(new long[] { Long.parseLong(value) });
+ if (ClickHouseChecker.isNullOrBlank(value)) {
+ set(ClickHouseValues.EMPTY_LONG_ARRAY);
+ } else {
+ List list = ClickHouseUtils.readValueArray(value, 0, value.length());
+ if (list.isEmpty()) {
+ set(ClickHouseValues.EMPTY_LONG_ARRAY);
+ } else {
+ long[] arr = new long[list.size()];
+ int index = 0;
+ for (String v : list) {
+ arr[index++] = Long.parseLong(v);
+ }
+ set(arr);
+ }
+ }
+ return this;
}
@Override
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseShortArrayValue.java b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseShortArrayValue.java
index 4daa591d4..9907124ef 100644
--- a/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseShortArrayValue.java
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/data/array/ClickHouseShortArrayValue.java
@@ -21,6 +21,7 @@
import java.util.Map.Entry;
import com.clickhouse.client.ClickHouseChecker;
+import com.clickhouse.client.ClickHouseUtils;
import com.clickhouse.client.ClickHouseValue;
import com.clickhouse.client.ClickHouseValues;
import com.clickhouse.client.data.ClickHouseObjectValue;
@@ -399,7 +400,22 @@ public ClickHouseShortArrayValue update(Map, ?> value) {
@Override
public ClickHouseShortArrayValue update(String value) {
- return set(new short[] { Short.parseShort(value) });
+ if (ClickHouseChecker.isNullOrBlank(value)) {
+ set(ClickHouseValues.EMPTY_SHORT_ARRAY);
+ } else {
+ List list = ClickHouseUtils.readValueArray(value, 0, value.length());
+ if (list.isEmpty()) {
+ set(ClickHouseValues.EMPTY_SHORT_ARRAY);
+ } else {
+ short[] arr = new short[list.size()];
+ int index = 0;
+ for (String v : list) {
+ arr[index++] = Short.parseShort(v);
+ }
+ set(arr);
+ }
+ }
+ return this;
}
@Override
diff --git a/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseClusterTest.java b/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseClusterTest.java
index ae478f332..712fb6630 100644
--- a/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseClusterTest.java
+++ b/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseClusterTest.java
@@ -105,8 +105,11 @@ public void testProbe() {
// FIXME does not support ClickHouseProtocol.POSTGRESQL for now
ClickHouseProtocol[] protocols = new ClickHouseProtocol[] { ClickHouseProtocol.GRPC, ClickHouseProtocol.HTTP,
ClickHouseProtocol.MYSQL, ClickHouseProtocol.TCP };
-
+ ClickHouseVersion serverVersion = ClickHouseVersion.of(System.getProperty("clickhouseVersion", "latest"));
for (ClickHouseProtocol p : protocols) {
+ if (p == ClickHouseProtocol.GRPC && !serverVersion.check("[21.1,)")) {
+ continue;
+ }
ClickHouseNode node = getServer(ClickHouseProtocol.ANY, p.getDefaultPort());
ClickHouseNode probedNode = ClickHouseCluster.probe(node);
Assert.assertNotEquals(probedNode, node);
diff --git a/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseUtilsTest.java b/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseUtilsTest.java
index bd99ba504..0d9ca12a9 100644
--- a/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseUtilsTest.java
+++ b/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseUtilsTest.java
@@ -34,7 +34,8 @@ public void testGetKeyValuePair() {
Assert.assertEquals(ClickHouseUtils.getKeyValuePairs(",,"), Collections.emptyMap());
Assert.assertEquals(ClickHouseUtils.getKeyValuePairs("=,"), Collections.emptyMap());
Assert.assertEquals(ClickHouseUtils.getKeyValuePairs(" =\r ,"), Collections.emptyMap());
- Assert.assertEquals(ClickHouseUtils.getKeyValuePairs("a\\=='b c',"), Collections.singletonMap("a=", "'b c'"));
+ Assert.assertEquals(ClickHouseUtils.getKeyValuePairs("a\\=='b c',"),
+ Collections.singletonMap("a=", "'b c'"));
Assert.assertEquals(ClickHouseUtils.getKeyValuePairs("User-Agent=New Client, X-Forward-For=1\\,2"),
new HashMap() {
{
@@ -53,7 +54,8 @@ public void testGetLeadingComment() {
Assert.assertEquals(ClickHouseUtils.getLeadingComment("-- a \r\nselect 1"), "a");
Assert.assertEquals(ClickHouseUtils.getLeadingComment(" -- a \r\n-- b\nselect 1"), "a");
Assert.assertEquals(ClickHouseUtils.getLeadingComment("/* a */select 1"), "a");
- Assert.assertEquals(ClickHouseUtils.getLeadingComment(" /* a /* b */*/ /*-- b*/\nselect 1"), "a /* b */");
+ Assert.assertEquals(ClickHouseUtils.getLeadingComment(" /* a /* b */*/ /*-- b*/\nselect 1"),
+ "a /* b */");
Assert.assertEquals(ClickHouseUtils.getLeadingComment("select /* a */1"), "");
}
@@ -113,11 +115,14 @@ public void testSkipBrackets() {
Assert.assertEquals(ClickHouseUtils.skipBrackets(newArgs, 0, newArgs.length(), '('), newArgs.length());
Assert.assertEquals(ClickHouseUtils.skipBrackets(newArgs = "))", 0, newArgs.length(), '('),
newArgs.lastIndexOf(')'));
- Assert.assertEquals(ClickHouseUtils.skipBrackets(newArgs = ")]", 0, newArgs.length(), '['), newArgs.length());
- Assert.assertEquals(ClickHouseUtils.skipBrackets(newArgs = "{}", 0, newArgs.length(), '{'), newArgs.length());
+ Assert.assertEquals(ClickHouseUtils.skipBrackets(newArgs = ")]", 0, newArgs.length(), '['),
+ newArgs.length());
+ Assert.assertEquals(ClickHouseUtils.skipBrackets(newArgs = "{}", 0, newArgs.length(), '{'),
+ newArgs.length());
Assert.assertEquals(ClickHouseUtils.skipBrackets(newArgs = "{ '''\\'}'}", 0, newArgs.length(), '{'),
newArgs.length());
- Assert.assertEquals(ClickHouseUtils.skipBrackets(newArgs = "{ -- }\n/*/*}*/*/}", 0, newArgs.length(), '{'),
+ Assert.assertEquals(
+ ClickHouseUtils.skipBrackets(newArgs = "{ -- }\n/*/*}*/*/}", 0, newArgs.length(), '{'),
newArgs.length());
}
@@ -133,19 +138,24 @@ public void testSkipQuotedString() {
Assert.assertEquals(ClickHouseUtils.skipQuotedString(args, 2, args.length(), '\''), args.length());
String newArgs = "''''";
- Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs, 0, newArgs.length(), '\''), newArgs.length());
+ Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs, 0, newArgs.length(), '\''),
+ newArgs.length());
Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs = "''''''", 0, newArgs.length(), '\''),
newArgs.length());
Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs = "'\\''''", 0, newArgs.length(), '\''),
newArgs.length());
- Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.skipQuotedString("", 0, 0, '\''));
- Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.skipQuotedString("'", 0, 1, '\''));
+ Assert.assertThrows(IllegalArgumentException.class,
+ () -> ClickHouseUtils.skipQuotedString("", 0, 0, '\''));
+ Assert.assertThrows(IllegalArgumentException.class,
+ () -> ClickHouseUtils.skipQuotedString("'", 0, 1, '\''));
Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs = "''", 0, newArgs.length(), '\''),
newArgs.length());
Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs = " '''\\'}'", 0, newArgs.length(), '\''),
newArgs.indexOf('\\'));
- Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs, 1, newArgs.length(), '\''), newArgs.length());
- Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs, 1, newArgs.length(), '\''), newArgs.length());
+ Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs, 1, newArgs.length(), '\''),
+ newArgs.length());
+ Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs, 1, newArgs.length(), '\''),
+ newArgs.length());
Assert.assertEquals(ClickHouseUtils.skipQuotedString(newArgs = "'\\\\'''", 0, newArgs.length(), '\''),
newArgs.length());
}
@@ -153,7 +163,8 @@ public void testSkipQuotedString() {
@Test(groups = { "unit" })
public void testSkipSingleLineComment() {
String args = "select 1 -- select one\n union all select 2 -- select two--";
- Assert.assertEquals(ClickHouseUtils.skipSingleLineComment(args, 11, args.length()), args.indexOf('\n') + 1);
+ Assert.assertEquals(ClickHouseUtils.skipSingleLineComment(args, 11, args.length()),
+ args.indexOf('\n') + 1);
Assert.assertEquals(ClickHouseUtils.skipSingleLineComment(args, args.indexOf("--", 11), args.length()),
args.length());
}
@@ -161,23 +172,29 @@ public void testSkipSingleLineComment() {
@Test(groups = { "unit" })
public void testSkipMultipleLineComment() {
String args = "select 1 /* select 1/*one*/ -- a */, 2";
- Assert.assertEquals(ClickHouseUtils.skipMultiLineComment(args, 11, args.length()), args.lastIndexOf("*/") + 2);
- Assert.assertEquals(ClickHouseUtils.skipMultiLineComment(args, 21, args.length()), args.indexOf("*/", 21) + 2);
+ Assert.assertEquals(ClickHouseUtils.skipMultiLineComment(args, 11, args.length()),
+ args.lastIndexOf("*/") + 2);
+ Assert.assertEquals(ClickHouseUtils.skipMultiLineComment(args, 21, args.length()),
+ args.indexOf("*/", 21) + 2);
Assert.assertThrows(IllegalArgumentException.class,
- () -> ClickHouseUtils.skipMultiLineComment(args, args.lastIndexOf("*/") + 1, args.length()));
+ () -> ClickHouseUtils.skipMultiLineComment(args, args.lastIndexOf("*/") + 1,
+ args.length()));
}
@Test(groups = { "unit" })
public void testSkipContentsUntilCharacters() {
String args = "select 'a' as `--b`,1/*('1(/*'*/(\0*/ \0from number(10)";
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length()), args.lastIndexOf('\0') + 1);
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), '('), args.lastIndexOf('(') + 1);
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length()),
+ args.lastIndexOf('\0') + 1);
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), '('),
+ args.lastIndexOf('(') + 1);
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), '(', 'n'),
args.lastIndexOf('n') + 1);
args = "column1 AggregateFunction(quantiles(0.5, 0.9), UInt64),\ncolumn2 UInt8 not null";
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length()), args.length());
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), ','), args.lastIndexOf(',') + 1);
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), ','),
+ args.lastIndexOf(',') + 1);
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), '@'), args.length());
}
@@ -188,28 +205,38 @@ public void testSkipContentsUntilKeyword() {
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), (String) null, false), 1);
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "", true), 1);
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "", false), 1);
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "SELECT", true), args.length());
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "SELECT", true),
+ args.length());
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "SELECT", false),
args.indexOf(' '));
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "'", true), args.indexOf('a'));
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "'", false), args.indexOf('a'));
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "From", true), args.length());
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "'", true),
+ args.indexOf('a'));
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "'", false),
+ args.indexOf('a'));
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "From", true),
+ args.length());
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "From", false),
args.lastIndexOf("from") + 4);
args = "with (SELECT 1 as a) abcb -- select\nselect abcd";
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "SELECT", true), args.length());
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "SELECT", true),
+ args.length());
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "SELECT", false),
args.lastIndexOf(' '));
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "abcd", true), args.length());
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "abcd", false), args.length());
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "abcd", true),
+ args.length());
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "abcd", false),
+ args.length());
Assert.assertEquals(ClickHouseUtils.skipContentsUntil("abcd", 0, args.length(), "abcd", true), 4);
Assert.assertEquals(ClickHouseUtils.skipContentsUntil("abcd", 0, args.length(), "abcd", false), 4);
args = "column1 AggregateFunction(quantiles(0.5, 0.9), UInt64),\ncolumn2 UInt64 not null";
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "uint128", true), args.length());
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "uint128", false), args.length());
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "uint64", true), args.length());
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "uint128", true),
+ args.length());
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "uint128", false),
+ args.length());
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "uint64", true),
+ args.length());
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), "uint64", false),
args.lastIndexOf("UInt64") + 6);
}
@@ -217,45 +244,66 @@ public void testSkipContentsUntilKeyword() {
@Test(groups = { "unit" })
public void testSkipContentsUntilKeywords() {
String args = "select 1 Insert, 2 as into";
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), (String[]) null, true), 1);
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), (String[]) null, false), 1);
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), (String[]) null, true),
+ 1);
+ Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), (String[]) null, false),
+ 1);
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[0], true), 1);
Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[0], false), 1);
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { null }, true), 1);
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { null }, false), 1);
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "" }, true), 1);
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "" }, false), 1);
+ Assert.assertEquals(
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { null }, true),
+ 1);
+ Assert.assertEquals(
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { null }, false),
+ 1);
+ Assert.assertEquals(
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "" }, true),
+ 1);
+ Assert.assertEquals(
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "" }, false),
+ 1);
Assert.assertEquals(
- ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "1", "insert" }, true),
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(),
+ new String[] { "1", "insert" }, true),
args.length());
Assert.assertEquals(
- ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "1", "insert" }, false),
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(),
+ new String[] { "1", "insert" }, false),
args.indexOf(','));
Assert.assertEquals(
- ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { " ", "insert" }, true),
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(),
+ new String[] { " ", "insert" }, true),
args.length());
Assert.assertEquals(
- ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { " ", "insert" }, false),
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(),
+ new String[] { " ", "insert" }, false),
args.length());
- Assert.assertEquals(ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "1", null }, true),
+ Assert.assertEquals(
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "1", null },
+ true),
args.indexOf('I'));
Assert.assertEquals(
- ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "1", null }, false),
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "1", null },
+ false),
args.indexOf('I'));
args = "insert Into db.table(c1, c2) select d2, d3 From input('d1 String, d2 UInt8, d3 Array(UInt16)')";
Assert.assertEquals(
- ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "insert", "into" }, true),
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(),
+ new String[] { "insert", "into" }, true),
args.length());
Assert.assertEquals(
- ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "insert", "into" }, false),
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(),
+ new String[] { "insert", "into" }, false),
args.indexOf('d') - 1);
Assert.assertEquals(
- ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "from", "input" }, true),
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(),
+ new String[] { "from", "input" }, true),
args.length());
Assert.assertEquals(
- ClickHouseUtils.skipContentsUntil(args, 0, args.length(), new String[] { "from", "input" }, false),
+ ClickHouseUtils.skipContentsUntil(args, 0, args.length(),
+ new String[] { "from", "input" }, false),
args.indexOf('\'') - 1);
}
@@ -263,7 +311,8 @@ public void testSkipContentsUntilKeywords() {
public void testReadNameOrQuotedString() {
String args = "123";
StringBuilder builder = new StringBuilder();
- Assert.assertEquals(ClickHouseUtils.readNameOrQuotedString(args, 0, args.length(), builder), args.length());
+ Assert.assertEquals(ClickHouseUtils.readNameOrQuotedString(args, 0, args.length(), builder),
+ args.length());
Assert.assertEquals(builder.toString(), args);
builder.setLength(0);
@@ -272,7 +321,9 @@ public void testReadNameOrQuotedString() {
Assert.assertEquals(builder.toString(), "123");
builder.setLength(0);
- Assert.assertEquals(ClickHouseUtils.readNameOrQuotedString(args = " `1\"'2``3` ", 1, args.length(), builder),
+ Assert.assertEquals(
+ ClickHouseUtils.readNameOrQuotedString(args = " `1\"'2``3` ", 1, args.length(),
+ builder),
args.lastIndexOf('`') + 1);
Assert.assertEquals(builder.toString(), "1\"'2`3");
@@ -290,7 +341,8 @@ public void testReadNameOrQuotedString() {
public void testReadEnumValues() {
String args = "Enum( ' `''1\" ' = 1, '\\''=2 )";
Map values = new HashMap<>();
- Assert.assertEquals(ClickHouseUtils.readEnumValues(args, 5, args.length(), values), args.lastIndexOf(')') + 1);
+ Assert.assertEquals(ClickHouseUtils.readEnumValues(args, 5, args.length(), values),
+ args.lastIndexOf(')') + 1);
Assert.assertEquals(values.size(), 2);
Assert.assertEquals(values.get(" `'1\" "), (Integer) 1);
Assert.assertEquals(values.get("'"), (Integer) 2);
@@ -309,11 +361,51 @@ public void testReadEnumValues() {
args = "a Enum('1)'=2), b UInt8";
values.clear();
- Assert.assertEquals(ClickHouseUtils.readEnumValues(args, 7, args.length(), values), args.lastIndexOf(','));
+ Assert.assertEquals(ClickHouseUtils.readEnumValues(args, 7, args.length(), values),
+ args.lastIndexOf(','));
Assert.assertEquals(values.size(), 1);
Assert.assertEquals(values.get("1)"), (Integer) 2);
}
+ @Test(groups = { "unit" })
+ public void testReadValueArray() {
+ String args = " [1, 2, 3 ] ";
+ List list = new LinkedList<>();
+ Assert.assertEquals(ClickHouseUtils.readValueArray(args, args.indexOf('['), args.length(), list::add),
+ args.lastIndexOf(']') + 1);
+ Assert.assertEquals(list, Arrays.asList("1", "2", "3"));
+
+ args = "['1\\'2', '2,3' , '3\n4\r5']";
+ list.clear();
+ Assert.assertEquals(ClickHouseUtils.readValueArray(args, 0, args.length(), list::add), args.length());
+ Assert.assertEquals(list, Arrays.asList("1'2", "2,3", "3\n4\r5"));
+
+ args = "[[1,2,3],[],(),(4,5,6)]";
+ list.clear();
+ Assert.assertEquals(ClickHouseUtils.readValueArray(args, 0, args.length(), list::add), args.length());
+ Assert.assertEquals(list, Arrays.asList("[1,2,3]", "[]", "()", "(4,5,6)"));
+
+ args = "[,null,nan,-inf,,123,]";
+ list.clear();
+ Assert.assertEquals(ClickHouseUtils.readValueArray(args, 0, args.length(), list::add), args.length());
+ Assert.assertEquals(list, Arrays.asList(null, null, "nan", "-inf", null, "123", null));
+
+ args = "1";
+ list.clear();
+ Assert.assertEquals(ClickHouseUtils.readValueArray(args, 0, args.length(), list::add), args.length());
+ Assert.assertEquals(list, Arrays.asList("1"));
+
+ args = "";
+ list.clear();
+ Assert.assertEquals(ClickHouseUtils.readValueArray(args, 0, args.length(), list::add), 0);
+ Assert.assertEquals(list, Collections.emptyList());
+
+ args = " [ ] ]";
+ list.clear();
+ Assert.assertEquals(ClickHouseUtils.readValueArray(args, 0, args.length(), list::add), args.indexOf(']') + 1);
+ Assert.assertEquals(list, Collections.emptyList());
+ }
+
@Test(groups = { "unit" })
public void testReadParameters() {
String args = "column1 AggregateFunction( quantiles(0.5, 'c \\'''([1],2) d',0.9) , UInt64),\ncolumn2 UInt8 not null";
diff --git a/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseVersionTest.java b/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseVersionTest.java
index a35d983f2..cd164943e 100644
--- a/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseVersionTest.java
+++ b/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseVersionTest.java
@@ -132,6 +132,12 @@ public void testCheckRange() {
Assert.assertTrue(ClickHouseVersion.parseVersion("21.3").check("[21.3,21.4)"));
Assert.assertTrue(ClickHouseVersion.parseVersion("21.8.8.29").check("[18.16,)"));
+
+ Assert.assertFalse(ClickHouseVersion.of("").check("[18.16,)"));
+ Assert.assertTrue(ClickHouseVersion.of("latest").check("[18.16,)"));
+
+ Assert.assertTrue(ClickHouseVersion.of("latest").check("(,)"));
+ Assert.assertTrue(ClickHouseVersion.of("latest").check("[,)"));
}
@Test(groups = { "unit" })
diff --git a/clickhouse-client/src/test/java/com/clickhouse/client/ClientIntegrationTest.java b/clickhouse-client/src/test/java/com/clickhouse/client/ClientIntegrationTest.java
new file mode 100644
index 000000000..2589bcf27
--- /dev/null
+++ b/clickhouse-client/src/test/java/com/clickhouse/client/ClientIntegrationTest.java
@@ -0,0 +1,951 @@
+package com.clickhouse.client;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+
+import com.clickhouse.client.config.ClickHouseClientOption;
+import com.clickhouse.client.data.ClickHouseBigDecimalValue;
+import com.clickhouse.client.data.ClickHouseBigIntegerValue;
+import com.clickhouse.client.data.ClickHouseDateTimeValue;
+import com.clickhouse.client.data.ClickHouseExternalTable;
+import com.clickhouse.client.data.ClickHouseIntegerValue;
+import com.clickhouse.client.data.ClickHouseIpv4Value;
+import com.clickhouse.client.data.ClickHouseIpv6Value;
+import com.clickhouse.client.data.ClickHouseLongValue;
+import com.clickhouse.client.data.ClickHouseStringValue;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public abstract class ClientIntegrationTest extends BaseIntegrationTest {
+ protected ClickHouseResponseSummary execute(ClickHouseRequest> request, String sql) throws Exception {
+ try (ClickHouseResponse response = request.query(sql).execute().get()) {
+ for (ClickHouseRecord record : response.records()) {
+ for (ClickHouseValue value : record) {
+ Assert.assertNotNull(value, "Value should never be null");
+ }
+ }
+
+ return response.getSummary();
+ }
+ }
+
+ protected abstract ClickHouseProtocol getProtocol();
+
+ protected abstract Class extends ClickHouseClient> getClientClass();
+
+ protected ClickHouseClient getClient() {
+ return ClickHouseClient.newInstance(getProtocol());
+ }
+
+ protected ClickHouseNode getServer() {
+ return getServer(getProtocol());
+ }
+
+ @DataProvider(name = "compressionMatrix")
+ protected Object[][] getCompressionMatrix() {
+ return new Object[][] {
+ new Object[] { false, false },
+ new Object[] { true, false },
+ new Object[] { true, true },
+ new Object[] { false, true } };
+ }
+
+ @DataProvider(name = "simpleTypeProvider")
+ protected Object[][] getSimpleTypes() {
+ return new Object[][] {
+ { ClickHouseDataType.Enum.name() + "('v-1' = -1, 'v0' = 0, 'v+1' = 1)", "v0", "v-1", "v+1" },
+ { ClickHouseDataType.Enum8.name() + "('v-1' = -1, 'v0' = 0, 'v+1' = 1)", "v0", "v-1", "v+1" },
+ { ClickHouseDataType.Enum16.name() + "('v-1' = -1, 'v0' = 0, 'v+1' = 1)", "v0", "v-1", "v+1" },
+ { ClickHouseDataType.Int8.name(), "0", "-1", "1" },
+ { ClickHouseDataType.UInt8.name(), "0", "255", "1" },
+ { ClickHouseDataType.Int16.name(), "0", "-1", "1" },
+ { ClickHouseDataType.UInt16.name(), "0", "65535", "1" },
+ { ClickHouseDataType.Int32.name(), "0", "-1", "1" },
+ { ClickHouseDataType.UInt32.name(), "0", "4294967295", "1" },
+ { ClickHouseDataType.Int64.name(), "0", "-1", "1" },
+ { ClickHouseDataType.UInt64.name(), "0", "18446744073709551615", "1" },
+ { ClickHouseDataType.Int128.name(), "0", "-1", "1" },
+ { ClickHouseDataType.UInt128.name(), "0", "340282366920938463463374607431768211455", "1" },
+ { ClickHouseDataType.Int256.name(), "0", "-1", "1" },
+ { ClickHouseDataType.UInt256.name(), "0",
+ "115792089237316195423570985008687907853269984665640564039457584007913129639935", "1" },
+ { ClickHouseDataType.Float32.name(), "0.0", "-1.0", "1.0" },
+ { ClickHouseDataType.Float64.name(), "0.0", "-1.0", "1.0" },
+ { ClickHouseDataType.Date.name(), "1970-01-01", "1970-01-01", "1970-01-02" },
+ { ClickHouseDataType.Date32.name(), "1970-01-01", "1969-12-31", "1970-01-02" },
+ { ClickHouseDataType.DateTime.name(), "1970-01-01 00:00:00", "1970-01-01 00:00:00",
+ "1970-01-01 00:00:01" },
+ { ClickHouseDataType.DateTime32.name(), "1970-01-01 00:00:00", "1970-01-01 00:00:00",
+ "1970-01-01 00:00:01" },
+ { ClickHouseDataType.DateTime64.name() + "(3)", "1970-01-01 00:00:00", "1969-12-31 23:59:59.999",
+ "1970-01-01 00:00:00.001" },
+ { ClickHouseDataType.Decimal.name() + "(10,9)", "0E-9", "-1.000000000", "1.000000000" },
+ { ClickHouseDataType.Decimal32.name() + "(1)", "0.0", "-1.0", "1.0" },
+ { ClickHouseDataType.Decimal64.name() + "(3)", "0.000", "-1.000", "1.000" },
+ { ClickHouseDataType.Decimal128.name() + "(5)", "0.00000", "-1.00000", "1.00000" },
+ { ClickHouseDataType.Decimal256.name() + "(7)", "0E-7", "-1.0000000", "1.0000000" },
+ { ClickHouseDataType.FixedString.name() + "(3)", "0\0\0", "-1\0", "1\0\0" },
+ { ClickHouseDataType.String.name(), "0", "-1", "1" },
+ { ClickHouseDataType.UUID.name(), "00000000-0000-0000-0000-000000000000",
+ "00000000-0000-0000-ffff-ffffffffffff", "00000000-0000-0000-0000-000000000001" } };
+ }
+
+ @Test(groups = { "unit" })
+ public void testInitialization() throws Exception {
+ Assert.assertNotNull(getProtocol(), "The client should support a non-null protocol");
+ Assert.assertNotEquals(getProtocol(), ClickHouseProtocol.ANY,
+ "The client should support a specific protocol instead of ANY");
+
+ try (ClickHouseClient client1 = ClickHouseClient.builder().build();
+ ClickHouseClient client2 = ClickHouseClient.builder().option(ClickHouseClientOption.ASYNC, false)
+ .build();
+ ClickHouseClient client3 = ClickHouseClient.newInstance();
+ ClickHouseClient client4 = ClickHouseClient.newInstance(getProtocol());
+ ClickHouseClient client5 = getClient()) {
+ for (ClickHouseClient client : new ClickHouseClient[] { client1, client2, client3, client4, client5 }) {
+ Assert.assertEquals(client.getClass(), getClientClass());
+ Assert.assertTrue(client.accept(getProtocol()), "The client should support protocl: " + getProtocol());
+ }
+ }
+ }
+
+ @Test(groups = { "integration" })
+ public void testOpenCloseClient() throws Exception {
+ int count = 100;
+ int timeout = 3000;
+ ClickHouseNode server = getServer();
+ for (int i = 0; i < count; i++) {
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse response = client.connect(server).query("select 1").execute().get()) {
+ Assert.assertEquals(response.firstRecord().getValue(0).asInteger(), 1);
+ }
+ Assert.assertTrue(getClient().ping(server, timeout));
+ }
+ }
+
+ @Test(dataProvider = "compressionMatrix", groups = { "integration" })
+ public void testCompression(boolean compressRequest, boolean compressResponse) throws Exception {
+ ClickHouseNode server = getServer();
+ String uuid = UUID.randomUUID().toString();
+ try (ClickHouseClient client = getClient()) {
+ ClickHouseRequest> request = client.connect(server).format(ClickHouseFormat.RowBinaryWithNamesAndTypes);
+ boolean hasResult = false;
+ try (ClickHouseResponse resp = request
+ .compressServerResponse(compressResponse)
+ .decompressClientRequest(compressRequest)
+ .query("select :uuid").params(ClickHouseStringValue.of(uuid)).execute().get()) {
+ Assert.assertEquals(resp.firstRecord().getValue(0).asString(), uuid);
+ hasResult = true;
+ }
+ Assert.assertTrue(hasResult, "Should have at least one result");
+ }
+ }
+
+ @Test(groups = { "integration" })
+ public void testFormat() throws Exception {
+ String sql = "select 1, 2";
+ ClickHouseNode node = getServer();
+
+ try (ClickHouseClient client = getClient()) {
+ try (ClickHouseResponse response = client.connect(node)
+ .format(ClickHouseFormat.RowBinaryWithNamesAndTypes).query(sql).execute().get()) {
+ Assert.assertEquals(response.getColumns().size(), 2);
+ int counter = 0;
+ for (ClickHouseRecord record : response.records()) {
+ Assert.assertEquals(record.getValue(0).asShort(), 1);
+ Assert.assertEquals(record.getValue(1).asShort(), 2);
+ counter++;
+ }
+ Assert.assertEquals(counter, 1);
+ }
+
+ // now let's try again using unsupported formats
+ try (ClickHouseResponse response = client.connect(node).query(sql).format(ClickHouseFormat.CSV).execute()
+ .get()) {
+ String results = new BufferedReader(
+ new InputStreamReader(response.getInputStream(), StandardCharsets.UTF_8)).lines()
+ .collect(Collectors.joining("\n"));
+ Assert.assertEquals(results, "1,2");
+ }
+
+ try (ClickHouseResponse response = client.connect(node).query(sql).format(ClickHouseFormat.JSONEachRow)
+ .execute().get()) {
+ String results = new BufferedReader(
+ new InputStreamReader(response.getInputStream(), StandardCharsets.UTF_8)).lines()
+ .collect(Collectors.joining("\n"));
+ Assert.assertEquals(results, "{\"1\":1,\"2\":2}");
+ }
+ }
+ }
+
+ @Test(groups = "integration")
+ public void testNonExistDb() throws Exception {
+ ClickHouseNode server = getServer();
+
+ try {
+ ClickHouseClient.send(server, "drop database non_exist_db").get();
+ Assert.fail("Exception is excepted");
+ } catch (ExecutionException e) {
+ ClickHouseException ce = ClickHouseException.of(e.getCause(), server);
+ Assert.assertEquals(ce.getErrorCode(), 81);
+ }
+
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).use("non_exist_db").query("select 1").execute()
+ .get()) {
+ Assert.fail("Exception is excepted");
+ } catch (ExecutionException e) {
+ ClickHouseException ce = ClickHouseException.of(e.getCause(), server);
+ Assert.assertEquals(ce.getErrorCode(), 81);
+ }
+
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).use("").query("select 1").execute().get()) {
+ Assert.assertEquals(resp.firstRecord().getValue(0).asInteger(), 1);
+ } catch (Exception e) {
+ Assert.fail("Should not have exception");
+ }
+
+ try (ClickHouseClient client = getClient()) {
+ String db = new StringBuilder().append('`').append(UUID.randomUUID().toString()).append('`').toString();
+ try (ClickHouseResponse resp = client.connect(server).use("").query("create database " + db).execute()
+ .get()) {
+ }
+ try (ClickHouseResponse resp = client.connect(server).use("").query("drop database " + db).execute()
+ .get()) {
+ }
+ } catch (Exception e) {
+ Assert.fail("Should not have exception");
+ }
+ }
+
+ @Test(groups = { "integration" })
+ public void testQueryWithNoResult() throws Exception {
+ String sql = "select * from system.numbers limit 0";
+
+ try (ClickHouseClient client = getClient()) {
+ // header without row
+ try (ClickHouseResponse response = client.connect(getServer())
+ .format(ClickHouseFormat.RowBinaryWithNamesAndTypes).query(sql).execute().get()) {
+ Assert.assertEquals(response.getColumns().size(), 1);
+ Assert.assertNotEquals(response.getColumns(), ClickHouseDataProcessor.DEFAULT_COLUMNS);
+ for (ClickHouseRecord record : response.records()) {
+ Assert.fail(ClickHouseUtils.format("Should have no record, but we got: %s", record));
+ }
+ }
+
+ // no header and row
+ try (ClickHouseResponse response = client.connect(getServer()).format(ClickHouseFormat.RowBinary).query(sql)
+ .execute().get()) {
+ Assert.assertEquals(response.getColumns(), Collections.emptyList());
+ for (ClickHouseRecord record : response.records()) {
+ Assert.fail(ClickHouseUtils.format("Should have no record, but we got: %s", record));
+ }
+ }
+
+ // custom header and row
+ try (ClickHouseResponse response = client.connect(getServer()).format(ClickHouseFormat.RowBinary).query(sql)
+ .execute().get()) {
+ Assert.assertEquals(response.getColumns(), Collections.emptyList());
+ for (ClickHouseRecord record : response.records()) {
+ Assert.fail(ClickHouseUtils.format("Should have no record, but we got: %s", record));
+ }
+ }
+ }
+ }
+
+ @Test(groups = { "integration" })
+ public void testQuery() throws Exception {
+ ClickHouseNode server = getServer();
+
+ try (ClickHouseClient client = getClient()) {
+ // "select * from system.data_type_families"
+ int limit = 10000;
+ String sql = "select number, toString(number) from system.numbers limit " + limit;
+
+ try (ClickHouseResponse response = client.connect(server)
+ .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
+ .set("send_logs_level", "trace")
+ .set("enable_optimize_predicate_expression", 1)
+ .set("log_queries_min_type", "EXCEPTION_WHILE_PROCESSING")
+ .query(sql).execute().get()) {
+ List columns = response.getColumns();
+ int index = 0;
+ for (ClickHouseRecord record : response.records()) {
+ String col1 = String.valueOf(record.getValue(0).asBigInteger());
+ String col2 = record.getValue(1).asString();
+ Assert.assertEquals(record.size(), columns.size());
+ Assert.assertEquals(col1, col2);
+ Assert.assertEquals(col1, String.valueOf(index++));
+ }
+
+ // int counter = 0;
+ // for (ClickHouseValue value : response.values()) {
+ // Assert.assertEquals(value.asString(), String.valueOf(index));
+ // index += counter++ % 2;
+ // }
+ Assert.assertEquals(index, limit);
+ // Thread.sleep(30000);
+ /*
+ * while (response.hasError()) { int index = 0; for (ClickHouseColumn c :
+ * columns) { // RawValue v = response.getRawValue(index++); // String v =
+ * response.getValue(index++, String.class) }
+ *
+ * } byte[] bytes = in.readAllBytes(); String str = new String(bytes);
+ */
+ } catch (Exception e) {
+ Assert.fail("Query failed", e);
+ }
+ }
+ }
+
+ @Test(groups = "integration")
+ public void testQueryInSameThread() throws Exception {
+ ClickHouseNode server = getServer();
+
+ try (ClickHouseClient client = ClickHouseClient.builder().option(ClickHouseClientOption.ASYNC, false).build()) {
+ CompletableFuture future = client.connect(server)
+ .format(ClickHouseFormat.TabSeparatedWithNamesAndTypes).query("select 1,2").execute();
+ // Assert.assertTrue(future instanceof ClickHouseImmediateFuture);
+ Assert.assertTrue(future.isDone());
+ try (ClickHouseResponse resp = future.get()) {
+ Assert.assertEquals(resp.getColumns().size(), 2);
+ for (ClickHouseRecord record : resp.records()) {
+ Assert.assertEquals(record.size(), 2);
+ Assert.assertEquals(record.getValue(0).asInteger(), 1);
+ Assert.assertEquals(record.getValue(1).asInteger(), 2);
+ }
+
+ // ClickHouseResponseSummary summary = resp.getSummary();
+ // Assert.assertEquals(summary.getStatistics().getRows(), 1);
+ }
+ }
+ }
+
+ @Test(groups = { "integration" })
+ public void testMutation() throws Exception {
+ ClickHouseNode node = getServer();
+
+ try (ClickHouseClient client = getClient()) {
+ ClickHouseRequest> request = client.connect(node)
+ .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
+ .set("send_logs_level", "trace")
+ .set("enable_optimize_predicate_expression", 1)
+ .set("log_queries_min_type", "EXCEPTION_WHILE_PROCESSING");
+ execute(request, "drop table if exists test_mutation;");
+ execute(request, "create table if not exists test_mutation(a String, b UInt32) engine = Memory;");
+ execute(request, "insert into test_mutation values('a', 1)('b', 2)");
+ }
+ }
+
+ @Test(groups = "integration")
+ public void testQueryIntervalTypes() throws Exception {
+ ClickHouseNode server = getServer();
+
+ try (ClickHouseClient client = getClient()) {
+ for (ClickHouseDataType type : new ClickHouseDataType[] { ClickHouseDataType.IntervalYear,
+ ClickHouseDataType.IntervalQuarter, ClickHouseDataType.IntervalMonth,
+ ClickHouseDataType.IntervalWeek, ClickHouseDataType.IntervalDay, ClickHouseDataType.IntervalHour,
+ ClickHouseDataType.IntervalMinute, ClickHouseDataType.IntervalSecond }) {
+ try (ClickHouseResponse resp = client.connect(server)
+ .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
+ .query(ClickHouseUtils.format(
+ "select to%1$s(0), to%1$s(-1), to%1$s(1), to%1$s(%2$d), to%1$s(%3$d)", type.name(),
+ Long.MIN_VALUE, Long.MAX_VALUE))
+ .execute().get()) {
+ List records = new ArrayList<>();
+ for (ClickHouseRecord record : resp.records()) {
+ records.add(record);
+ }
+
+ Assert.assertEquals(records.size(), 1);
+ ClickHouseRecord r = records.get(0);
+ Assert.assertEquals(r.getValue(0).asString(), "0");
+ Assert.assertEquals(r.getValue(1).asString(), "-1");
+ Assert.assertEquals(r.getValue(2).asString(), "1");
+ Assert.assertEquals(r.getValue(3).asString(), String.valueOf(Long.MIN_VALUE));
+ Assert.assertEquals(r.getValue(4).asString(), String.valueOf(Long.MAX_VALUE));
+ }
+ }
+ }
+ }
+
+ @Test(groups = "integration")
+ public void testReadWriteDateTimeTypes() throws Exception {
+ ClickHouseNode server = getServer();
+
+ ClickHouseClient.send(server, "drop table if exists test_datetime_types",
+ "create table test_datetime_types(no UInt8, d0 DateTime32, d1 DateTime64(5), d2 DateTime(3)) engine=Memory")
+ .get();
+ ClickHouseClient.send(server, "insert into test_datetime_types values(:no, :d0, :d1, :d2)",
+ new ClickHouseValue[] { ClickHouseIntegerValue.ofNull(),
+ ClickHouseDateTimeValue.ofNull(0, ClickHouseValues.UTC_TIMEZONE),
+ ClickHouseDateTimeValue.ofNull(3, ClickHouseValues.UTC_TIMEZONE),
+ ClickHouseDateTimeValue.ofNull(9, ClickHouseValues.UTC_TIMEZONE) },
+ new Object[] { 0, "1970-01-01 00:00:00", "1970-01-01 00:00:00.123456",
+ "1970-01-01 00:00:00.123456789" },
+ new Object[] { 1, -1, -1, -1 }, new Object[] { 2, 1, 1, 1 }, new Object[] { 3, 2.1, 2.1, 2.1 }).get();
+
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
+ .query("select * except(no) from test_datetime_types order by no").execute().get()) {
+ List list = new ArrayList<>();
+ for (ClickHouseRecord record : resp.records()) {
+ list.add(record);
+ }
+
+ Assert.assertEquals(list.size(), 4);
+ }
+ }
+
+ @Test(groups = "integration")
+ public void testReadWriteDomains() throws Exception {
+ ClickHouseNode server = getServer();
+
+ ClickHouseClient.send(server, "drop table if exists test_domain_types",
+ "create table test_domain_types(no UInt8, ipv4 IPv4, nipv4 Nullable(IPv4), ipv6 IPv6, nipv6 Nullable(IPv6)) engine=Memory")
+ .get();
+
+ ClickHouseClient.send(server, "insert into test_domain_types values(:no, :i0, :i1, :i2, :i3)",
+ new ClickHouseValue[] { ClickHouseIntegerValue.ofNull(), ClickHouseIpv4Value.ofNull(),
+ ClickHouseIpv4Value.ofNull(), ClickHouseIpv6Value.ofNull(), ClickHouseIpv6Value.ofNull() },
+ new Object[] { 0,
+ (Inet4Address) InetAddress.getByAddress(new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0 }),
+ null,
+ Inet6Address.getByAddress(null,
+ new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+ (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+ (byte) 0 },
+ null),
+ null },
+ new Object[] { 1,
+ (Inet4Address) InetAddress.getByAddress(new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 1 }),
+ (Inet4Address) InetAddress
+ .getByAddress(new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF }),
+ Inet6Address.getByAddress(null,
+ new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+ (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+ (byte) 1 },
+ null),
+ Inet6Address.getByAddress(null,
+ new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF },
+ null) })
+ .get();
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
+ .query("select * except(no) from test_domain_types order by no").execute().get()) {
+ List list = new ArrayList<>();
+ for (ClickHouseRecord record : resp.records()) {
+ list.add(record);
+ }
+
+ Assert.assertEquals(list.size(), 2);
+ }
+ }
+
+ @Test(groups = "integration")
+ public void testReadWriteGeoTypes() throws Exception {
+ ClickHouseNode server = getServer();
+
+ ClickHouseClient.send(server, "set allow_experimental_geo_types=1", "drop table if exists test_geo_types",
+ "create table test_geo_types(no UInt8, p Point, r Ring, pg Polygon, mp MultiPolygon) engine=Memory")
+ .get();
+
+ // write
+ ClickHouseClient.send(server,
+ "insert into test_geo_types values(0, (0,0), " + "[(0,0),(0,0)], [[(0,0),(0,0)],[(0,0),(0,0)]], "
+ + "[[[(0,0),(0,0)],[(0,0),(0,0)]],[[(0,0),(0,0)],[(0,0),(0,0)]]])",
+ "insert into test_geo_types values(1, (-1,-1), "
+ + "[(-1,-1),(-1,-1)], [[(-1,-1),(-1,-1)],[(-1,-1),(-1,-1)]], "
+ + "[[[(-1,-1),(-1,-1)],[(-1,-1),(-1,-1)]],[[(-1,-1),(-1,-1)],[(-1,-1),(-1,-1)]]])",
+ "insert into test_geo_types values(2, (1,1), " + "[(1,1),(1,1)], [[(1,1),(1,1)],[(1,1),(1,1)]], "
+ + "[[[(1,1),(1,1)],[(1,1),(1,1)]],[[(1,1),(1,1)],[(1,1),(1,1)]]])")
+ .get();
+
+ // read
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
+ .query("select * except(no) from test_geo_types order by no").execute().get()) {
+ List records = new ArrayList<>();
+ for (ClickHouseRecord record : resp.records()) {
+ String[] values = new String[record.size()];
+ int index = 0;
+ for (ClickHouseValue v : record) {
+ values[index++] = v.asString();
+ }
+ records.add(values);
+ }
+
+ Assert.assertEquals(records.size(), 3);
+ Assert.assertEquals(records.get(0)[0], "(0.0,0.0)");
+ Assert.assertEquals(records.get(0)[1], "[(0.0,0.0),(0.0,0.0)]");
+ Assert.assertEquals(records.get(0)[2], "[[(0.0,0.0),(0.0,0.0)],[(0.0,0.0),(0.0,0.0)]]");
+ Assert.assertEquals(records.get(0)[3],
+ "[[[(0.0,0.0),(0.0,0.0)],[(0.0,0.0),(0.0,0.0)]],[[(0.0,0.0),(0.0,0.0)],[(0.0,0.0),(0.0,0.0)]]]");
+ Assert.assertEquals(records.get(1)[0], "(-1.0,-1.0)");
+ Assert.assertEquals(records.get(1)[1], "[(-1.0,-1.0),(-1.0,-1.0)]");
+ Assert.assertEquals(records.get(1)[2], "[[(-1.0,-1.0),(-1.0,-1.0)],[(-1.0,-1.0),(-1.0,-1.0)]]");
+ Assert.assertEquals(records.get(1)[3],
+ "[[[(-1.0,-1.0),(-1.0,-1.0)],[(-1.0,-1.0),(-1.0,-1.0)]],[[(-1.0,-1.0),(-1.0,-1.0)],[(-1.0,-1.0),(-1.0,-1.0)]]]");
+ Assert.assertEquals(records.get(2)[0], "(1.0,1.0)");
+ Assert.assertEquals(records.get(2)[1], "[(1.0,1.0),(1.0,1.0)]");
+ Assert.assertEquals(records.get(2)[2], "[[(1.0,1.0),(1.0,1.0)],[(1.0,1.0),(1.0,1.0)]]");
+ Assert.assertEquals(records.get(2)[3],
+ "[[[(1.0,1.0),(1.0,1.0)],[(1.0,1.0),(1.0,1.0)]],[[(1.0,1.0),(1.0,1.0)],[(1.0,1.0),(1.0,1.0)]]]");
+ }
+ }
+
+ @Test(dataProvider = "simpleTypeProvider", groups = "integration")
+ public void testReadWriteSimpleTypes(String dataType, String zero, String negativeOne, String positiveOne)
+ throws Exception {
+ ClickHouseNode server = getServer();
+
+ String typeName = dataType;
+ String columnName = typeName.toLowerCase();
+ int currIdx = columnName.indexOf('(');
+ if (currIdx > 0) {
+ columnName = columnName.substring(0, currIdx);
+ }
+ String dropTemplate = "drop table if exists test_%s";
+ String createTemplate = "create table test_%1$s(no UInt8, %1$s %2$s, n%1$s Nullable(%2$s)) engine=Memory";
+ String insertTemplate = "insert into table test_%s values(%s, %s, %s)";
+
+ String negativeOneValue = "-1";
+ String zeroValue = "0";
+ String positiveOneValue = "1";
+ if (dataType.startsWith(ClickHouseDataType.FixedString.name())) {
+ negativeOneValue = "'-1'";
+ zeroValue = "'0'";
+ positiveOneValue = "'1'";
+ } else if (dataType.startsWith(ClickHouseDataType.UUID.name())) {
+ negativeOneValue = ClickHouseUtils.format("'%s'", ClickHouseIntegerValue.of(-1).asUuid());
+ zeroValue = ClickHouseUtils.format("'%s'", ClickHouseIntegerValue.of(0).asUuid());
+ positiveOneValue = ClickHouseUtils.format("'%s'", ClickHouseIntegerValue.of(1).asUuid());
+ }
+
+ try {
+ ClickHouseClient
+ .send(server, ClickHouseUtils.format(dropTemplate, columnName),
+ ClickHouseUtils.format(createTemplate, columnName, typeName),
+ ClickHouseUtils.format(insertTemplate, columnName, 0, zeroValue, null),
+ ClickHouseUtils.format(insertTemplate, columnName, 1, zeroValue, zeroValue),
+ ClickHouseUtils.format(insertTemplate, columnName, 2, negativeOneValue, negativeOneValue),
+ ClickHouseUtils.format(insertTemplate, columnName, 3, positiveOneValue, positiveOneValue))
+ .get();
+ } catch (ExecutionException e) {
+ // maybe the type is just not supported, for example: Date32
+ Throwable cause = e.getCause();
+ Assert.assertTrue(cause instanceof ClickHouseException);
+ return;
+ }
+
+ ClickHouseVersion version = null;
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client
+ .connect(server).format(ClickHouseFormat.RowBinaryWithNamesAndTypes).query(ClickHouseUtils
+ .format("select * except(no), version() from test_%s order by no", columnName))
+ .execute().get()) {
+ List records = new ArrayList<>();
+ for (ClickHouseRecord record : resp.records()) {
+ String[] values = new String[record.size()];
+ int index = 0;
+ for (ClickHouseValue v : record) {
+ values[index++] = v.asString();
+ }
+ records.add(values);
+ }
+
+ Assert.assertEquals(records.size(), 4);
+ Assert.assertEquals(records.get(0)[0], zero);
+ Assert.assertEquals(records.get(0)[1], null);
+ if (version == null) {
+ version = ClickHouseVersion.of(records.get(0)[2]);
+ }
+
+ Assert.assertEquals(records.get(1)[0], zero);
+ Assert.assertEquals(records.get(1)[1], zero);
+ Assert.assertEquals(records.get(3)[0], positiveOne);
+ Assert.assertEquals(records.get(3)[1], positiveOne);
+
+ if ((ClickHouseDataType.DateTime.name().equals(dataType)
+ || ClickHouseDataType.DateTime32.name().equals(dataType)) && version.getMajorVersion() == 21
+ && version.getMinorVersion() == 3) {
+ // skip DateTime and DateTime32 negative test on 21.3 since it's not doing well
+ // see https://github.com/ClickHouse/ClickHouse/issues/29835 for more
+ } else {
+ Assert.assertEquals(records.get(2)[0], negativeOne);
+ Assert.assertEquals(records.get(2)[1], negativeOne);
+ }
+ }
+ }
+
+ @Test(groups = "integration")
+ public void testReadWriteMap() throws Exception {
+ ClickHouseNode server = getServer();
+
+ try {
+ ClickHouseClient
+ .send(server, "drop table if exists test_map_types",
+ "create table test_map_types(no UInt32, m Map(LowCardinality(String), Int32))engine=Memory")
+ .get();
+ } catch (ExecutionException e) {
+ // looks like LowCardinality(String) as key is not supported even in 21.8
+ Throwable cause = e.getCause();
+ Assert.assertTrue(cause instanceof ClickHouseException);
+ return;
+ }
+
+ // write
+ ClickHouseClient.send(server, "insert into test_map_types values (1, {'key1' : 1})").get();
+ ClickHouseClient.send(server, "insert into test_map_types values (:n,:m)",
+ new String[][] { new String[] { "-1", "{'key-1' : -1}" }, new String[] { "-2", "{'key-2' : -2}" } })
+ .get();
+ ClickHouseClient.send(server, "insert into test_map_types values (3, :m)",
+ Collections.singletonMap("m", "{'key3' : 3}")).get();
+
+ // read
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
+ .query("select * except(no) from test_map_types order by no").execute().get()) {
+ List records = new ArrayList<>();
+ for (ClickHouseRecord record : resp.records()) {
+ String[] values = new String[record.size()];
+ int index = 0;
+ for (ClickHouseValue v : record) {
+ values[index++] = v.asString();
+ }
+ records.add(values);
+ }
+
+ Assert.assertEquals(records.size(), 4);
+ }
+ }
+
+ @Test(groups = "integration")
+ public void testReadWriteUInt64() throws Exception {
+ ClickHouseNode server = getServer();
+
+ // INSERT INTO test_table VALUES (10223372036854775100)
+ ClickHouseClient.send(server, "drop table if exists test_uint64_values",
+ "create table test_uint64_values(no UInt8, v0 UInt64, v1 UInt64, v2 UInt64, v3 UInt64) engine=Memory")
+ .get();
+ ClickHouseClient.send(server, "insert into test_uint64_values values(:no, :v0, :v1, :v2, :v3)",
+ new ClickHouseValue[] { ClickHouseIntegerValue.ofNull(),
+ ClickHouseLongValue.ofNull(true), ClickHouseStringValue.ofNull(),
+ ClickHouseBigIntegerValue.ofNull(), ClickHouseBigDecimalValue.ofNull() },
+ new Object[] { 0, 0L, "0", BigInteger.ZERO, BigDecimal.ZERO },
+ new Object[] { 1, 1L, "1", BigInteger.ONE, BigDecimal.ONE },
+ new Object[] { 2, Long.MAX_VALUE, Long.toString(Long.MAX_VALUE), BigInteger.valueOf(Long.MAX_VALUE),
+ BigDecimal.valueOf(Long.MAX_VALUE) },
+ new Object[] { 3, -8223372036854776516L, "10223372036854775100", new BigInteger("10223372036854775100"),
+ new BigDecimal("10223372036854775100") })
+ .get();
+
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
+ .query("select * except(no) from test_uint64_values order by no").execute().get()) {
+ int count = 0;
+ for (ClickHouseRecord r : resp.records()) {
+ if (count == 0) {
+ Assert.assertEquals(r.getValue(0).asLong(), 0L);
+ Assert.assertEquals(r.getValue(1).asLong(), 0L);
+ Assert.assertEquals(r.getValue(2).asLong(), 0L);
+ Assert.assertEquals(r.getValue(3).asLong(), 0L);
+ } else if (count == 1) {
+ Assert.assertEquals(r.getValue(0).asLong(), 1L);
+ Assert.assertEquals(r.getValue(1).asLong(), 1L);
+ Assert.assertEquals(r.getValue(2).asLong(), 1L);
+ Assert.assertEquals(r.getValue(3).asLong(), 1L);
+ } else if (count == 2) {
+ Assert.assertEquals(r.getValue(0).asLong(), Long.MAX_VALUE);
+ Assert.assertEquals(r.getValue(1).asLong(), Long.MAX_VALUE);
+ Assert.assertEquals(r.getValue(2).asLong(), Long.MAX_VALUE);
+ Assert.assertEquals(r.getValue(3).asLong(), Long.MAX_VALUE);
+ } else if (count == 3) {
+ Assert.assertEquals(r.getValue(0).asString(), "10223372036854775100");
+ Assert.assertEquals(r.getValue(1).asBigInteger(), new BigInteger("10223372036854775100"));
+ Assert.assertEquals(r.getValue(2).asBigDecimal(), new BigDecimal("10223372036854775100"));
+ Assert.assertEquals(r.getValue(3).asLong(), -8223372036854776516L);
+ }
+ count++;
+ }
+
+ Assert.assertEquals(count, 4);
+ }
+ }
+
+ @Test(groups = "integration")
+ public void testQueryWithMultipleExternalTables() throws Exception {
+ ClickHouseNode server = getServer();
+
+ int tables = 30;
+ int rows = 10;
+ try (ClickHouseClient client = getClient()) {
+ try (ClickHouseResponse resp = client.connect(server).query("drop table if exists test_ext_data_query")
+ .execute().get()) {
+ }
+
+ String ddl = "create table test_ext_data_query (\n" + " Cb String,\n" + " CREATETIME DateTime64(3),\n"
+ + " TIMESTAMP UInt64,\n" + " Cc String,\n" + " Ca1 UInt64,\n" + " Ca2 UInt64,\n"
+ + " Ca3 UInt64\n" + ") engine = MergeTree()\n" + "PARTITION BY toYYYYMMDD(CREATETIME)\n"
+ + "ORDER BY (Cb, CREATETIME, Cc);";
+ try (ClickHouseResponse resp = client.connect(server).query(ddl).execute().get()) {
+ }
+ }
+
+ String template = "avgIf(Ca1, Cb in L%1$d) as avgCa1%2$d, sumIf(Ca1, Cb in L%1$d) as sumCa1%2$d, minIf(Ca1, Cb in L%1$d) as minCa1%2$d, maxIf(Ca1, Cb in L%1$d) as maxCa1%2$d, anyIf(Ca1, Cb in L%1$d) as anyCa1%2$d, avgIf(Ca2, Cb in L%1$d) as avgCa2%2$d, sumIf(Ca2, Cb in L%1$d) as sumCa2%2$d, minIf(Ca2, Cb in L%1$d) as minCa2%2$d, maxIf(Ca2, Cb in L%1$d) as maxCa2%2$d, anyIf(Ca2, Cb in L%1$d) as anyCa2%2$d, avgIf(Ca3, Cb in L%1$d) as avgCa3%2$d, sumIf(Ca3, Cb in L%1$d) as sumCa3%2$d, minIf(Ca3, Cb in L%1$d) as minCa3%2$d, maxIf(Ca3, Cb in L%1$d) as maxCa3%2$d, anyIf(Ca3, Cb in L%1$d) as anyCa3%2$d";
+ StringBuilder sql = new StringBuilder().append("select ");
+ List extTableList = new ArrayList<>(tables);
+ for (int i = 0; i < tables; i++) {
+ sql.append(ClickHouseUtils.format(template, i, i + 1)).append(',');
+ List valueList = new ArrayList<>(rows);
+ for (int j = i, size = i + rows; j < size; j++) {
+ valueList.add(String.valueOf(j));
+ }
+ String dnExtString = String.join("\n", valueList);
+ InputStream inputStream = new ByteArrayInputStream(dnExtString.getBytes(StandardCharsets.UTF_8));
+ ClickHouseExternalTable extTable = ClickHouseExternalTable.builder().name("L" + i).content(inputStream)
+ .addColumn("Cb", "String").build();
+ extTableList.add(extTable);
+ }
+
+ if (tables > 0) {
+ sql.deleteCharAt(sql.length() - 1);
+ } else {
+ sql.append('*');
+ }
+ sql.append(
+ " from test_ext_data_query where TIMESTAMP >= 1625796480 and TIMESTAMP < 1625796540 and Cc = 'eth0'");
+
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).query(sql.toString())
+ .format(ClickHouseFormat.RowBinaryWithNamesAndTypes).external(extTableList).execute().get()) {
+ Assert.assertNotNull(resp.getColumns());
+ Assert.assertTrue(tables <= 0 || resp.records().iterator().hasNext());
+ }
+ }
+
+ @Test(groups = { "integration" })
+ public void testDump() throws Exception {
+ ClickHouseNode server = getServer();
+
+ Path temp = Files.createTempFile("dump", ".tsv");
+ Assert.assertEquals(Files.size(temp), 0L);
+
+ int lines = 10000;
+ ClickHouseResponseSummary summary = ClickHouseClient.dump(server, "select * from system.numbers limit " + lines,
+ ClickHouseFormat.TabSeparated, ClickHouseCompression.NONE, temp.toString()).get();
+ Assert.assertNotNull(summary);
+ // Assert.assertEquals(summary.getReadRows(), lines);
+
+ int counter = 0;
+ for (String line : Files.readAllLines(temp)) {
+ Assert.assertEquals(String.valueOf(counter++), line);
+ }
+ Assert.assertEquals(counter, lines);
+
+ Files.delete(temp);
+ }
+
+ @Test(groups = { "integration" })
+ public void testCustomLoad() throws Exception {
+ ClickHouseNode server = getServer();
+
+ ClickHouseClient.send(server, "drop table if exists test_custom_load",
+ "create table test_custom_load(n UInt32, s Nullable(String)) engine = Memory").get();
+
+ ClickHouseClient.load(server, "test_custom_load", ClickHouseFormat.TabSeparated,
+ ClickHouseCompression.NONE, new ClickHouseWriter() {
+ @Override
+ public void write(OutputStream output) throws IOException {
+ output.write("1\t\\N\n".getBytes(StandardCharsets.US_ASCII));
+ output.write("2\t123".getBytes(StandardCharsets.US_ASCII));
+ }
+ }).get();
+
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).query("select * from test_custom_load order by n")
+ .format(ClickHouseFormat.RowBinaryWithNamesAndTypes).execute().get()) {
+ Assert.assertNotNull(resp.getColumns());
+ List values = new ArrayList<>();
+ for (ClickHouseRecord record : resp.records()) {
+ String[] arr = new String[2];
+ arr[0] = record.getValue(0).asString();
+ arr[1] = record.getValue(1).asString();
+ values.add(arr);
+ }
+
+ Assert.assertEquals(values.size(), 2);
+ Assert.assertEquals(values.get(0), new String[] { "1", null });
+ Assert.assertEquals(values.get(1), new String[] { "2", "123" });
+ }
+ }
+
+ @Test(groups = { "integration" })
+ public void testLoadCsv() throws Exception {
+ ClickHouseNode server = getServer();
+
+ List summaries = ClickHouseClient
+ .send(server, "drop table if exists test_load_csv",
+ "create table test_load_csv(n UInt32) engine = Memory")
+ .get();
+ Assert.assertNotNull(summaries);
+ Assert.assertEquals(summaries.size(), 2);
+
+ Path temp = Files.createTempFile("data", ".tsv");
+ Assert.assertEquals(Files.size(temp), 0L);
+
+ int lines = 10000;
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < lines; i++) {
+ builder.append(i).append('\n');
+ }
+ Files.write(temp, builder.toString().getBytes(StandardCharsets.US_ASCII));
+ Assert.assertTrue(Files.size(temp) > 0L);
+
+ ClickHouseResponseSummary summary = ClickHouseClient.load(server, "test_load_csv",
+ ClickHouseFormat.TabSeparated, ClickHouseCompression.NONE, temp.toString()).get();
+ Assert.assertNotNull(summary);
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).query("select count(1) from test_load_csv").execute()
+ .get()) {
+ Assert.assertEquals(resp.firstRecord().getValue(0).asInteger(), lines);
+ }
+
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server)
+ .query("select min(n), max(n), count(1), uniqExact(n) from test_load_csv")
+ .format(ClickHouseFormat.RowBinaryWithNamesAndTypes).execute().get()) {
+ Assert.assertNotNull(resp.getColumns());
+ for (ClickHouseRecord record : resp.records()) {
+ Assert.assertNotNull(record);
+ Assert.assertEquals(record.getValue(0).asLong(), 0L);
+ Assert.assertEquals(record.getValue(1).asLong(), lines - 1);
+ Assert.assertEquals(record.getValue(2).asLong(), lines);
+ Assert.assertEquals(record.getValue(3).asLong(), lines);
+ }
+ } finally {
+ Files.delete(temp);
+ }
+ }
+
+ @Test(groups = { "integration" })
+ public void testMultipleQueries() throws Exception {
+ ClickHouseNode server = getServer();
+ try (ClickHouseClient client = getClient()) {
+ ClickHouseRequest> req = client.connect(server).format(ClickHouseFormat.RowBinaryWithNamesAndTypes);
+
+ int result1 = 1;
+ int result2 = 2;
+ ClickHouseResponse queryResp = req.copy().query("select 1").execute().get();
+
+ try (ClickHouseResponse resp = req.copy().query("select 2").execute().get()) {
+ Assert.assertEquals(resp.firstRecord().getValue(0).asInteger(), result2);
+ }
+
+ result2 = 0;
+ for (ClickHouseRecord r : queryResp.records()) {
+ Assert.assertEquals(r.getValue(0).asInteger(), result1);
+ result2++;
+ }
+ Assert.assertEquals(result2, 1, "Should have only one record");
+ }
+ }
+
+ @Test(groups = { "integration" })
+ public void testExternalTableAsParameter() throws Exception {
+ ClickHouseNode server = getServer();
+ try (ClickHouseClient client = getClient();
+ ClickHouseResponse resp = client.connect(server).format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
+ .query("select toString(number) as query_id from numbers(100) "
+ + "where query_id not in (select query_id from ext_table) limit 10")
+ .external(ClickHouseExternalTable.builder().name("ext_table")
+ .columns("query_id String, a_num Nullable(Int32)").format(ClickHouseFormat.CSV)
+ .content(new ByteArrayInputStream(
+ "\"1,2,3\",\\N\n2,333".getBytes(StandardCharsets.US_ASCII)))
+ .build())
+ .execute().get()) {
+ for (ClickHouseRecord r : resp.records()) {
+ Assert.assertNotNull(r);
+ }
+ }
+ }
+
+ @Test(groups = { "integration" })
+ public void testInsertWithInputFunction() throws Exception {
+ ClickHouseNode server = getServer();
+ ClickHouseClient.send(server, "drop table if exists test_input_function",
+ "create table test_input_function(name String, value Nullable(Int32))engine=Memory").get();
+
+ try (ClickHouseClient client = getClient()) {
+ // default format ClickHouseFormat.TabSeparated
+ ClickHouseRequest> req = client.connect(server);
+ try (ClickHouseResponse resp = req.write().query(
+ "insert into test_input_function select col2, col3 from "
+ + "input('col1 UInt8, col2 String, col3 Int32')")
+ .data(new ByteArrayInputStream("1\t2\t33\n2\t3\t333".getBytes(StandardCharsets.US_ASCII))).execute()
+ .get()) {
+
+ }
+
+ List