Skip to content

Commit 6d9bc0c

Browse files
committed
added options for additional headers and server settings
1 parent 1ab7809 commit 6d9bc0c

File tree

13 files changed

+438
-27
lines changed

13 files changed

+438
-27
lines changed

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseNodes.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ static ClickHouseNodes create(String endpoints, Map<?, ?> defaultOptions) {
6868
} else {
6969
index = 0;
7070
}
71+
7172

7273
String defaultParams = "";
7374
Set<String> list = new LinkedHashSet<>();
@@ -95,14 +96,19 @@ static ClickHouseNodes create(String endpoints, Map<?, ?> defaultOptions) {
9596
}
9697

9798
int endIndex = i;
99+
// parsing host name
98100
for (int j = i + 1; j < len; j++) {
99101
ch = endpoints.charAt(j);
100102
if (ch == stopChar || Character.isWhitespace(ch)) {
101103
endIndex = j;
102104
break;
105+
} else if ( stopChar == ',' && ( ch == '/' || ch == '?' || ch == '#') ) {
106+
break;
103107
}
104108
}
109+
105110
if (endIndex > i) {
111+
// add host name to list
106112
list.add(endpoints.substring(index, endIndex).trim());
107113
i = endIndex;
108114
index = endIndex + 1;

clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseNodeTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.clickhouse.client;
22

3+
import com.clickhouse.config.ClickHouseOption;
34
import org.testng.Assert;
5+
import org.testng.annotations.DataProvider;
46
import org.testng.annotations.Test;
57

68
import java.net.URI;
@@ -438,4 +440,34 @@ public void testToUri() {
438440
.toUri().toString(),
439441
"http://server1.dc1:8123/db1?async=false&auto_discovery=true#apj,r1s1");
440442
}
443+
444+
@Test(groups = { "unit" }, dataProvider = "testPropertyWithValueList_endpoints")
445+
public void testPropertyWithValueList(String endpoints, int numOfNodes, String[] expectedBaseUris) {
446+
ClickHouseNodes node = ClickHouseNodes.of(endpoints);
447+
Assert.assertEquals(node.nodes.size(), numOfNodes, "Number of nodes does not match");
448+
449+
int i = 0;
450+
for (ClickHouseNode n : node.nodes) {
451+
Assert.assertEquals(n.config.getDatabase(), "my_db");
452+
Assert.assertEquals(expectedBaseUris[i++], n.getBaseUri());
453+
String customSettings = (String)n.config.getOption(ClickHouseClientOption.CUSTOM_SETTINGS);
454+
String configSettings = (String) n.config.getOption(ClickHouseClientOption.CUSTOM_SETTINGS);
455+
456+
Arrays.asList(customSettings, configSettings).forEach((settings) -> {
457+
Map<String, String> settingsMap = ClickHouseOption.toKeyValuePairs(settings);
458+
Assert.assertEquals(settingsMap.get("param1"), "value1");
459+
Assert.assertEquals(settingsMap.get("param2"), "value2");
460+
});
461+
}
462+
}
463+
464+
@DataProvider(name = "testPropertyWithValueList_endpoints")
465+
public static Object[][] endpoints() {
466+
return new Object[][] {
467+
{ "http://server1:9090/my_db?custom_settings=param1=value1,param2=value2", 1, new String[]{"http://server1:9090/"} },
468+
{ "http://server1/my_db?custom_settings=param1=value1,param2=value2", 1, new String[]{"http://server1:8123/"} },
469+
{ "http://server1:9090,server2/my_db?custom_settings=param1=value1,param2=value2", 2, new String[]{"http://server1:9090/", "http://server2:8123/"} },
470+
{ "http://server1,server2:9090/my_db?custom_settings=param1=value1,param2=value2", 2, new String[]{"http://server1:8123/", "http://server2:9090/"} }
471+
};
472+
}
441473
}

clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseNodesTest.java

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,9 @@ public void testNodeGrouping() throws ExecutionException, InterruptedException,
214214
Assert.assertEquals(nodes.get(), ClickHouseNode.of("tcp://b:9000/test?x=1"));
215215
}
216216

