Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on:
pull_request_target:
branches:
- master
- develop
types:
- opened
- synchronize
Expand Down
10 changes: 8 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion .github/workflows/timezone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Java 8 or higher is required in order to use Java client([clickhouse-client](htt
<groupId>com.clickhouse</groupId>
<!-- or clickhouse-grpc-client if you prefer gRPC -->
<artifactId>clickhouse-http-client</artifactId>
<version>0.3.2-patch3</version>
<version>0.3.2-patch4</version>
</dependency>
```

Expand Down Expand Up @@ -135,7 +135,7 @@ try (ClickHouseClient client = ClickHouseClient.newInstance(preferredProtocol);
<!-- will stop using ru.yandex.clickhouse starting from 0.4.0 -->
<groupId>com.clickhouse</groupId>
<artifactId>clickhouse-jdbc</artifactId>
<version>0.3.2-patch3</version>
<version>0.3.2-patch4</version>
<!-- below is only needed when all you want is a shaded jar -->
<classifier>http</classifier>
<exclusions>
Expand Down
4 changes: 2 additions & 2 deletions clickhouse-benchmark/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

<properties>
<clickhouse4j-driver.version>1.4.4</clickhouse4j-driver.version>
<native-driver.version>2.6.3</native-driver.version>
<native-driver.version>2.6.4</native-driver.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jmh.version>1.33</jmh.version>
<jmh.version>1.34</jmh.version>
<shade.name>benchmarks</shade.name>
</properties>

Expand Down
2 changes: 1 addition & 1 deletion clickhouse-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Async Java client for ClickHouse. `clickhouse-client` is an abstract module, so
<dependency>
<groupId>com.clickhouse</groupId>
<artifactId>clickhouse-http-client</artifactId>
<version>0.3.2-patch3</version>
<version>0.3.2-patch4</version>
</dependency>
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ static <T> CompletableFuture<T> submit(Callable<T> 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) {
Expand All @@ -88,6 +90,8 @@ static <T> CompletableFuture<T> submit(Callable<T> 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) {
Expand Down Expand Up @@ -463,17 +467,17 @@ static CompletableFuture<List<ClickHouseResponseSummary>> send(ClickHouseNode se
*/
static CompletableFuture<List<ClickHouseResponseSummary>> 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");
}

// in case the protocol is ANY
final ClickHouseNode theServer = ClickHouseCluster.probe(server);

return submit(() -> {
List<ClickHouseResponseSummary> list = new ArrayList<>(params.length);
List<ClickHouseResponseSummary> list = new ArrayList<>(size);

// set async to false so that we don't have to create additional thread
try (ClickHouseClient client = ClickHouseClient.builder()
Expand All @@ -484,13 +488,13 @@ static CompletableFuture<List<ClickHouseResponseSummary>> 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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -1066,6 +1067,91 @@ public static int readEnumValues(String args, int startIndex, int len, Map<Strin
return len;
}

public static List<String> readValueArray(String args, int startIndex, int len) {
List<String> 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<String> 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<String> params) {
char closeBracket = ')'; // startIndex points to the openning bracket
Deque<Character> stack = new ArrayDeque<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> 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
Expand Down
Loading