diff --git a/README.md b/README.md index 47924005c..fda038360 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 + 0.3.2-patch1 ``` @@ -135,7 +135,7 @@ try (ClickHouseClient client = ClickHouseClient.newInstance(preferredProtocol); com.clickhouse clickhouse-jdbc - 0.3.2 + 0.3.2-patch1 http diff --git a/clickhouse-client/README.md b/clickhouse-client/README.md index ca9912ba1..3e62dfab4 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 + 0.3.2-patch1 ``` diff --git a/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseGrpcClient.java b/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseGrpcClient.java index a3ae241cd..5e526261a 100644 --- a/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseGrpcClient.java +++ b/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseGrpcClient.java @@ -245,8 +245,9 @@ protected CompletableFuture executeAsync(ClickHouseRequest { - int timeout = sealedRequest.getConfig().getConnectionTimeout() / 1000 - + sealedRequest.getConfig().getMaxExecutionTime(); + ClickHouseConfig config = sealedRequest.getConfig(); + int timeout = config.getConnectionTimeout() / 1000 + + Math.max(config.getSocketTimeout() / 1000, config.getMaxExecutionTime()); try { if (!responseObserver.await(timeout, TimeUnit.SECONDS)) { if (!Context.current().withCancellation().cancel(new StatusException(Status.CANCELLED))) { diff --git a/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseGrpcFuture.java b/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseGrpcFuture.java index 5bc0346c6..4c6f47050 100644 --- a/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseGrpcFuture.java +++ b/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseGrpcFuture.java @@ -10,6 +10,7 @@ import io.grpc.StatusException; import io.grpc.stub.StreamObserver; import com.clickhouse.client.ClickHouseChecker; +import com.clickhouse.client.ClickHouseConfig; import com.clickhouse.client.ClickHouseNode; import com.clickhouse.client.ClickHouseRequest; import com.clickhouse.client.ClickHouseResponse; @@ -63,7 +64,10 @@ public boolean isDone() { @Override public ClickHouseResponse get() throws InterruptedException, ExecutionException { try { - return get(request.getConfig().getConnectionTimeout() / 1000 + request.getConfig().getMaxExecutionTime(), + ClickHouseConfig config = request.getConfig(); + return get( + config.getConnectionTimeout() / 1000 + + Math.max(config.getSocketTimeout() / 1000, config.getMaxExecutionTime()), TimeUnit.SECONDS); } catch (TimeoutException e) { cancel(true); diff --git a/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseStreamObserver.java b/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseStreamObserver.java index 930940fb4..a52554f57 100644 --- a/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseStreamObserver.java +++ b/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/ClickHouseStreamObserver.java @@ -64,7 +64,7 @@ protected void setError(Throwable error) { protected boolean updateStatus(Result result) { summary.update(); - log.info(() -> { + log.debug(() -> { for (LogEntry e : result.getLogsList()) { String logLevel = e.getLevel().name(); int index = logLevel.indexOf('_'); diff --git a/clickhouse-jdbc/README.md b/clickhouse-jdbc/README.md index 4060f7c19..d2a671f7e 100644 --- a/clickhouse-jdbc/README.md +++ b/clickhouse-jdbc/README.md @@ -11,7 +11,7 @@ Keep in mind that `clickhouse-jdbc` is synchronous, and in general it has more o com.clickhouse clickhouse-jdbc - 0.3.2 + 0.3.2-patch1 ``` diff --git a/examples/grpc/pom.xml b/examples/grpc/pom.xml new file mode 100644 index 000000000..8dfa5f37f --- /dev/null +++ b/examples/grpc/pom.xml @@ -0,0 +1,99 @@ + + + 4.0.0 + + com.clickhouse + grpc-examples + 1.0.0 + jar + + grpc-examples + gRPC Examples + https://github.com/ClickHouse/clickhouse-jdbc + 2022 + + + ClickHouse, Inc. + https://clickhouse.com/ + + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + repo + + + + + + zhicwu + Zhichun Wu + zhicwu@gmail.com + +8 + + + + + https://github.com/ClickHouse/clickhouse-jdbc + scm:git@github.com:ClickHouse/clickhouse-jdbc.git + scm:git@github.com:ClickHouse/clickhouse-jdbc.git + HEAD + + + + Github + https://github.com/ClickHouse/clickhouse-jdbc/issues + + + + Github + https://github.com/ClickHouse/clickhouse-jdbc/actions + + + + 2022 + UTF-8 + UTF-8 + + 0.3.2 + + 3.8.1 + + 1.8 + + + + + com.clickhouse + clickhouse-grpc-client + ${clickhouse-grpc.version} + shaded + + + * + * + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${compiler-plugin.version} + + ${minJdk} + ${minJdk} + true + + -Xlint:all + + + + + + + \ No newline at end of file diff --git a/examples/grpc/src/main/java/com/clickhouse/examples/jdbc/Main.java b/examples/grpc/src/main/java/com/clickhouse/examples/jdbc/Main.java new file mode 100644 index 000000000..a4ccd43b4 --- /dev/null +++ b/examples/grpc/src/main/java/com/clickhouse/examples/jdbc/Main.java @@ -0,0 +1,108 @@ +package com.clickhouse.examples.jdbc; + +import java.io.IOException; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import com.clickhouse.client.ClickHouseClient; +import com.clickhouse.client.ClickHouseConfig; +import com.clickhouse.client.ClickHouseCredentials; +import com.clickhouse.client.ClickHouseException; +import com.clickhouse.client.ClickHouseFormat; +import com.clickhouse.client.ClickHouseNode; +import com.clickhouse.client.ClickHouseProtocol; +import com.clickhouse.client.ClickHouseRecord; +import com.clickhouse.client.ClickHouseRequest; +import com.clickhouse.client.ClickHouseResponse; +import com.clickhouse.client.ClickHouseResponseSummary; +import com.clickhouse.client.data.BinaryStreamUtils; +import com.clickhouse.client.data.ClickHousePipedStream; + +public class Main { + static void dropAndCreateTable(ClickHouseNode server, String table) throws ClickHouseException { + try (ClickHouseClient client = ClickHouseClient.newInstance(server.getProtocol())) { + ClickHouseRequest request = client.connect(server); + // or use future chaining + request.query("drop table if exists " + table).execute().get(); + request.query("create table " + table + "(a String, b Nullable(String)) engine=MergeTree() order by a") + .execute().get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw ClickHouseException.forCancellation(e, server); + } catch (ExecutionException e) { + throw ClickHouseException.of(e, server); + } + } + + static long insert(ClickHouseNode server, String table) throws ClickHouseException { + try (ClickHouseClient client = ClickHouseClient.newInstance(server.getProtocol())) { + ClickHouseRequest.Mutation request = client.connect(server).write().table(table) + .format(ClickHouseFormat.RowBinary); + ClickHouseConfig config = request.getConfig(); + CompletableFuture future; + // back-pressuring is not supported, you can adjust the first two arguments + try (ClickHousePipedStream stream = new ClickHousePipedStream(config.getMaxBufferSize(), + config.getMaxQueuedBuffers(), config.getSocketTimeout())) { + // in async mode, which is default, execution happens in a worker thread + future = request.data(stream.getInput()).execute(); + + // writing happens in main thread + for (int i = 0; i < 1000000; i++) { + BinaryStreamUtils.writeString(stream, String.valueOf(i % 16)); + BinaryStreamUtils.writeNonNull(stream); + BinaryStreamUtils.writeString(stream, UUID.randomUUID().toString()); + } + } + + // response should be always closed + try (ClickHouseResponse response = future.get()) { + ClickHouseResponseSummary summary = response.getSummary(); + return summary.getWrittenRows(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw ClickHouseException.forCancellation(e, server); + } catch (ExecutionException | IOException e) { + throw ClickHouseException.of(e, server); + } + } + + static int query(ClickHouseNode server, String table) throws ClickHouseException { + try (ClickHouseClient client = ClickHouseClient.newInstance(server.getProtocol()); + ClickHouseResponse response = client.connect(server).query("select * from " + table).execute().get()) { + int count = 0; + // or use stream API via response.stream() + for (ClickHouseRecord rec : response.records()) { + count++; + } + return count; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw ClickHouseException.forCancellation(e, server); + } catch (ExecutionException e) { + throw ClickHouseException.of(e, server); + } + } + + public static void main(String[] args) { + ClickHouseNode server = ClickHouseNode.builder() + .host(System.getProperty("chHost", "192.168.3.16")) + .port(ClickHouseProtocol.GRPC, Integer.parseInt(System.getProperty("chPort", "9100"))) + .database("system").credentials(ClickHouseCredentials.fromUserAndPassword( + System.getProperty("chUser", "default"), System.getProperty("chPassword", ""))) + .build(); + + String table = "grpc_example_table"; + + try { + dropAndCreateTable(server, table); + + insert(server, table); + + query(server, table); + } catch (ClickHouseException e) { + e.printStackTrace(); + } + } +} diff --git a/examples/jdbc/pom.xml b/examples/jdbc/pom.xml new file mode 100644 index 000000000..fee05756f --- /dev/null +++ b/examples/jdbc/pom.xml @@ -0,0 +1,99 @@ + + + 4.0.0 + + com.clickhouse + jdbc-examples + 1.0.0 + jar + + jdbc-examples + JDBC Examples + https://github.com/ClickHouse/clickhouse-jdbc + 2022 + + + ClickHouse, Inc. + https://clickhouse.com/ + + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + repo + + + + + + zhicwu + Zhichun Wu + zhicwu@gmail.com + +8 + + + + + https://github.com/ClickHouse/clickhouse-jdbc + scm:git@github.com:ClickHouse/clickhouse-jdbc.git + scm:git@github.com:ClickHouse/clickhouse-jdbc.git + HEAD + + + + Github + https://github.com/ClickHouse/clickhouse-jdbc/issues + + + + Github + https://github.com/ClickHouse/clickhouse-jdbc/actions + + + + 2022 + UTF-8 + UTF-8 + + 0.3.2 + + 3.8.1 + + 1.8 + + + + + com.clickhouse + clickhouse-jdbc + ${clickhouse-jdbc.version} + http + + + * + * + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${compiler-plugin.version} + + ${minJdk} + ${minJdk} + true + + -Xlint:all + + + + + + + \ No newline at end of file diff --git a/examples/jdbc/src/main/java/com/clickhouse/examples/jdbc/Advance.java b/examples/jdbc/src/main/java/com/clickhouse/examples/jdbc/Advance.java new file mode 100644 index 000000000..b092aae03 --- /dev/null +++ b/examples/jdbc/src/main/java/com/clickhouse/examples/jdbc/Advance.java @@ -0,0 +1,79 @@ +package com.clickhouse.examples.jdbc; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.LocalDateTime; +import java.util.Properties; + +import com.clickhouse.client.ClickHouseFormat; +import com.clickhouse.client.data.ClickHouseExternalTable; + +public class Advance { + static String exteralTables(String url, String user, String password) throws SQLException { + String sql = "select a.name as n1, b.name as n2 from {tt 'table1'} a inner join {tt 'table2'} b on a.id=b.id"; + try (Connection conn = DriverManager.getConnection(url, user, password); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setObject(1, + ClickHouseExternalTable.builder().name("table1").columns("id Int32, name Nullable(String)") + .format(ClickHouseFormat.CSV) + .content(new ByteArrayInputStream("1,a\n2,b".getBytes(StandardCharsets.US_ASCII))).build()); + ps.setObject(2, + ClickHouseExternalTable.builder().name("table2").columns("id Int32, name String") + .format(ClickHouseFormat.JSONEachRow) + .content(new ByteArrayInputStream("{\"id\":3,\"name\":\"c\"}\n{\"id\":1,\"name\":\"d\"}" + .getBytes(StandardCharsets.US_ASCII))) + .build()); + try (ResultSet rs = ps.executeQuery()) { + if (!rs.next()) { + throw new IllegalStateException("Should have at least one record"); + } + + // n1=a, n2=d + return String.format("n1=%s, n2=%s", rs.getString(1), rs.getString(2)); + } + } + } + + static String namedParameter(String url, String user, String password) throws SQLException { + Properties props = new Properties(); + props.setProperty("user", user); + props.setProperty("password", password); + props.setProperty("namedParameter", "true"); + // two parameters: + // * a - String + // * b - DateTime64(3) + String sql = "select :a as a1, :a(String) as a2, :b(DateTime64(3)) as b"; + try (Connection conn = DriverManager.getConnection(url, props); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, "a"); + ps.setObject(2, LocalDateTime.of(2022, 1, 7, 22, 48, 17, 123000000)); + + try (ResultSet rs = ps.executeQuery()) { + if (!rs.next()) { + throw new IllegalStateException("Should have at least one record"); + } + // a1=a, a2=a, b=2022-01-07 22:48:17.123 + return String.format("a1=%s, a2=%s, b=%s", rs.getString(1), rs.getString(2), rs.getString("B")); + } + } + } + + public static void main(String[] args) { + String url = String.format("jdbc:ch://%s:%d/system", System.getProperty("chHost", "localhost"), + Integer.parseInt(System.getProperty("chPort", "8123"))); + String user = System.getProperty("chUser", "default"); + String password = System.getProperty("chPassword", ""); + + try { + exteralTables(url, user, password); + namedParameter(url, user, password); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/examples/jdbc/src/main/java/com/clickhouse/examples/jdbc/Basic.java b/examples/jdbc/src/main/java/com/clickhouse/examples/jdbc/Basic.java new file mode 100644 index 000000000..c25383c80 --- /dev/null +++ b/examples/jdbc/src/main/java/com/clickhouse/examples/jdbc/Basic.java @@ -0,0 +1,90 @@ +package com.clickhouse.examples.jdbc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +public class Basic { + static void dropAndCreateTable(String url, String user, String password, String table) throws SQLException { + try (Connection conn = DriverManager.getConnection(url, user, password); + Statement stmt = conn.createStatement()) { + stmt.execute( + String.format( + "drop table if exists %1$s; create table %1$s(a String, b Nullable(String)) engine=Memory", + table)); + } + } + + static void batchInsert(String url, String user, String password, String table) throws SQLException { + try (Connection conn = DriverManager.getConnection(url, user, password)) { + // not that fast as it's based on string substitution and large sql statement + String sql = String.format("insert into %1$s values(?, ?)", table); + try (PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, "a"); + ps.setString(2, "b"); + ps.addBatch(); + ps.setString(1, "c"); + ps.setString(2, null); + ps.addBatch(); + ps.executeBatch(); + } + + // faster when inserting massive data + sql = String.format("insert into %1$s", table); + try (PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, "a"); + ps.setString(2, "b"); + ps.addBatch(); + ps.setString(1, "c"); + ps.setString(2, null); + ps.addBatch(); + ps.executeBatch(); + } + + // fastest approach as it does not need to issue additional query for metadata + sql = String.format("insert into %1$s select a, b from input('a String, b Nullable(String)')", table); + try (PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, "a"); + ps.setString(2, "b"); + ps.addBatch(); + ps.setString(1, "c"); + ps.setString(2, null); + ps.addBatch(); + ps.executeBatch(); + } + } + } + + static int query(String url, String user, String password, String table) throws SQLException { + try (Connection conn = DriverManager.getConnection(url, user, password); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("select * from " + table)) { + int count = 0; + while (rs.next()) { + count++; + } + return count; + } + } + + public static void main(String[] args) { + String url = String.format("jdbc:ch://%s:%d/system", System.getProperty("chHost", "localhost"), + Integer.parseInt(System.getProperty("chPort", "8123"))); + String user = System.getProperty("chUser", "default"); + String password = System.getProperty("chPassword", ""); + String table = "jdbc_example_basic"; + + try { + dropAndCreateTable(url, user, password, table); + + batchInsert(url, user, password, table); + + query(url, user, password, table); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/pom.xml b/pom.xml index ef115f68b..9b075830d 100644 --- a/pom.xml +++ b/pom.xml @@ -73,33 +73,33 @@ 0.3.2-SNAPSHOT - 2021 + 2022 UTF-8 UTF-8 6.0.53 9.2 - 3.0.4 + 3.0.5 3.4.4 - 3.4.2 - 8.5.4 - 1.40.1 - 2.8.8 + 3.4.3 + 8.5.6 + 1.40.2 + 2.8.9 4.5.13 3.17.3 1.8.0 - 0.9.21 + 0.9.23 2.0.0-alpha5 3.12.4 - 2.31.0 - 1.16.0 + 2.32.0 + 1.16.2 7.4.0 2.7.4 8.0.27 42.3.1 - 1.1.0 + 1.1.1 3.3.0 3.8.1