Skip to content

Commit 51be963

Browse files
committed
Merge branch 'main' into issue-1470-fix-failover
2 parents edc9ad7 + 9a2359c commit 51be963

File tree

12 files changed

+538
-18
lines changed

12 files changed

+538
-18
lines changed

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,5 @@
11
package com.clickhouse.data;
22

3-
import java.io.Serializable;
4-
import java.lang.reflect.Array;
5-
import java.time.OffsetDateTime;
6-
import java.util.ArrayList;
7-
import java.util.Arrays;
8-
import java.util.Collections;
9-
import java.util.LinkedList;
10-
import java.util.List;
11-
import java.util.Objects;
12-
import java.util.TimeZone;
13-
143
import com.clickhouse.data.value.ClickHouseArrayValue;
154
import com.clickhouse.data.value.ClickHouseBigDecimalValue;
165
import com.clickhouse.data.value.ClickHouseBigIntegerValue;
@@ -46,6 +35,17 @@
4635
import com.clickhouse.data.value.array.ClickHouseLongArrayValue;
4736
import com.clickhouse.data.value.array.ClickHouseShortArrayValue;
4837

38+
import java.io.Serializable;
39+
import java.lang.reflect.Array;
40+
import java.time.OffsetDateTime;
41+
import java.util.ArrayList;
42+
import java.util.Arrays;
43+
import java.util.Collections;
44+
import java.util.LinkedList;
45+
import java.util.List;
46+
import java.util.Objects;
47+
import java.util.TimeZone;
48+
4949
/**
5050
* This class represents a column defined in database.
5151
*/

client-v2/pom.xml

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,16 @@
6969
<scope>provided</scope>
7070
</dependency>
7171

72-
<!-- <dependency>-->
73-
<!-- <groupId>${project.parent.groupId}</groupId>-->
74-
<!-- <artifactId>clickhouse-client</artifactId>-->
75-
<!-- <version>${revision}</version>-->
76-
<!-- <type>test-jar</type>-->
77-
<!-- <scope>test</scope>-->
78-
<!-- </dependency>-->
72+
<!-- START: Temporary test dependencies -->
73+
<dependency>
74+
<groupId>${project.parent.groupId}</groupId>
75+
<artifactId>clickhouse-client</artifactId>
76+
<version>${revision}</version>
77+
<type>test-jar</type>
78+
<scope>test</scope>
79+
</dependency>
80+
<!-- END: Temporary test dependencies -->
81+
7982
<dependency>
8083
<groupId>org.slf4j</groupId>
8184
<artifactId>slf4j-simple</artifactId>
@@ -96,13 +99,28 @@
9699
<artifactId>testng</artifactId>
97100
<scope>test</scope>
98101
</dependency>
102+
<dependency>
103+
<groupId>org.projectlombok</groupId>
104+
<artifactId>lombok</artifactId>
105+
<version>1.18.32</version>
106+
<scope>provided</scope>
107+
</dependency>
99108
</dependencies>
100109

101110
<build>
102111
<plugins>
103112
<plugin>
104113
<groupId>org.apache.maven.plugins</groupId>
105114
<artifactId>maven-compiler-plugin</artifactId>
115+
<configuration>
116+
<annotationProcessorPaths>
117+
<path>
118+
<groupId>org.projectlombok</groupId>
119+
<artifactId>lombok</artifactId>
120+
<version>1.18.32</version>
121+
</path>
122+
</annotationProcessorPaths>
123+
</configuration>
106124
</plugin>
107125
<plugin>
108126
<groupId>org.apache.maven.plugins</groupId>

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,23 @@
22

33
import com.clickhouse.client.ClickHouseClient;
44
import com.clickhouse.client.ClickHouseNode;
5+
import com.clickhouse.client.ClickHouseParameterizedQuery;
56
import com.clickhouse.client.ClickHouseProtocol;
7+
import com.clickhouse.client.ClickHouseRequest;
8+
import com.clickhouse.client.api.metadata.TableSchema;
9+
import com.clickhouse.client.api.internal.TableSchemaParser;
10+
import com.clickhouse.client.api.query.QueryResponse;
11+
import com.clickhouse.client.api.query.QuerySettings;
12+
import com.clickhouse.data.ClickHouseFormat;
613

714
import java.util.ArrayList;
815
import java.util.HashMap;
916
import java.util.HashSet;
1017
import java.util.List;
1118
import java.util.Map;
1219
import java.util.Set;
20+
import java.util.concurrent.CompletableFuture;
21+
import java.util.concurrent.Future;
1322

