diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClientBuilder.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClientBuilder.java index df32d81b8..4008a86cf 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClientBuilder.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClientBuilder.java @@ -4,13 +4,10 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.Properties; import java.util.ServiceLoader; -import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; -import com.clickhouse.client.config.ClickHouseClientOption; import com.clickhouse.client.config.ClickHouseOption; import com.clickhouse.client.config.ClickHouseDefaults; @@ -186,33 +183,6 @@ public ClickHouseClientBuilder options(Map optio return this; } - /** - * Sets options. - * - * @param options options - * @return this builder - */ - public ClickHouseClientBuilder options(Properties options) { - if (options != null && !options.isEmpty()) { - for (Entry e : options.entrySet()) { - Object key = e.getKey(); - Object value = e.getValue(); - if (key == null || value == null) { - continue; - } - - ClickHouseClientOption o = ClickHouseClientOption.fromKey(key.toString()); - if (o != null) { - this.options.put(o, ClickHouseOption.fromString(value.toString(), o.getValueType())); - } - } - - resetConfig(); - } - - return this; - } - /* * public ClickHouseClientBuilder addUserType(Object... userTypeMappers) { * resetConfig(); return this; } diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseDefaults.java b/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseDefaults.java index 1e47c0d4a..feb36664e 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseDefaults.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseDefaults.java @@ -3,7 +3,6 @@ import java.io.Serializable; import com.clickhouse.client.ClickHouseChecker; -import com.clickhouse.client.ClickHouseCompression; import com.clickhouse.client.ClickHouseFormat; import com.clickhouse.client.ClickHouseProtocol; @@ -87,7 +86,7 @@ public enum ClickHouseDefaults implements ClickHouseOption { private final String key; private final Serializable defaultValue; - private final Class clazz; + private final Class clazz; private final String description; ClickHouseDefaults(String key, T defaultValue, String description) { @@ -118,7 +117,7 @@ public String getPrefix() { } @Override - public Class getValueType() { + public Class getValueType() { return clazz; } } diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseOption.java b/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseOption.java index a0eeffc2a..9e5dddcd5 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseOption.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseOption.java @@ -164,7 +164,7 @@ default String getPrefix() { * * @return value type of the option, defaults to String */ - Class getValueType(); + Class getValueType(); /** * Gets name of the option. diff --git a/clickhouse-client/src/test/java/com/clickhouse/client/config/ClickHouseConfigOptionTest.java b/clickhouse-client/src/test/java/com/clickhouse/client/config/ClickHouseConfigOptionTest.java index 6bfe97ef8..e93f30889 100644 --- a/clickhouse-client/src/test/java/com/clickhouse/client/config/ClickHouseConfigOptionTest.java +++ b/clickhouse-client/src/test/java/com/clickhouse/client/config/ClickHouseConfigOptionTest.java @@ -8,106 +8,110 @@ import com.clickhouse.client.ClickHouseFormat; public class ClickHouseConfigOptionTest { - static enum ClickHouseTestOption implements ClickHouseOption { - STR("string_option", "string", "string option"), - STR0("string_option0", "string0", "string option without environment variable support"), - STR1("string_option0", "string1", "string option without environment variable and system property support"), - INT("integer_option", 2333, "integer option"), - INT0("integer_option0", 23330, "integer option without environment variable support"), - INT1("integer_option1", 23331, "integer option without environment variable and system property support"), - BOOL("boolean_option", false, "boolean option"), - BOOL0("boolean_option0", true, "boolean option without environment variable support"), - BOOL1("boolean_option1", false, "boolean option without environment variable and system property support"); - - private final String key; - private final Serializable defaultValue; - private final Class clazz; - private final String description; - - ClickHouseTestOption(String key, T defaultValue, String description) { - this.key = ClickHouseChecker.nonNull(key, "key"); - this.defaultValue = defaultValue; - this.clazz = defaultValue.getClass(); - this.description = ClickHouseChecker.nonNull(description, "description"); + static enum ClickHouseTestOption implements ClickHouseOption { + STR("string_option", "string", "string option"), + STR0("string_option0", "string0", "string option without environment variable support"), + STR1("string_option0", "string1", + "string option without environment variable and system property support"), + INT("integer_option", 2333, "integer option"), + INT0("integer_option0", 23330, "integer option without environment variable support"), + INT1("integer_option1", 23331, + "integer option without environment variable and system property support"), + BOOL("boolean_option", false, "boolean option"), + BOOL0("boolean_option0", true, "boolean option without environment variable support"), + BOOL1("boolean_option1", false, + "boolean option without environment variable and system property support"); + + private final String key; + private final Serializable defaultValue; + private final Class clazz; + private final String description; + + ClickHouseTestOption(String key, T defaultValue, String description) { + this.key = ClickHouseChecker.nonNull(key, "key"); + this.defaultValue = defaultValue; + this.clazz = defaultValue.getClass(); + this.description = ClickHouseChecker.nonNull(description, "description"); + } + + @Override + public String getKey() { + return key; + } + + @Override + public Serializable getDefaultValue() { + return defaultValue; + } + + @Override + public Class getValueType() { + return clazz; + } + + @Override + public String getDescription() { + return description; + } } - @Override - public String getKey() { - return key; + @Test(groups = { "unit" }) + public void testFromString() { + Assert.assertThrows(IllegalArgumentException.class, + () -> ClickHouseOption.fromString(null, String.class)); + Assert.assertEquals(ClickHouseOption.fromString("", String.class), ""); + + Assert.assertEquals(ClickHouseOption.fromString("", Boolean.class), Boolean.FALSE); + Assert.assertEquals(ClickHouseOption.fromString("Yes", Boolean.class), Boolean.FALSE); + Assert.assertEquals(ClickHouseOption.fromString("1", Boolean.class), Boolean.TRUE); + Assert.assertEquals(ClickHouseOption.fromString("true", Boolean.class), Boolean.TRUE); + Assert.assertEquals(ClickHouseOption.fromString("True", Boolean.class), Boolean.TRUE); + + Assert.assertEquals(ClickHouseOption.fromString("", Integer.class), Integer.valueOf(0)); + Assert.assertEquals(ClickHouseOption.fromString("0", Integer.class), Integer.valueOf(0)); + Assert.assertThrows(IllegalArgumentException.class, + () -> ClickHouseOption.fromString(null, Integer.class)); + + Assert.assertEquals(ClickHouseOption.fromString("0.1", Float.class), Float.valueOf(0.1F)); + Assert.assertEquals(ClickHouseOption.fromString("NaN", Float.class), Float.valueOf(Float.NaN)); + + Assert.assertEquals(ClickHouseOption.fromString("Map", ClickHouseDataType.class), + ClickHouseDataType.Map); + Assert.assertEquals(ClickHouseOption.fromString("RowBinary", ClickHouseFormat.class), + ClickHouseFormat.RowBinary); + Assert.assertThrows(IllegalArgumentException.class, + () -> ClickHouseOption.fromString("NonExistFormat", ClickHouseFormat.class)); } - @Override - public Serializable getDefaultValue() { - return defaultValue; + @Test(groups = { "unit" }) + public void testGetEffectiveDefaultValue() { + // environment variables are set in pom.xml + Assert.assertEquals(ClickHouseTestOption.STR.getEffectiveDefaultValue(), + ClickHouseTestOption.STR.getDefaultValueFromEnvVar().get()); + Assert.assertEquals(ClickHouseTestOption.INT.getEffectiveDefaultValue(), + Integer.parseInt(ClickHouseTestOption.INT.getDefaultValueFromEnvVar().get())); + Assert.assertEquals(ClickHouseTestOption.BOOL.getEffectiveDefaultValue(), + Boolean.valueOf(ClickHouseTestOption.BOOL.getDefaultValueFromEnvVar().get())); + + String sv = "system.property"; + int iv = 12345; + boolean bv = true; + System.setProperty(ClickHouseTestOption.STR0.getPrefix().toLowerCase() + "_" + + ClickHouseTestOption.STR0.name().toLowerCase(), sv); + System.setProperty(ClickHouseTestOption.INT0.getPrefix().toLowerCase() + "_" + + ClickHouseTestOption.INT0.name().toLowerCase(), String.valueOf(iv)); + System.setProperty(ClickHouseTestOption.BOOL0.getPrefix().toLowerCase() + "_" + + ClickHouseTestOption.BOOL0.name().toLowerCase(), String.valueOf(bv)); + + Assert.assertEquals(ClickHouseTestOption.STR0.getEffectiveDefaultValue(), sv); + Assert.assertEquals(ClickHouseTestOption.INT0.getEffectiveDefaultValue(), iv); + Assert.assertEquals(ClickHouseTestOption.BOOL0.getEffectiveDefaultValue(), bv); + + Assert.assertEquals(ClickHouseTestOption.STR1.getEffectiveDefaultValue(), + ClickHouseTestOption.STR1.getDefaultValue()); + Assert.assertEquals(ClickHouseTestOption.INT1.getEffectiveDefaultValue(), + ClickHouseTestOption.INT1.getDefaultValue()); + Assert.assertEquals(ClickHouseTestOption.BOOL1.getEffectiveDefaultValue(), + ClickHouseTestOption.BOOL1.getDefaultValue()); } - - @Override - public Class getValueType() { - return clazz; - } - - @Override - public String getDescription() { - return description; - } - } - - @Test(groups = { "unit" }) - public void testFromString() { - Assert.assertThrows(IllegalArgumentException.class, - () -> ClickHouseOption.fromString(null, String.class)); - Assert.assertEquals(ClickHouseOption.fromString("", String.class), ""); - - Assert.assertEquals(ClickHouseOption.fromString("", Boolean.class), Boolean.FALSE); - Assert.assertEquals(ClickHouseOption.fromString("Yes", Boolean.class), Boolean.FALSE); - Assert.assertEquals(ClickHouseOption.fromString("1", Boolean.class), Boolean.TRUE); - Assert.assertEquals(ClickHouseOption.fromString("true", Boolean.class), Boolean.TRUE); - Assert.assertEquals(ClickHouseOption.fromString("True", Boolean.class), Boolean.TRUE); - - Assert.assertEquals(ClickHouseOption.fromString("", Integer.class), Integer.valueOf(0)); - Assert.assertEquals(ClickHouseOption.fromString("0", Integer.class), Integer.valueOf(0)); - Assert.assertThrows(IllegalArgumentException.class, - () -> ClickHouseOption.fromString(null, Integer.class)); - - Assert.assertEquals(ClickHouseOption.fromString("0.1", Float.class), Float.valueOf(0.1F)); - Assert.assertEquals(ClickHouseOption.fromString("NaN", Float.class), Float.valueOf(Float.NaN)); - - Assert.assertEquals(ClickHouseOption.fromString("Map", ClickHouseDataType.class), ClickHouseDataType.Map); - Assert.assertEquals(ClickHouseOption.fromString("RowBinary", ClickHouseFormat.class), - ClickHouseFormat.RowBinary); - Assert.assertThrows(IllegalArgumentException.class, - () -> ClickHouseOption.fromString("NonExistFormat", ClickHouseFormat.class)); - } - - @Test(groups = { "unit" }) - public void testGetEffectiveDefaultValue() { - // environment variables are set in pom.xml - Assert.assertEquals(ClickHouseTestOption.STR.getEffectiveDefaultValue(), - ClickHouseTestOption.STR.getDefaultValueFromEnvVar().get()); - Assert.assertEquals(ClickHouseTestOption.INT.getEffectiveDefaultValue(), - Integer.parseInt(ClickHouseTestOption.INT.getDefaultValueFromEnvVar().get())); - Assert.assertEquals(ClickHouseTestOption.BOOL.getEffectiveDefaultValue(), - Boolean.valueOf(ClickHouseTestOption.BOOL.getDefaultValueFromEnvVar().get())); - - String sv = "system.property"; - int iv = 12345; - boolean bv = true; - System.setProperty(ClickHouseTestOption.STR0.getPrefix().toLowerCase() + "_" - + ClickHouseTestOption.STR0.name().toLowerCase(), sv); - System.setProperty(ClickHouseTestOption.INT0.getPrefix().toLowerCase() + "_" - + ClickHouseTestOption.INT0.name().toLowerCase(), String.valueOf(iv)); - System.setProperty(ClickHouseTestOption.BOOL0.getPrefix().toLowerCase() + "_" - + ClickHouseTestOption.BOOL0.name().toLowerCase(), String.valueOf(bv)); - - Assert.assertEquals(ClickHouseTestOption.STR0.getEffectiveDefaultValue(), sv); - Assert.assertEquals(ClickHouseTestOption.INT0.getEffectiveDefaultValue(), iv); - Assert.assertEquals(ClickHouseTestOption.BOOL0.getEffectiveDefaultValue(), bv); - - Assert.assertEquals(ClickHouseTestOption.STR1.getEffectiveDefaultValue(), - ClickHouseTestOption.STR1.getDefaultValue()); - Assert.assertEquals(ClickHouseTestOption.INT1.getEffectiveDefaultValue(), - ClickHouseTestOption.INT1.getDefaultValue()); - Assert.assertEquals(ClickHouseTestOption.BOOL1.getEffectiveDefaultValue(), - ClickHouseTestOption.BOOL1.getDefaultValue()); - } } diff --git a/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/config/ClickHouseGrpcOption.java b/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/config/ClickHouseGrpcOption.java index b3f39f214..8c5c296ff 100644 --- a/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/config/ClickHouseGrpcOption.java +++ b/clickhouse-grpc-client/src/main/java/com/clickhouse/client/grpc/config/ClickHouseGrpcOption.java @@ -37,7 +37,7 @@ public enum ClickHouseGrpcOption implements ClickHouseOption { private final String key; private final Serializable defaultValue; - private final Class clazz; + private final Class clazz; private final String description; ClickHouseGrpcOption(String key, T defaultValue, String description) { @@ -63,7 +63,7 @@ public String getKey() { } @Override - public Class getValueType() { + public Class getValueType() { return clazz; } } diff --git a/clickhouse-http-client/src/main/java/com/clickhouse/client/http/config/ClickHouseHttpOption.java b/clickhouse-http-client/src/main/java/com/clickhouse/client/http/config/ClickHouseHttpOption.java index cd1ce8500..cdf90592f 100644 --- a/clickhouse-http-client/src/main/java/com/clickhouse/client/http/config/ClickHouseHttpOption.java +++ b/clickhouse-http-client/src/main/java/com/clickhouse/client/http/config/ClickHouseHttpOption.java @@ -44,7 +44,7 @@ public enum ClickHouseHttpOption implements ClickHouseOption { private final String key; private final Serializable defaultValue; - private final Class clazz; + private final Class clazz; private final String description; ClickHouseHttpOption(String key, T defaultValue, String description) { @@ -70,7 +70,7 @@ public String getKey() { } @Override - public Class getValueType() { + public Class getValueType() { return clazz; } } diff --git a/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/ClickHouseDriver.java b/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/ClickHouseDriver.java index 2e3bdc3b5..4d4fef910 100644 --- a/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/ClickHouseDriver.java +++ b/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/ClickHouseDriver.java @@ -1,5 +1,6 @@ package com.clickhouse.jdbc; +import java.io.Serializable; import java.sql.Driver; import java.sql.DriverManager; import java.sql.DriverPropertyInfo; @@ -7,11 +8,13 @@ import java.sql.SQLFeatureNotSupportedException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.ServiceLoader; -import java.util.WeakHashMap; +import java.util.Map.Entry; import com.clickhouse.client.ClickHouseClient; import com.clickhouse.client.ClickHouseVersion; @@ -38,6 +41,8 @@ public class ClickHouseDriver implements Driver { private static final Logger log = LoggerFactory.getLogger(ClickHouseDriver.class); + private static final Map clientSpecificOptions; + static final String driverVersionString; static final ClickHouseVersion driverVersion; static final ClickHouseVersion specVersion; @@ -56,6 +61,50 @@ public class ClickHouseDriver implements Driver { } log.debug("ClickHouse Driver %s(JDBC: %s) registered", driverVersion, specVersion); + + // client-specific options + Map m = new LinkedHashMap<>(); + try { + for (ClickHouseClient c : ServiceLoader.load(ClickHouseClient.class, + Thread.currentThread().getContextClassLoader())) { + Class clazz = c.getOptionClass(); + if (clazz == null || clazz == ClickHouseClientOption.class) { + continue; + } + for (ClickHouseOption o : clazz.getEnumConstants()) { + m.put(o.getKey(), o); + } + } + } catch (Exception e) { + log.warn("Failed to load client-specific options", e); + } + + clientSpecificOptions = Collections.unmodifiableMap(m); + } + + public static Map toClientOptions(Properties props) { + if (props == null || props.isEmpty()) { + return Collections.emptyMap(); + } + + Map options = new HashMap<>(); + for (Entry e : props.entrySet()) { + if (e.getKey() == null || e.getValue() == null) { + continue; + } + + String key = e.getKey().toString(); + ClickHouseOption o = ClickHouseClientOption.fromKey(key); + if (o == null) { + o = clientSpecificOptions.get(key); + } + + if (o != null) { + options.put(o, ClickHouseOption.fromString(e.getValue().toString(), o.getValueType())); + } + } + + return options; } private DriverPropertyInfo create(ClickHouseOption option, Properties props) { @@ -109,19 +158,9 @@ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws result.add(create(option, info)); } - // client-specific configuration - try { - for (ClickHouseClient c : ServiceLoader.load(ClickHouseClient.class, getClass().getClassLoader())) { - Class clazz = c.getOptionClass(); - if (clazz == null || clazz == ClickHouseClientOption.class) { - continue; - } - for (ClickHouseOption option : clazz.getEnumConstants()) { - result.add(create(option, info)); - } - } - } catch (Exception e) { - log.warn("Failed to load client-specific configuration", e); + // and then client-specific options + for (ClickHouseOption option : clientSpecificOptions.values()) { + result.add(create(option, info)); } DriverPropertyInfo custom = new DriverPropertyInfo(ClickHouseJdbcUrlParser.PROP_JDBC_COMPLIANT, "true"); diff --git a/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/ClickHouseConnectionImpl.java b/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/ClickHouseConnectionImpl.java index 1a7a9e23a..1b273fd22 100644 --- a/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/ClickHouseConnectionImpl.java +++ b/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/ClickHouseConnectionImpl.java @@ -54,6 +54,7 @@ import com.clickhouse.jdbc.ClickHouseClob; import com.clickhouse.jdbc.ClickHouseConnection; import com.clickhouse.jdbc.ClickHouseDatabaseMetaData; +import com.clickhouse.jdbc.ClickHouseDriver; import com.clickhouse.jdbc.ClickHouseStatement; import com.clickhouse.jdbc.ClickHouseXml; import com.clickhouse.jdbc.JdbcParameterizedQuery; @@ -170,7 +171,7 @@ public ClickHouseConnectionImpl(String url, Properties properties) throws SQLExc jvmTimeZone = TimeZone.getDefault(); - client = ClickHouseClient.builder().options(connInfo.getProperties()) + client = ClickHouseClient.builder().options(ClickHouseDriver.toClientOptions(connInfo.getProperties())) .nodeSelector(ClickHouseNodeSelector.of(node.getProtocol())).build(); clientRequest = client.connect(node); ClickHouseConfig config = clientRequest.getConfig();