217-
@Test(groups = { "unit" })
217+
@Test(groups = { "unit" }, enabled = false)
218218
public void testQueryWithSlash() {
219+
// test is disabled because this format of urls is not supported
219220
ClickHouseNodes servers = ClickHouseNodes
220221
.of("https://node1?a=/b/c/d,node2/db2?/a/b/c=d,node3/db1?a=/d/c.b");
221222
Assert.assertEquals(servers.nodes.get(0).getDatabase().orElse(null), "db1");
@@ -268,30 +269,33 @@ public void testMultiNodeList() {
268269
Assert.assertEquals(ClickHouseNodes.of("http://(a) , {b}, [::1]"), new ClickHouseNodes(
269270
Arrays.asList(ClickHouseNode.of("http://a"), ClickHouseNode.of("http://b"),
270271
ClickHouseNode.of("http://[::1]"))));
271-
Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c"), new ClickHouseNodes(
272-
Arrays.asList(ClickHouseNode.of("http://a"), ClickHouseNode.of("tcp://b"),
273-
ClickHouseNode.of("grpc://c"))));
274-
Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c/"), new ClickHouseNodes(
275-
Arrays.asList(ClickHouseNode.of("http://a"), ClickHouseNode.of("tcp://b"),
276-
ClickHouseNode.of("grpc://c"))));
277-
Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c/db1"), new ClickHouseNodes(
278-
Arrays.asList(ClickHouseNode.of("http://a/db1"), ClickHouseNode.of("tcp://b/db1"),
279-
ClickHouseNode.of("grpc://c/db1"))));
280-
Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c?a=1"), new ClickHouseNodes(
281-
Arrays.asList(ClickHouseNode.of("http://a?a=1"), ClickHouseNode.of("tcp://b?a=1"),
282-
ClickHouseNode.of("grpc://c?a=1"))));
283-
Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c#dc1"), new ClickHouseNodes(
284-
Arrays.asList(ClickHouseNode.of("http://a#dc1"), ClickHouseNode.of("tcp://b#dc1"),
285-
ClickHouseNode.of("grpc://c#dc1"))));
286-
Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c:1234/some/db?a=1#dc1"),
287-
new ClickHouseNodes(
288-
Arrays.asList(ClickHouseNode.of("http://a/some/db?a=1#dc1"),
289-
ClickHouseNode.of("tcp://b/some/db?a=1#dc1"),
290-
ClickHouseNode.of("grpc://c:1234/some/db?a=1#dc1"))));
272+
273+
// THIS IS SHOULD NOT BE SUPPORTED
274+
// Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c"), new ClickHouseNodes(
275+
// Arrays.asList(ClickHouseNode.of("http://a"), ClickHouseNode.of("tcp://b"),
276+
// ClickHouseNode.of("grpc://c"))));
277+
// Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c/"), new ClickHouseNodes(
278+
// Arrays.asList(ClickHouseNode.of("http://a"), ClickHouseNode.of("tcp://b"),
279+
// ClickHouseNode.of("grpc://c"))));
280+
// Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c/db1"), new ClickHouseNodes(
281+
// Arrays.asList(ClickHouseNode.of("http://a/db1"), ClickHouseNode.of("tcp://b/db1"),
282+
// ClickHouseNode.of("grpc://c/db1"))));
283+
// Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c?a=1"), new ClickHouseNodes(
284+
// Arrays.asList(ClickHouseNode.of("http://a?a=1"), ClickHouseNode.of("tcp://b?a=1"),
285+
// ClickHouseNode.of("grpc://c?a=1"))));
286+
// Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c#dc1"), new ClickHouseNodes(
287+
// Arrays.asList(ClickHouseNode.of("http://a#dc1"), ClickHouseNode.of("tcp://b#dc1"),
288+
// ClickHouseNode.of("grpc://c#dc1"))));
289+
// Assert.assertEquals(ClickHouseNodes.of("http://a,tcp://b,grpc://c:1234/some/db?a=1#dc1"),
290+
// new ClickHouseNodes(
291+
// Arrays.asList(ClickHouseNode.of("http://a/some/db?a=1#dc1"),
292+
// ClickHouseNode.of("tcp://b/some/db?a=1#dc1"),
293+
// ClickHouseNode.of("grpc://c:1234/some/db?a=1#dc1"))));
291294
}
292295

