Skip to content

Commit 5c8f0aa

Browse files
authored
Merge pull request #1693 from ClickHouse/feat_exec_api
[client-v2] Added executCommand API
2 parents ae04bf0 + 09dfdba commit 5c8f0aa

File tree

4 files changed

+175
-2
lines changed

4 files changed

+175
-2
lines changed

client-v2/src/main/java/com/clickhouse/client/api/Client.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import com.clickhouse.client.ClickHouseNode;
55
import com.clickhouse.client.ClickHouseRequest;
66
import com.clickhouse.client.ClickHouseResponse;
7+
import com.clickhouse.client.api.command.CommandResponse;
8+
import com.clickhouse.client.api.command.CommandSettings;
79
import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
810
import com.clickhouse.client.api.data_formats.RowBinaryWithNamesAndTypesFormatReader;
911
import com.clickhouse.client.api.data_formats.internal.MapBackedRecord;
@@ -672,8 +674,6 @@ public CompletableFuture<QueryResponse> query(String sqlQuery, QuerySettings set
672674
return query(sqlQuery, null, settings);
673675
}
674676

675-
676-
677677
/**
678678
* <p>Sends SQL query to server with parameters. The map `queryParams` should contain keys that
679679
* match the placeholders in the SQL query.</p>
@@ -848,6 +848,43 @@ public TableSchema getTableSchema(String table, String database) {
848848
}
849849
}
850850

851+
/**
852+
* <p>Executes a SQL command and doesn't care response. Useful for DDL statements, like `CREATE`, `DROP`, `ALTER`.
853+
* Method however returns execution errors from a server or summary in case of successful execution. </p>
854+
*
855+
* @param sql - SQL command
856+
* @param settings - execution settings
857+
* @return {@code CompletableFuture<CommandResponse>} - a promise to command response
858+
*/
859+
public CompletableFuture<CommandResponse> execute(String sql, CommandSettings settings) {
860+
return query(sql, settings)
861+
.thenApplyAsync(response -> {
862+
try {
863+
return new CommandResponse(response);
864+
} catch (Exception e) {
865+
throw new ClientException("Failed to get command response", e);
866+
}
867+
});
868+
}
869+
870+
/**
871+
* <p>Executes a SQL command and doesn't care response. Useful for DDL statements, like `CREATE`, `DROP`, `ALTER`.
872+
* Method however returns execution errors from a server or summary in case of successful execution. </p>
873+
*
874+
* @param sql - SQL command
875+
* @return {@code CompletableFuture<CommandResponse>} - a promise to command response
876+
*/
877+
public CompletableFuture<CommandResponse> execute(String sql) {
878+
return query(sql)
879+
.thenApplyAsync(response -> {
880+
try {
881+
return new CommandResponse(response);
882+
} catch (Exception e) {
883+
throw new ClientException("Failed to get command response", e);
884+
}
885+
});
886+
}
887+
851888
private String startOperation() {
852889
String operationId = UUID.randomUUID().toString();
853890
globalClientStats.put(operationId, new ClientStatisticsHolder());
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.clickhouse.client.api.command;
2+
3+
import com.clickhouse.client.api.ClientException;
4+
import com.clickhouse.client.api.metrics.OperationMetrics;
5+
import com.clickhouse.client.api.metrics.ServerMetrics;
6+
import com.clickhouse.client.api.query.QueryResponse;
7+
8+
public class CommandResponse{
9+
10+
private final QueryResponse response;
11+
12+
public CommandResponse(QueryResponse response) {
13+
this.response = response;
14+
try {
15+
response.close();
16+
} catch (Exception e) {
17+
throw new ClientException("Failed to close underlying resource", e);
18+
}
19+
}
20+
21+
/**
22+
* Returns the metrics of this operation.
23+
*
24+
* @return metrics of this operation
25+
*/
26+
public OperationMetrics getMetrics() {
27+
return response.getMetrics();
28+
}
29+
30+
/**
31+
* Alias for {@link ServerMetrics#NUM_ROWS_READ}
32+
*
33+
* @return number of rows read by server from the storage
34+
*/
35+
public long getReadRows() {
36+
return response.getReadRows();
37+
}
38+
39+
/**
40+
* Alias for {@link ServerMetrics#NUM_BYTES_READ}
41+
*
42+
* @return number of bytes read by server from the storage
43+
*/
44+
public long getReadBytes() {
45+
return response.getReadBytes();
46+
}
47+
48+
/**
49+
* Alias for {@link ServerMetrics#NUM_ROWS_WRITTEN}
50+
*
51+
* @return number of rows written by server to the storage
52+
*/
53+
public long getWrittenRows() {
54+
return response.getWrittenRows();
55+
}
56+
57+
/**
58+
* Alias for {@link ServerMetrics#NUM_BYTES_WRITTEN}
59+
*
60+
* @return number of bytes written by server to the storage
61+
*/
62+
public long getWrittenBytes() {
63+
return response.getWrittenBytes();
64+
}
65+
66+
/**
67+
* Alias for {@link ServerMetrics#ELAPSED_TIME}
68+
*
69+
* @return elapsed time in nanoseconds
70+
*/
71+
public long getServerTime() {
72+
return response.getServerTime();
73+
}
74+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.clickhouse.client.api.command;
2+
3+
import com.clickhouse.client.api.query.QuerySettings;
4+
5+
public class CommandSettings extends QuerySettings {
6+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.clickhouse.client.command;
2+
3+
import com.clickhouse.client.BaseIntegrationTest;
4+
import com.clickhouse.client.ClickHouseNode;
5+
import com.clickhouse.client.ClickHouseProtocol;
6+
import com.clickhouse.client.api.Client;
7+
import com.clickhouse.client.api.ClientException;
8+
import com.clickhouse.client.api.command.CommandResponse;
9+
import com.clickhouse.client.api.enums.Protocol;
10+
import org.testng.Assert;
11+
import org.testng.annotations.BeforeMethod;
12+
import org.testng.annotations.Test;
13+
14+
import java.util.concurrent.TimeUnit;
15+
16+
public class CommandTests extends BaseIntegrationTest {
17+
18+
private Client client;
19+
20+
@BeforeMethod(groups = {"integration"})
21+
public void setUp() {
22+
ClickHouseNode node = getServer(ClickHouseProtocol.HTTP);
23+
client = new Client.Builder()
24+
.addEndpoint(Protocol.HTTP, node.getHost(), node.getPort(), false)
25+
.setUsername("default")
26+
.setPassword("")
27+
.build();
28+
29+
System.out.println("Real port: " + node.getPort());
30+
}
31+
32+
33+
@Test(groups = {"integration"})
34+
public void testCreateTable() throws Exception {
35+
client.execute("DROP TABLE IF EXISTS test_table").get(10, TimeUnit.SECONDS);
36+
CommandResponse response =
37+
client.execute("CREATE TABLE IF NOT EXISTS test_table (id UInt32, name String) ENGINE = Memory")
38+
.get(10, TimeUnit.SECONDS);
39+
40+
Assert.assertNotNull(response);
41+
}
42+
43+
@Test(groups = {"integration"})
44+
public void testInvalidCommandExecution() throws Exception {
45+
CommandResponse response = client.execute("ALTER TABLE non_existing_table ADD COLUMN id2 UInt32")
46+
.exceptionally(e -> {
47+
48+
if (!(e.getCause() instanceof ClientException)) {
49+
Assert.fail("Cause should be a ClientException");
50+
}
51+
return null;
52+
}).get(10, TimeUnit.SECONDS);
53+
54+
Assert.assertNull(response);
55+
}
56+
}

0 commit comments

Comments
 (0)