Skip to content

Commit

Permalink
support credentials and protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
zhicwu committed Oct 10, 2021
1 parent a8ac5b2 commit 4f93201
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -14,34 +16,49 @@

public class ClickhouseJdbcUrlParser {
private static final Logger log = LoggerFactory.getLogger(ClickhouseJdbcUrlParser.class);

protected static final String DEFAULT_DATABASE = "default";

public static final String JDBC_PREFIX = "jdbc:";
public static final String JDBC_CLICKHOUSE_PREFIX = JDBC_PREFIX + "clickhouse:";
public static final Pattern DB_PATH_PATTERN = Pattern.compile("/([a-zA-Z0-9_*\\-]+)");
protected final static String DEFAULT_DATABASE = "default";

private ClickhouseJdbcUrlParser(){
private ClickhouseJdbcUrlParser() {
}

public static ClickHouseProperties parse(String jdbcUrl, Properties defaults) throws URISyntaxException
{
public static ClickHouseProperties parse(String jdbcUrl, Properties defaults) throws URISyntaxException {
if (!jdbcUrl.startsWith(JDBC_CLICKHOUSE_PREFIX)) {
throw new URISyntaxException(jdbcUrl, "'" + JDBC_CLICKHOUSE_PREFIX + "' prefix is mandatory");
}
return parseClickhouseUrl(jdbcUrl.substring(JDBC_PREFIX.length()), defaults);
}

private static ClickHouseProperties parseClickhouseUrl(String uriString, Properties defaults)
throws URISyntaxException
{
throws URISyntaxException {
URI uri = new URI(uriString);
Properties urlProperties = parseUriQueryPart(uri.getQuery(), defaults);
ClickHouseProperties props = new ClickHouseProperties(urlProperties);
props.setHost(uri.getHost());
int port = uri.getPort();
if (port == -1) {
throw new IllegalArgumentException("port is missed or wrong");
port = props.getProtocol().getDefaultPort();
}
props.setPort(port);
String credentials = uri.getRawUserInfo();
if (credentials != null && !credentials.isEmpty()) {
int index = credentials.indexOf(':');
String userName = index == 0 ? ""
: URLDecoder.decode(index > 0 ? credentials.substring(0, index) : credentials,
StandardCharsets.UTF_8);
if (!userName.isEmpty()) {
props.setUser(userName);
}
String password = index < 0 ? ""
: URLDecoder.decode(credentials.substring(index + 1), StandardCharsets.UTF_8);
if (!password.isEmpty()) {
props.setPassword(password);
}
}
String path = uri.getPath();
String database;
if (props.isUsePathAsDb()) {
Expand Down Expand Up @@ -75,9 +92,9 @@ static Properties parseUriQueryPart(String query, Properties defaults) {
return defaults;
}
Properties urlProps = new Properties(defaults);
String queryKeyValues[] = query.split("&");
String[] queryKeyValues = query.split("&");
for (String keyValue : queryKeyValues) {
String keyValueTokens[] = keyValue.split("=");
String[] keyValueTokens = keyValue.split("=");
if (keyValueTokens.length == 2) {
urlProps.put(keyValueTokens[0], keyValueTokens[1]);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public enum ClickHouseConnectionSettings implements DriverPropertyCreator {
SSL_MODE("sslmode", "strict", "verify or not certificate: none (don't verify), strict (verify)"),
USE_PATH_AS_DB("use_path_as_db", true, "whether URL path should be treated as database name"),
PATH("path", "/", "URL path"),
PROTOCOL("protocol", "http", "protocol used to connect to server, http or grpc"),
CHECK_FOR_REDIRECTS("check_for_redirects", false, "whether we should check for 307 redirect using GET before sending POST to given URL"),
MAX_REDIRECTS("max_redirects", 5, "number of redirect checks before using last URL"),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.Properties;

import com.clickhouse.client.ClickHouseChecker;
import com.clickhouse.client.ClickHouseProtocol;

public class ClickHouseProperties {

Expand All @@ -21,6 +22,7 @@ public class ClickHouseProperties {
private int maxRetries;
private String host;
private int port;
private ClickHouseProtocol protocol;
private boolean usePathAsDb;
private String path;
private boolean ssl;
Expand Down Expand Up @@ -119,6 +121,7 @@ public ClickHouseProperties(Properties info) {
this.sslMode = (String) getSetting(info, ClickHouseConnectionSettings.SSL_MODE);
this.usePathAsDb = (Boolean) getSetting(info, ClickHouseConnectionSettings.USE_PATH_AS_DB);
this.path = (String) getSetting(info, ClickHouseConnectionSettings.PATH);
this.protocol = ClickHouseProtocol.valueOf(((String) getSetting(info, ClickHouseConnectionSettings.PROTOCOL)).toUpperCase());
this.maxRedirects = (Integer) getSetting(info, ClickHouseConnectionSettings.MAX_REDIRECTS);
this.checkForRedirects = (Boolean) getSetting(info, ClickHouseConnectionSettings.CHECK_FOR_REDIRECTS);
this.useServerTimeZone = (Boolean)getSetting(info, ClickHouseConnectionSettings.USE_SERVER_TIME_ZONE);
Expand All @@ -134,6 +137,7 @@ public ClickHouseProperties(Properties info) {
this.quotaKey = getSetting(info, ClickHouseQueryParam.QUOTA_KEY);
this.priority = getSetting(info, ClickHouseQueryParam.PRIORITY);
this.database = getSetting(info, ClickHouseQueryParam.DATABASE);
this.protocol = ClickHouseProtocol.valueOf(((String)getSetting(info, ClickHouseConnectionSettings.PROTOCOL)).toUpperCase());
this.compress = (Boolean)getSetting(info, ClickHouseQueryParam.COMPRESS);
this.decompress = (Boolean)getSetting(info, ClickHouseQueryParam.DECOMPRESS);
this.extremes = (Boolean)getSetting(info, ClickHouseQueryParam.EXTREMES);
Expand Down Expand Up @@ -187,6 +191,7 @@ public Properties asProperties() {
ret.put(ClickHouseConnectionSettings.SSL_MODE.getKey(), String.valueOf(sslMode));
ret.put(ClickHouseConnectionSettings.USE_PATH_AS_DB.getKey(), String.valueOf(usePathAsDb));
ret.put(ClickHouseConnectionSettings.PATH.getKey(), String.valueOf(path));
ret.put(ClickHouseConnectionSettings.PROTOCOL.getKey(), String.valueOf(protocol.name().toLowerCase()));
ret.put(ClickHouseConnectionSettings.MAX_REDIRECTS.getKey(), String.valueOf(maxRedirects));
ret.put(ClickHouseConnectionSettings.CHECK_FOR_REDIRECTS.getKey(), String.valueOf(checkForRedirects));
ret.put(ClickHouseConnectionSettings.USE_SERVER_TIME_ZONE.getKey(), String.valueOf(useServerTimeZone));
Expand Down Expand Up @@ -258,6 +263,7 @@ public ClickHouseProperties(ClickHouseProperties properties) {
setSslMode(properties.sslMode);
setUsePathAsDb(properties.usePathAsDb);
setPath(properties.path);
setProtocol(properties.protocol);
setMaxRedirects(properties.maxRedirects);
setCheckForRedirects(properties.checkForRedirects);
setUseServerTimeZone(properties.useServerTimeZone);
Expand Down Expand Up @@ -799,6 +805,14 @@ public void setPort(int port) {
this.port = port;
}

public ClickHouseProtocol getProtocol() {
return this.protocol;
}

public void setProtocol(ClickHouseProtocol protocol) {
this.protocol = protocol;
}

public boolean isUsePathAsDb() {
return usePathAsDb;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import java.util.Properties;

import com.clickhouse.client.ClickHouseProtocol;

import org.eclipse.jetty.client.ProxyProtocolClientConnectionFactory.V2.Tag.Protocol;
import org.testng.Assert;
import org.testng.annotations.Test;

Expand All @@ -12,25 +15,25 @@ public class ClickhouseJdbcUrlParserTest {
@Test(groups = "unit")
public void testParseDashes() throws Exception {
Properties props = new Properties();
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse(
"jdbc:clickhouse://foo.yandex:1337/db-name-with-dash", new Properties());
ClickHouseProperties chProps = ClickhouseJdbcUrlParser
.parse("jdbc:clickhouse://foo.yandex:1337/db-name-with-dash", new Properties());
Assert.assertEquals(chProps.getDatabase(), "db-name-with-dash");
}

@Test(groups = "unit")
public void testParseTrailingSlash() throws Exception {
Properties props = new Properties();
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse(
"jdbc:clickhouse://foo.yandex:1337/", new Properties());
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse("jdbc:clickhouse://foo.yandex:1337/",
new Properties());
Assert.assertEquals(chProps.getDatabase(), "default");
}

@Test(groups = "unit")
public void testParseDbInPathAndProps() throws Exception {
ClickHouseProperties props = new ClickHouseProperties();
props.setDatabase("database-name");
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse(
"jdbc:clickhouse://foo.yandex:1337/database-name", props.asProperties());
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse("jdbc:clickhouse://foo.yandex:1337/database-name",
props.asProperties());
Assert.assertEquals(chProps.getDatabase(), "database-name");
Assert.assertEquals(chProps.getPath(), "/");
}
Expand All @@ -40,8 +43,8 @@ public void testParseDbInPathAndProps2() throws Exception {
ClickHouseProperties props = new ClickHouseProperties();
props.setDatabase("database-name");
props.setUsePathAsDb(false);
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse(
"jdbc:clickhouse://foo.yandex:1337/database-name", props.asProperties());
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse("jdbc:clickhouse://foo.yandex:1337/database-name",
props.asProperties());
Assert.assertEquals(chProps.getDatabase(), "database-name");
Assert.assertEquals(chProps.getPath(), "/database-name");
}
Expand All @@ -50,8 +53,8 @@ public void testParseDbInPathAndProps2() throws Exception {
public void testParsePathDefaultDb() throws Exception {
ClickHouseProperties props = new ClickHouseProperties();
props.setPath("/path");
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse(
"jdbc:clickhouse://foo.yandex:1337/", props.asProperties());
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse("jdbc:clickhouse://foo.yandex:1337/",
props.asProperties());
Assert.assertEquals(chProps.getDatabase(), "default");
Assert.assertEquals(chProps.getPath(), "/path");
}
Expand All @@ -61,17 +64,17 @@ public void testParsePathDefaultDb2() throws Exception {
ClickHouseProperties props = new ClickHouseProperties();
props.setPath("/path");
props.setUsePathAsDb(false);
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse(
"jdbc:clickhouse://foo.yandex:1337", props.asProperties());
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse("jdbc:clickhouse://foo.yandex:1337",
props.asProperties());
Assert.assertEquals(chProps.getDatabase(), "default");
Assert.assertEquals(chProps.getPath(), "/"); //uri takes priority
Assert.assertEquals(chProps.getPath(), "/"); // uri takes priority
}

@Test(groups = "unit")
public void testParsePathAndDb() throws Exception {
ClickHouseProperties props = new ClickHouseProperties();
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse(
"jdbc:clickhouse://foo.yandex:1337/db?database=dbname", props.asProperties());
ClickHouseProperties chProps = ClickhouseJdbcUrlParser
.parse("jdbc:clickhouse://foo.yandex:1337/db?database=dbname", props.asProperties());
Assert.assertEquals(chProps.getDatabase(), "db");
Assert.assertEquals(chProps.getPath(), "/");
}
Expand All @@ -80,10 +83,33 @@ public void testParsePathAndDb() throws Exception {
public void testParsePathAndDb2() throws Exception {
ClickHouseProperties props = new ClickHouseProperties();
props.setUsePathAsDb(false);
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse(
"jdbc:clickhouse://foo.yandex:1337/db?database=dbname", props.asProperties());
ClickHouseProperties chProps = ClickhouseJdbcUrlParser
.parse("jdbc:clickhouse://foo.yandex:1337/db?database=dbname", props.asProperties());
Assert.assertEquals(chProps.getDatabase(), "dbname");
Assert.assertEquals(chProps.getPath(), "/db");
}

@Test(groups = "unit")
public void testParseCredentials() throws Exception {
ClickHouseProperties props = new ClickHouseProperties();
props.setUser("default1");
props.setPassword("password1");
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse("jdbc:clickhouse://user:a:[email protected]/test",
props.asProperties());
Assert.assertEquals(chProps.getUser(), "user");
Assert.assertEquals(chProps.getPassword(), "a:passwd");
}

@Test(groups = "unit")
public void testParseProtocol() throws Exception {
ClickHouseProperties props = new ClickHouseProperties();
ClickHouseProperties chProps = ClickhouseJdbcUrlParser.parse("jdbc:clickhouse://foo.ch/test",
props.asProperties());
Assert.assertEquals(chProps.getProtocol(), ClickHouseProtocol.HTTP);
Assert.assertEquals(chProps.getPort(), ClickHouseProtocol.HTTP.getDefaultPort());

chProps = ClickhouseJdbcUrlParser.parse("jdbc:clickhouse://foo.ch/test?protocol=grpc", props.asProperties());
Assert.assertEquals(chProps.getProtocol(), ClickHouseProtocol.GRPC);
Assert.assertEquals(chProps.getPort(), ClickHouseProtocol.GRPC.getDefaultPort());
}
}

0 comments on commit 4f93201

Please sign in to comment.