1423
public class Client {
1524
public static final int TIMEOUT = 30_000;
@@ -92,4 +101,38 @@ public boolean ping(int timeout) {
92101
ClickHouseClient clientPing = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
93102
return clientPing.ping(getServerNode(), timeout);
94103
}
104+
105+
/**
106+
* Sends data query to the server and returns a reference to a result descriptor.
107+
* Control is returned when server accepted the query and started processing it.
108+
* <br/>
109+
* The caller should use {@link ClickHouseParameterizedQuery} to render the `sqlQuery` with parameters.
110+
*
111+
*
112+
* @param sqlQuery - complete SQL query.
113+
* @param settings
114+
* @return
115+
*/
116+
public Future<QueryResponse> query(String sqlQuery, Map<String, Object> qparams, QuerySettings settings) {
117+
ClickHouseClient clientQuery = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
118+
ClickHouseRequest request = clientQuery.read(getServerNode());
119+
request.query(sqlQuery, settings.getQueryID());
120+
// TODO: convert qparams to map[string, string]
121+
request.params(qparams);
122+
return CompletableFuture.completedFuture(new QueryResponse(clientQuery.execute(request)));
123+
}
124+
125+
public TableSchema getTableSchema(String table, String database) {
126+
try (ClickHouseClient clientQuery = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP)) {
127+
ClickHouseRequest request = clientQuery.read(getServerNode());
128+
// XML - because java has a built-in XML parser. Will consider CSV later.
129+
request.query("DESCRIBE TABLE " + table + " FORMAT " + ClickHouseFormat.TSKV.name());
130+
TableSchema tableSchema = new TableSchema();
131+
try {
132+
return new TableSchemaParser().createFromBinaryResponse(clientQuery.execute(request).get(), table, database);
133+
} catch (Exception e) {
134+
throw new RuntimeException("Failed to get table schema", e);
135+
}
136+
}
137+
}
95138
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.clickhouse.client.api.data_formats;
2+
3+
import com.clickhouse.data.ClickHouseRecord;
4+
5+
import java.util.function.Consumer;
6+
7+
public interface RecordReader {
8+
9+
/**
10+
* Check if the reader can read the specified data format.
11+
*
12+
* @param dataFormat
13+
* @return true if the reader can read the specified data format, false otherwise
14+
*/
15+
boolean canRead(String dataFormat);
16+
17+
/**
18+
* Read a batch of records from a stream.
19+
*
20+
* @param size the maximum number of records to read
21+
* @param consumer the consumer to process the records
22+
* @param errorHandler the consumer to handle exceptions
23+
* @return true if there are more records to read, false otherwise
24+
*/
25+
boolean readBatch(int size, Consumer<ClickHouseRecord> consumer, Consumer<Exception> errorHandler);
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.clickhouse.client.api.data_formats;
2+
3+
import com.clickhouse.data.ClickHouseInputStream;
4+
import com.clickhouse.data.ClickHouseRecord;
5+
6+
import java.util.function.Consumer;
7+
8+
public class RowBinaryReader implements RecordReader {
9+
10+
private final ClickHouseInputStream inputStream;
11+
12+
public RowBinaryReader(ClickHouseInputStream inputStream) {
13+
this.inputStream = inputStream;
14+
}
15+
16+
@Override
17+
public boolean readBatch(int size, Consumer<ClickHouseRecord> consumer, Consumer<Exception> errorHandler) {
18+
// TODO: implementation of record reader will get raw stream from response and will read records from it
19+
return false;
20+
}
21+
22+
@Override
23+
public boolean canRead(String dataFormat) {
24+
return "RowBinary".equalsIgnoreCase(dataFormat);
25+
}
26+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.clickhouse.client.api.internal;
2+
3+
import com.clickhouse.client.ClickHouseResponse;
4+
import com.clickhouse.client.api.metadata.TableSchema;
5+
6+
import java.io.IOException;
7+
import java.io.StringReader;
8+
import java.util.Properties;
9+
10+
public class TableSchemaParser {
11+
12+
public TableSchemaParser() {
13+
}
14+
15+
public TableSchema createFromBinaryResponse(ClickHouseResponse response, String tableName, String databaseName) {
16+
TableSchema schema = new TableSchema();
17+
schema.setTableName(tableName);
18+
schema.setDatabaseName(databaseName);
19+
Properties p = new Properties();
20+
response.records().forEach(record -> {
21+
String values = record.getValue(0).asString().replaceAll("\t", "\n");
22+
try {
23+
p.clear();
24+
p.load(new StringReader(values));
25+
schema.addColumn(p.getProperty("name"), p.getProperty("type"));
26+
} catch ( IOException e) {
27+
throw new RuntimeException("Failed to parse table schema", e);
28+
}
29+
});
30+
return schema;
31+
}
32+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.clickhouse.client.api.metadata;
2+
3+
import com.clickhouse.data.ClickHouseColumn;
4+
5+
import java.util.ArrayList;
6+
import java.util.Collections;
7+
import java.util.HashMap;
8+
import java.util.List;
9+
import java.util.Map;
10+
11+
public class TableSchema {
12+
13+
private String tableName = "";
14+
15+
private String databaseName = "";
16+
17+
private List<ClickHouseColumn> columns;
18+
19+
private Map<String, Map<String, Object>> metadata;
20+
21+
public TableSchema() {
22+
this.metadata = new HashMap<>();
23+
this.columns = new ArrayList<>();
24+
}
25+
26+
/**
27+
* Returns unmodifiable collection of columns.
28+
*
29+
* @return - collection of columns in the table
30+
*/
31+
public List<ClickHouseColumn> getColumns() {
32+
return Collections.unmodifiableList(columns);
33+
}
34+
35+
public String getDatabaseName() {
36+
return databaseName;
37+
}
38+
39+
public String getTableName() {
40+
return tableName;
41+
}
42+
43+
public void setTableName(String tableName) {
44+
this.tableName = tableName;
45+
}
46+
47+
public void setDatabaseName(String databaseName) {
48+
this.databaseName = databaseName;
49+
}
50+
51+
public void addColumn(String name, String type) {
52+
columns.add(ClickHouseColumn.of(name, type));
53+
metadata.computeIfAbsent(name, k -> new HashMap<>()).put("type", type);
54+
}
55+
}
56+
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.clickhouse.client.api.query;
2+
3+
import com.clickhouse.client.ClickHouseResponse;
4+
import com.clickhouse.data.ClickHouseInputStream;
5+
6+
import java.util.concurrent.ExecutionException;
7+
import java.util.concurrent.Future;
8+
import java.util.concurrent.TimeUnit;
9+
import java.util.concurrent.TimeoutException;
10+
11+
/**
12+
* Response class provides interface to input stream of response data.
13+
* <br/>
14+
* It is used to read data from ClickHouse server.
15+
* It is used to get response metadata like errors, warnings, etc.
16+
*
17+
* This class is for the following user cases:
18+
* <ul>
19+
* <li>Full read. User does conversion from record to custom object</li>
20+
* <li>Full read. No conversion to custom object. List of generic records is returned. </li>
21+
* <li>Iterative read. One record is returned at a time</li>
22+
* </ul>
23+
*
24+
*
25+
*/
26+
public class QueryResponse {
27+
28+
private final Future<ClickHouseResponse> responseRef;
29+
30+
private long completeTimeout = TimeUnit.MINUTES.toMillis(1);
31+
32+
public QueryResponse(Future<ClickHouseResponse> responseRef) {
33+
this.responseRef = responseRef;
34+
}
35+
36+
public boolean isDone() {
37+
return responseRef.isDone();
38+
}
39+
40+
public void ensureDone() {
41+
if (!isDone()) {
42+
try {
43+
responseRef.get(completeTimeout, TimeUnit.MILLISECONDS);
44+
} catch (TimeoutException | InterruptedException | ExecutionException e) {
45+
throw new RuntimeException(e); // TODO: handle exception
46+
}
47+
}
48+
}
49+
50+
public ClickHouseInputStream getInputStream() {
51+
ensureDone();
52+
try {
53+
return responseRef.get().getInputStream();
54+
} catch (Exception e) {
55+
throw new RuntimeException(e); // TODO: handle exception
56+
}
57+
}
58+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.clickhouse.client.api.query;
2+
3+
4+
import com.clickhouse.client.config.ClickHouseClientOption;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
9+
public class QuerySettings {
10+
11+
private Map<String, Object> rawSettings;
12+
13+
public QuerySettings() {
14+
this.rawSettings = new HashMap<>();
15+
}
16+
17+
public QuerySettings setSetting(String key, Object value) {
18+
rawSettings.put(key, value);
19+
return this;
20+
}
21+
public Object getSetting(String key) {
22+
return rawSettings.get(key);
23+
}
24+
public QuerySettings appendToSetting(String key, Object value) {
25+
rawSettings.put(key, value);
26+
return this;
27+
}
28+
29+
public QuerySettings setFormat(String format) {
30+
rawSettings.put(ClickHouseClientOption.FORMAT.getKey(), format);
31+
return this;
32+
}
33+
34+
public String getFormat() {
35+
return (String) rawSettings.get(ClickHouseClientOption.FORMAT.getKey());
36+
}
37+
38+
public QuerySettings setQueryID(String queryID) {
39+
rawSettings.put("query_id", queryID);
40+
return this;
41+
}
42+
public String getQueryID() {
43+
return (String) rawSettings.get("query_id");
44+
}
45+
}

0 commit comments

Comments
 (0)