293-
@Test(groups = { "unit" })
296+
@Test(groups = { "unit" }, enabled = false)
294297
public void testManageAndUnmanageNewNode() {
298+
// test is disabled because this format of urls is not supported
295299
ClickHouseNodes nodes = ClickHouseNodes.create("https://a,grpcs://b,mysql://c", null);
296300
Assert.assertEquals(nodes.getPolicy(), ClickHouseLoadBalancingPolicy.DEFAULT);
297301
Assert.assertEquals(nodes.nodes.size(), 3);
@@ -322,7 +326,7 @@ public void testManageAndUnmanageNewNode() {
322326

323327
@Test(groups = { "unit" })
324328
public void testManageAndUnmanageSameNode() {
325-
ClickHouseNodes nodes = ClickHouseNodes.create("grpc://(http://a), tcp://b, c", null);
329+
ClickHouseNodes nodes = ClickHouseNodes.create("http://a,b,c", null);
326330
Assert.assertEquals(nodes.nodes.size(), 3);
327331
Assert.assertEquals(nodes.faultyNodes.size(), 0);
328332
ClickHouseNode node = ClickHouseNode.of("http://a");
@@ -337,7 +341,7 @@ public void testManageAndUnmanageSameNode() {
337341
Assert.assertEquals(nodes.faultyNodes.size(), 0);
338342

339343
// now repeat same scenario but using different method
340-
node = ClickHouseNode.of("tcp://b");
344+
node = ClickHouseNode.of("http://b");
341345
Assert.assertTrue(node.isStandalone(), "Newly created node is always standalone");
342346
node.setManager(nodes);
343347
Assert.assertTrue(node.isManaged(), "Node should be managed");

clickhouse-http-client/src/main/java/com/clickhouse/client/http/config/ClickHouseHttpOption.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ public enum ClickHouseHttpOption implements ClickHouseOption {
2020
*/
2121
CUSTOM_HEADERS("custom_http_headers", "", "Custom HTTP headers."),
2222
/**
23-
* Custom HTTP query parameters. Consider
24-
* {@link com.clickhouse.client.config.ClickHouseClientOption#CUSTOM_SETTINGS}
25-
* if you don't want your implementation ties to http protocol.
23+
* @deprecated use {@link com.clickhouse.client.config.ClickHouseClientOption#CUSTOM_SETTINGS}
2624
*/
2725
CUSTOM_PARAMS("custom_http_params", "", "Custom HTTP query parameters."),
2826
/**

clickhouse-jdbc/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,12 @@
231231
<artifactId>mysql-connector-j</artifactId>
232232
<scope>test</scope>
233233
</dependency>
234+
<dependency>
235+
<groupId>com.clickhouse</groupId>
236+
<artifactId>clickhouse-http-client</artifactId>
237+
<version>0.6.5-SNAPSHOT</version>
238+
<scope>compile</scope>
239+
</dependency>
234240
</dependencies>
235241

236242
<profiles>

clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHouseDriverTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import com.clickhouse.client.ClickHouseProtocol;
66

7+
import com.clickhouse.jdbc.internal.ClickHouseJdbcUrlParser;
78
import org.testng.Assert;
89
import org.testng.annotations.Test;
910

clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/internal/ClickHouseJdbcUrlParserTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
import java.util.Properties;
77

88
import com.clickhouse.client.ClickHouseCredentials;
9+
import com.clickhouse.client.ClickHouseLoadBalancingPolicy;
910
import com.clickhouse.client.ClickHouseNode;
1011
import com.clickhouse.client.ClickHouseProtocol;
1112
import com.clickhouse.client.config.ClickHouseDefaults;
1213
import com.clickhouse.jdbc.internal.ClickHouseJdbcUrlParser.ConnectionInfo;
1314

1415
import org.testng.Assert;
16+
import org.testng.annotations.DataProvider;
1517
import org.testng.annotations.Test;
1618

1719
public class ClickHouseJdbcUrlParserTest {
@@ -154,4 +156,24 @@ public void testParseCredentials() throws SQLException {
154156
Assert.assertEquals(server.getCredentials().get().getUserName(), "let@me:in");
155157
Assert.assertEquals(server.getCredentials().get().getPassword(), "let@me:in");
156158
}
159+
160+
@Test(groups = "unit", dataProvider = "testParseUrlPropertiesProvider")
161+
public void testParseUrlProperties(String url, int numOfNodes) throws SQLException {
162+
163+
ConnectionInfo info = ClickHouseJdbcUrlParser.parse(url, null);
164+
Assert.assertEquals(info.getNodes().getNodes().size(), numOfNodes);
165+
Assert.assertEquals(info.getNodes().getPolicy().getClass().getSimpleName(), "FirstAlivePolicy");
166+
for (ClickHouseNode n : info.getNodes().getNodes()) {
167+
Assert.assertEquals(n.getOptions().get("connect_timeout"), "10000");
168+
Assert.assertEquals(n.getOptions().get("http_connection_provider"), "HTTP_CLIENT");
169+
}
170+
}
171+
172+
@DataProvider(name = "testParseUrlPropertiesProvider")
173+
public static Object[][] testParseUrlPropertiesProvider() {
174+
return new Object[][] {
175+
{ "jdbc:clickhouse://host1:8123,host2:8123,host3:8123/db1?http_connection_provider=HTTP_CLIENT&load_balancing_policy=firstAlive&connect_timeout=10000", 3 },
176+
{ "jdbc:clickhouse:http://host1:8123,host2:8123,host3:8123/db1?http_connection_provider=HTTP_CLIENT&load_balancing_policy=firstAlive&connect_timeout=10000", 3 }
177+
};
178+
}
157179
}

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

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import java.time.ZoneId;
6767
import java.time.temporal.ChronoUnit;
6868
import java.util.ArrayList;
69+
import java.util.Collection;
6970
import java.util.Collections;
7071
import java.util.HashMap;
7172
import java.util.HashSet;
@@ -120,6 +121,7 @@
120121
*
121122
*/
122123
public class Client implements AutoCloseable {
124+
123125
private HttpAPIClientHelper httpClientHelper = null;
124126

125127
private final Set<String> endpoints;
@@ -779,6 +781,72 @@ public Builder allowBinaryReaderToReuseBuffers(boolean reuse) {
779781
return this;
780782
}
781783

784+
/**
785+
* Defines list of headers that should be sent with each request. The Client will use a header value
786+
* defined in {@code headers} instead of any other.
787+
* Operation settings may override these headers.
788+
*
789+
* @see InsertSettings#httpHeaders(Map)
790+
* @see QuerySettings#httpHeaders(Map)
791+
* @see CommandSettings#httpHeaders(Map)
792+
* @param key - a name of the header.
793+
* @param value - a value of the header.
794+
* @return same instance of the builder
795+
*/
796+
public Builder httpHeader(String key, String value) {
797+
this.configuration.put(ClientSettings.HTTP_HEADER_PREFIX + key, value);
798+
return this;
799+
}
800+
801+
/**
802+
* {@see #httpHeader(String, String)} but for multiple values.
803+
* @param key - name of the header
804+
* @param values - collection of values
805+
* @return same instance of the builder
806+
*/
807+
public Builder httpHeader(String key, Collection<String> values) {
808+
this.configuration.put(ClientSettings.HTTP_HEADER_PREFIX + key, ClientSettings.commaSeparated(values));
809+
return this;
810+
}
811+
812+
/**
813+
* {@see #httpHeader(String, String)} but for multiple headers.
814+
* @param headers - map of headers
815+
* @return same instance of the builder
816+
*/
817+
public Builder httpHeaders(Map<String, String> headers) {
818+
headers.forEach(this::httpHeader);
819+
return this;
820+
}
821+
822+
/**
823+
* Defines list of server settings that should be sent with each request. The Client will use a setting value
824+
* defined in {@code settings} instead of any other.
825+
* Operation settings may override these values.
826+
*
827+
* @see InsertSettings#serverSetting(String, String) (Map)
828+
* @see QuerySettings#serverSetting(String, String) (Map)
829+
* @see CommandSettings#serverSetting(String, String) (Map)
830+
* @param name - name of the setting without special prefix
831+
* @param value - value of the setting
832+
* @return same instance of the builder
833+
*/
834+
public Builder serverSetting(String name, String value) {
835+
this.configuration.put(ClientSettings.SERVER_SETTING_PREFIX + name, value);
836+
return this;
837+
}
838+
839+
/**
840+
* {@see #serverSetting(String, String)} but for multiple values.
841+
* @param name - name of the setting without special prefix
842+
* @param values - collection of values
843+
* @return same instance of the builder
844+
*/
845+
public Builder serverSetting(String name, Collection<String> values) {
846+
this.configuration.put(ClientSettings.SERVER_SETTING_PREFIX + name, ClientSettings.commaSeparated(values));
847+
return this;
848+
}
849+
782850
public Client build() {
783851
setDefaults();
784852

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.clickhouse.client.api;
2+
3+
import java.util.Arrays;
4+
import java.util.Collection;
5+
import java.util.List;
6+
import java.util.stream.Collectors;
7+
8+
/**
9+
* All known client settings at current version.
10+
*
11+
*/
12+
public class ClientSettings {
13+
14+
public static final String HTTP_HEADER_PREFIX = "http_header_";
15+
16+
public static final String SERVER_SETTING_PREFIX = "clickhouse_setting_";
17+
18+
public static String commaSeparated(Collection<?> values) {
19+
StringBuilder sb = new StringBuilder();
20+
for (Object value : values) {
21+
sb.append(value.toString().replaceAll(",", "\\,")).append(",");
22+
}
23+
sb.setLength(sb.length() - 1);
24+
return sb.toString();
25+
}
26+
27+
public static List<String> valuesFromCommaSeparated(String value) {
28+
return Arrays.stream(value.split(",")).map(s -> s.replaceAll("\\\\,", ","))
29+
.collect(Collectors.toList());
30+
}
31+
}

0 commit comments

Comments
 (0)