From 30d84af71041d46a3aef977aee67357d168277d7 Mon Sep 17 00:00:00 2001 From: Sergey Chernov Date: Mon, 18 Aug 2025 13:40:42 -0700 Subject: [PATCH 1/5] added common settings to reduce code duplication --- .../client/api/insert/InsertSettings.java | 85 ++++--- .../client/api/internal/CommonSettings.java | 217 ++++++++++++++++++ .../client/api/query/QuerySettings.java | 118 +++++----- .../jdbc/PreparedStatementTest.java | 1 - 4 files changed, 313 insertions(+), 108 deletions(-) create mode 100644 client-v2/src/main/java/com/clickhouse/client/api/internal/CommonSettings.java diff --git a/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java b/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java index 6179b09ce..966d25302 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java @@ -1,32 +1,30 @@ package com.clickhouse.client.api.insert; -import com.clickhouse.client.ClickHouseProtocol; import com.clickhouse.client.api.Client; import com.clickhouse.client.api.ClientConfigProperties; -import com.clickhouse.client.api.enums.Protocol; -import com.clickhouse.client.api.internal.ValidationUtils; +import com.clickhouse.client.api.internal.CommonSettings; import org.apache.hc.core5.http.HttpHeaders; import java.util.Collection; -import java.util.HashMap; import java.util.Map; public class InsertSettings { private static final int DEFAULT_INPUT_STREAM_BATCH_SIZE = 8196; private int inputStreamCopyBufferSize; - private String operationId; - Map rawSettings; + CommonSettings settings; public InsertSettings() { - rawSettings = new HashMap<>(); + settings = new CommonSettings(); setDefaults(); } public InsertSettings(Map settings) { - rawSettings = new HashMap<>(); + this.settings = new CommonSettings(); setDefaults(); - rawSettings.putAll(settings); + for (Map.Entry entry : settings.entrySet()) { + this.settings.setOption(entry.getKey(), entry.getValue()); + } } private void setDefaults() {// Default settings, for now a very small list @@ -40,7 +38,7 @@ private void setDefaults() {// Default settings, for now a very small list * @return configuration option value */ public Object getOption(String option) { - return rawSettings.get(option); + return settings.getOption(option); } /** @@ -51,10 +49,7 @@ public Object getOption(String option) { * @param value - configuration option value */ public InsertSettings setOption(String option, Object value) { - rawSettings.put(option, value); - if (option.equals(ClientConfigProperties.PRODUCT_NAME.getKey())) { - rawSettings.put(ClientConfigProperties.CLIENT_NAME.getKey(), value); - } + settings.setOption(option, value); return this; } @@ -64,7 +59,7 @@ public InsertSettings setOption(String option, Object value) { * @return all settings */ public Map getAllSettings() { - return rawSettings; + return settings.getAllSettings(); } /** @@ -79,14 +74,14 @@ public InsertSettings setDeduplicationToken(String token) { } public String getQueryId() { - return (String) rawSettings.get(ClientConfigProperties.QUERY_ID.getKey()); + return settings.getQueryId(); } /** * Sets the query id. This id will be sent to the server and can be used to identify the query. */ public InsertSettings setQueryId(String queryId) { - rawSettings.put(ClientConfigProperties.QUERY_ID.getKey(), queryId); + settings.setQueryId(queryId); return this; } @@ -108,7 +103,7 @@ public InsertSettings setInputStreamCopyBufferSize(int size) { * Should not be called directly. */ public String getOperationId() { - return this.operationId; + return settings.getOperationId(); } /** @@ -118,7 +113,7 @@ public String getOperationId() { * @param operationId - operation id */ public InsertSettings setOperationId(String operationId) { - this.operationId = operationId; + settings.setOperationId(operationId); return this; } @@ -126,13 +121,12 @@ public InsertSettings setOperationId(String operationId) { * Sets database to be used for a request. */ public InsertSettings setDatabase(String database) { - ValidationUtils.checkNonBlank(database, "database"); - rawSettings.put("database", database); + settings.setDatabase(database); return this; } public String getDatabase() { - return (String) rawSettings.get("database"); + return settings.getDatabase(); } /** @@ -141,12 +135,12 @@ public String getDatabase() { * @param enabled - indicates if client request compression is enabled */ public InsertSettings compressClientRequest(boolean enabled) { - this.rawSettings.put(ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getKey(), enabled); + settings.setOption(ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getKey(), enabled); return this; } public InsertSettings useHttpCompression(boolean enabled) { - this.rawSettings.put(ClientConfigProperties.USE_HTTP_COMPRESSION.getKey(), enabled); + settings.setOption(ClientConfigProperties.USE_HTTP_COMPRESSION.getKey(), enabled); return this; } @@ -156,48 +150,50 @@ public InsertSettings useHttpCompression(boolean enabled) { * @param enabled - if application provides compressed data */ public InsertSettings appCompressedData(boolean enabled, String compressionMethod) { - this.rawSettings.put(ClientConfigProperties.APP_COMPRESSED_DATA.getKey(), enabled); + settings.setOption(ClientConfigProperties.APP_COMPRESSED_DATA.getKey(), enabled); useHttpCompression(true); httpHeader(HttpHeaders.CONTENT_ENCODING, compressionMethod); return this; } public boolean isClientRequestEnabled() { - return (Boolean) rawSettings.get("decompress"); + return (Boolean) settings.getOption(ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getKey()); } /** * Defines list of headers that should be sent with current request. The Client will use a header value * defined in {@code headers} instead of any other. * - * @see Client.Builder#httpHeaders(Map) - * @param key - header name. + * @param key - header name. * @param value - header value. * @return same instance of the builder + * @see Client.Builder#httpHeaders(Map) */ public InsertSettings httpHeader(String key, String value) { - rawSettings.put(ClientConfigProperties.httpHeader(key), value); + settings.httpHeader(key, value); return this; } /** * {@see #httpHeader(String, String)} but for multiple values. - * @param key - name of the header + * + * @param key - name of the header * @param values - collection of values * @return same instance of the builder */ public InsertSettings httpHeader(String key, Collection values) { - rawSettings.put(ClientConfigProperties.httpHeader(key), ClientConfigProperties.commaSeparated(values)); + settings.httpHeader(key, values); return this; } /** * {@see #httpHeader(String, String)} but for multiple headers. + * * @param headers - map of headers * @return same instance of the builder */ public InsertSettings httpHeaders(Map headers) { - headers.forEach(this::httpHeader); + settings.httpHeaders(headers); return this; } @@ -206,24 +202,25 @@ public InsertSettings httpHeaders(Map headers) { * defined in {@code settings} instead of any other. * Operation settings may override these values. * - * @see Client.Builder#serverSetting(String, Collection) - * @param name - name of the setting + * @param name - name of the setting * @param value - value of the setting * @return same instance of the builder + * @see Client.Builder#serverSetting(String, Collection) */ public InsertSettings serverSetting(String name, String value) { - rawSettings.put(ClientConfigProperties.serverSetting(name), value); + settings.serverSetting(name, value); return this; } /** * {@see #serverSetting(String, String)} but for multiple values. - * @param name - name of the setting without special prefix + * + * @param name - name of the setting without special prefix * @param values - collection of values * @return same instance of the builder */ public InsertSettings serverSetting(String name, Collection values) { - rawSettings.put(ClientConfigProperties.serverSetting(name), ClientConfigProperties.commaSeparated(values)); + settings.serverSetting(name, values); return this; } @@ -233,7 +230,7 @@ public InsertSettings serverSetting(String name, Collection values) { * @param dbRoles */ public InsertSettings setDBRoles(Collection dbRoles) { - rawSettings.put(ClientConfigProperties.SESSION_DB_ROLES.getKey(), dbRoles); + settings.setDBRoles(dbRoles); return this; } @@ -243,25 +240,21 @@ public InsertSettings setDBRoles(Collection dbRoles) { * @return list of DB roles */ public Collection getDBRoles() { - return (Collection) rawSettings.get(ClientConfigProperties.SESSION_DB_ROLES.getKey()); + return settings.getDBRoles(); } /** * Sets the comment that will be added to the query log record associated with the query. + * * @param logComment - comment to be added to the log * @return same instance of the builder */ public InsertSettings logComment(String logComment) { - this.logComment = logComment; - if (logComment != null && !logComment.isEmpty()) { - rawSettings.put(ClientConfigProperties.SETTING_LOG_COMMENT.getKey(), logComment); - } + settings.logComment(logComment); return this; } - private String logComment = null; - public String getLogComment() { - return logComment; + return settings.getLogComment(); } } diff --git a/client-v2/src/main/java/com/clickhouse/client/api/internal/CommonSettings.java b/client-v2/src/main/java/com/clickhouse/client/api/internal/CommonSettings.java new file mode 100644 index 000000000..3b415e311 --- /dev/null +++ b/client-v2/src/main/java/com/clickhouse/client/api/internal/CommonSettings.java @@ -0,0 +1,217 @@ +package com.clickhouse.client.api.internal; + +import com.clickhouse.client.api.Client; +import com.clickhouse.client.api.ClientConfigProperties; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Class representing very common logic across all setting objects + * like setting database, getting option + * + */ +public class CommonSettings { + + private String operationId; + private String logComment; + protected Map settings; + + public CommonSettings() { + settings = new HashMap<>(); + } + + /** + * Gets a configuration option. + * + * @param option - configuration option name + * @return configuration option value + */ + public Object getOption(String option) { + return settings.get(option); + } + + public boolean hasOption(String option) { + return settings.containsKey(option); + } + + /** + * Sets a configuration option. This method can be used to set any configuration option. + * There is no specific validation is done on the key or value. + * + * @param option - configuration option name + * @param value - configuration option value + */ + public CommonSettings setOption(String option, Object value) { + settings.put(option, value); + if (option.equals(ClientConfigProperties.PRODUCT_NAME.getKey())) { + settings.put(ClientConfigProperties.CLIENT_NAME.getKey(), value); + } + return this; + } + + public CommonSettings resetOption(String option) { + settings.remove(option); + return this; + } + + /** + * Get all settings as an unmodifiable map. + * + * @return all settings + */ + public Map getAllSettings() { + return settings; + } + + public String getQueryId() { + return (String) settings.get(ClientConfigProperties.QUERY_ID.getKey()); + } + + /** + * Sets the query id. This id will be sent to the server and can be used to identify the query. + */ + public CommonSettings setQueryId(String queryId) { + settings.put(ClientConfigProperties.QUERY_ID.getKey(), queryId); + return this; + } + + /** + * Operation id. Used internally to register new operation. + * Should not be called directly. + */ + public String getOperationId() { + return this.operationId; + } + + /** + * Operation id. Used internally to register new operation. + * Should not be called directly. + * + * @param operationId - operation id + */ + public CommonSettings setOperationId(String operationId) { + this.operationId = operationId; + return this; + } + + /** + * Sets database to be used for a request. + */ + public CommonSettings setDatabase(String database) { + ValidationUtils.checkNonBlank(database, ClientConfigProperties.DATABASE.getKey()); + settings.put(ClientConfigProperties.DATABASE.getKey(), database); + return this; + } + + public String getDatabase() { + return (String) settings.get(ClientConfigProperties.DATABASE.getKey()); + } + + /** + * Defines list of headers that should be sent with current request. The Client will use a header value + * defined in {@code headers} instead of any other. + * + * @see Client.Builder#httpHeaders(Map) + * @param key - header name. + * @param value - header value. + * @return same instance of the builder + */ + public CommonSettings httpHeader(String key, String value) { + settings.put(ClientConfigProperties.httpHeader(key), value); + return this; + } + + /** + * {@see #httpHeader(String, String)} but for multiple values. + * @param key - name of the header + * @param values - collection of values + * @return same instance of the builder + */ + public CommonSettings httpHeader(String key, Collection values) { + settings.put(ClientConfigProperties.httpHeader(key), ClientConfigProperties.commaSeparated(values)); + return this; + } + + /** + * {@see #httpHeader(String, String)} but for multiple headers. + * @param headers - map of headers + * @return same instance of the builder + */ + public CommonSettings httpHeaders(Map headers) { + headers.forEach(this::httpHeader); + return this; + } + + /** + * Defines list of server settings that should be sent with each request. The Client will use a setting value + * defined in {@code settings} instead of any other. + * Operation settings may override these values. + * + * @see Client.Builder#serverSetting(String, Collection) + * @param name - name of the setting + * @param value - value of the setting + * @return same instance of the builder + */ + public CommonSettings serverSetting(String name, String value) { + settings.put(ClientConfigProperties.serverSetting(name), value); + return this; + } + + /** + * {@see #serverSetting(String, String)} but for multiple values. + * @param name - name of the setting without special prefix + * @param values - collection of values + * @return same instance of the builder + */ + public CommonSettings serverSetting(String name, Collection values) { + settings.put(ClientConfigProperties.serverSetting(name), ClientConfigProperties.commaSeparated(values)); + return this; + } + + /** + * Sets DB roles for an operation. Roles that were set by {@link Client#setDBRoles(Collection)} will be overridden. + * + * @param dbRoles + */ + public CommonSettings setDBRoles(Collection dbRoles) { + settings.put(ClientConfigProperties.SESSION_DB_ROLES.getKey(), dbRoles); + return this; + } + + /** + * Gets DB roles for an operation. + * + * @return list of DB roles + */ + public Collection getDBRoles() { + return (Collection) settings.get(ClientConfigProperties.SESSION_DB_ROLES.getKey()); + } + + /** + * Sets the comment that will be added to the query log record associated with the query. + * @param logComment - comment to be added to the log + * @return same instance of the builder + */ + public CommonSettings logComment(String logComment) { + this.logComment = logComment; + if (logComment != null && !logComment.isEmpty()) { + settings.put(ClientConfigProperties.SETTING_LOG_COMMENT.getKey(), logComment); + } + return this; + } + + public String getLogComment() { + return logComment; + } + + public CommonSettings copyAndMerge(CommonSettings override) { + CommonSettings copy = new CommonSettings(); + copy.settings.putAll(settings); + copy.logComment = logComment; + copy.settings.putAll(override.settings); + + return copy; + } +} diff --git a/client-v2/src/main/java/com/clickhouse/client/api/query/QuerySettings.java b/client-v2/src/main/java/com/clickhouse/client/api/query/QuerySettings.java index 16580d129..e1b8cbce9 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/query/QuerySettings.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/query/QuerySettings.java @@ -3,6 +3,7 @@ import com.clickhouse.client.api.Client; import com.clickhouse.client.api.ClientConfigProperties; +import com.clickhouse.client.api.internal.CommonSettings; import com.clickhouse.client.api.internal.ServerSettings; import com.clickhouse.client.api.internal.ValidationUtils; import com.clickhouse.data.ClickHouseFormat; @@ -14,19 +15,26 @@ /** *

Query settings class represents a set of settings that can be used to customize query execution.

- * */ public class QuerySettings { public static final int MINIMAL_READ_BUFFER_SIZE = 8192; - private final Map rawSettings; + private final CommonSettings settings; - public QuerySettings(Map rawSettings) { - this.rawSettings = rawSettings; + public QuerySettings(Map settings) { + this.settings = new CommonSettings(); + for (Map.Entry entry : settings.entrySet()) { + this.settings.setOption(entry.getKey(), entry.getValue()); + } } + public QuerySettings() { - this(new HashMap<>()); + this.settings = new CommonSettings(); + } + + private QuerySettings(CommonSettings settings) { + this.settings = settings; } /** @@ -34,19 +42,15 @@ public QuerySettings() { * There is no specific validation is done on the key or value. * * @param option - configuration option name - * @param value - configuration option value + * @param value - configuration option value */ public QuerySettings setOption(String option, Object value) { - rawSettings.put(option, value); - if (option.equals(ClientConfigProperties.PRODUCT_NAME.getKey())) { - rawSettings.put(ClientConfigProperties.CLIENT_NAME.getKey(), value); - } - + settings.setOption(option, value); return this; } public QuerySettings resetOption(String option) { - rawSettings.remove(option); + settings.resetOption(option); return this; } @@ -57,7 +61,7 @@ public QuerySettings resetOption(String option) { * @return configuration option value */ public Object getOption(String option) { - return rawSettings.get(option); + return settings.getOption(option); } /** @@ -66,19 +70,19 @@ public Object getOption(String option) { * @return all settings map */ public Map getAllSettings() { - return rawSettings; + return settings.getAllSettings(); } /** * Sets the query id. This id will be sent to the server and can be used to identify the query. */ public QuerySettings setQueryId(String queryId) { - rawSettings.put("query_id", queryId); + settings.setQueryId(queryId); return this; } public String getQueryId() { - return (String) rawSettings.get("query_id"); + return settings.getQueryId(); } /** @@ -88,24 +92,24 @@ public String getQueryId() { public QuerySettings setReadBufferSize(Integer size) { ValidationUtils.checkNotNull(size, "read_buffer_size"); ValidationUtils.checkRange(size, MINIMAL_READ_BUFFER_SIZE, Integer.MAX_VALUE, "read_buffer_size"); - rawSettings.put("read_buffer_size", size); + settings.setOption("read_buffer_size", size); return this; } public Integer getReadBufferSize() { - return (Integer) rawSettings.get("read_buffer_size"); + return (Integer) settings.getOption("read_buffer_size"); } /** * Sets output format for a server response. */ public QuerySettings setFormat(ClickHouseFormat format) { - rawSettings.put("format", format); + settings.setOption("format", format); return this; } public ClickHouseFormat getFormat() { - return (ClickHouseFormat) rawSettings.get("format"); + return (ClickHouseFormat) settings.getOption("format"); } /** @@ -113,93 +117,94 @@ public ClickHouseFormat getFormat() { * If query is not finished in this time then server will send an exception. */ public QuerySettings setMaxExecutionTime(Integer maxExecutionTime) { - rawSettings.put("max_execution_time", maxExecutionTime); + settings.setOption("max_execution_time", maxExecutionTime); return this; } public Integer getMaxExecutionTime() { - return (Integer) rawSettings.get("max_execution_time"); + return (Integer) settings.getOption("max_execution_time"); } /** * Sets database to be used for a request. */ public QuerySettings setDatabase(String database) { - ValidationUtils.checkNonBlank(database, "database"); - rawSettings.put("database", database); + settings.setDatabase(database); return this; } public String getDatabase() { - return (String) rawSettings.get("database"); + return settings.getDatabase(); } /** * Requests the server to wait for the and of the query before sending response. Useful for getting accurate summary. */ public QuerySettings waitEndOfQuery(Boolean waitEndOfQuery) { - serverSetting(ServerSettings.WAIT_END_OF_QUERY, waitEndOfQuery ? "1" : "0"); + serverSetting(ServerSettings.WAIT_END_OF_QUERY, waitEndOfQuery ? "1" : "0"); return this; } public QuerySettings setUseServerTimeZone(Boolean useServerTimeZone) { - if (rawSettings.containsKey(ClientConfigProperties.USE_TIMEZONE.getKey())) { + if (settings.hasOption(ClientConfigProperties.USE_TIMEZONE.getKey())) { throw new ValidationUtils.SettingsValidationException(ClientConfigProperties.USE_SERVER_TIMEZONE.getKey(), "Cannot set both use_time_zone and use_server_time_zone"); } - rawSettings.put(ClientConfigProperties.USE_SERVER_TIMEZONE.getKey(), useServerTimeZone); + settings.setOption(ClientConfigProperties.USE_SERVER_TIMEZONE.getKey(), useServerTimeZone); return this; } public Boolean getUseServerTimeZone() { - return (Boolean) rawSettings.get(ClientConfigProperties.USE_SERVER_TIMEZONE.getKey()); + return (Boolean) settings.getOption(ClientConfigProperties.USE_SERVER_TIMEZONE.getKey()); } public QuerySettings setUseTimeZone(String timeZone) { - if (rawSettings.containsKey(ClientConfigProperties.USE_SERVER_TIMEZONE.getKey())) { + if (settings.hasOption(ClientConfigProperties.USE_SERVER_TIMEZONE.getKey())) { throw new ValidationUtils.SettingsValidationException(ClientConfigProperties.USE_TIMEZONE.getKey(), "Cannot set both use_time_zone and use_server_time_zone"); } - rawSettings.put(ClientConfigProperties.USE_TIMEZONE.getKey(), TimeZone.getTimeZone(timeZone)); + settings.setOption(ClientConfigProperties.USE_TIMEZONE.getKey(), TimeZone.getTimeZone(timeZone)); return this; } public TimeZone getServerTimeZone() { - return (TimeZone) rawSettings.get(ClientConfigProperties.SERVER_TIMEZONE.getKey()); + return (TimeZone) settings.getOption(ClientConfigProperties.SERVER_TIMEZONE.getKey()); } /** * Defines list of headers that should be sent with current request. The Client will use a header value * defined in {@code headers} instead of any other. * - * @see Client.Builder#httpHeaders(Map) - * @param key - header name. + * @param key - header name. * @param value - header value. * @return same instance of the builder + * @see Client.Builder#httpHeaders(Map) */ public QuerySettings httpHeader(String key, String value) { - rawSettings.put(ClientConfigProperties.httpHeader(key), value); + settings.httpHeader(key, value); return this; } /** * {@see #httpHeader(String, String)} but for multiple values. - * @param key - name of the header + * + * @param key - name of the header * @param values - collection of values * @return same instance of the builder */ public QuerySettings httpHeader(String key, Collection values) { - rawSettings.put(ClientConfigProperties.httpHeader(key), ClientConfigProperties.commaSeparated(values)); + settings.httpHeader(key, values); return this; } /** * {@see #httpHeader(String, String)} but for multiple headers. + * * @param headers - map of headers * @return same instance of the builder */ public QuerySettings httpHeaders(Map headers) { - headers.forEach(this::httpHeader); + settings.httpHeaders(headers); return this; } @@ -208,34 +213,35 @@ public QuerySettings httpHeaders(Map headers) { * defined in {@code settings} instead of any other. * Operation settings may override these values. * - * @see Client.Builder#serverSetting(String, Collection) - * @param name - name of the setting + * @param name - name of the setting * @param value - value of the setting * @return same instance of the builder + * @see Client.Builder#serverSetting(String, Collection) */ public QuerySettings serverSetting(String name, String value) { - rawSettings.put(ClientConfigProperties.serverSetting(name), value); + settings.serverSetting(name, value); return this; } /** * {@see #serverSetting(String, String)} but for multiple values. - * @param name - name of the setting without special prefix + * + * @param name - name of the setting without special prefix * @param values - collection of values * @return same instance of the builder */ public QuerySettings serverSetting(String name, Collection values) { - rawSettings.put(ClientConfigProperties.serverSetting(name), ClientConfigProperties.commaSeparated(values)); + settings.serverSetting(name, values); return this; } /** * Sets DB roles for an operation. Roles that were set by {@link Client#setDBRoles(Collection)} will be overridden. * - * @param dbRoles + * @param dbRoles - list of role to use with an operation */ public QuerySettings setDBRoles(Collection dbRoles) { - rawSettings.put(ClientConfigProperties.SESSION_DB_ROLES.getKey(), dbRoles); + settings.setDBRoles(dbRoles); return this; } @@ -245,36 +251,26 @@ public QuerySettings setDBRoles(Collection dbRoles) { * @return list of DB roles */ public Collection getDBRoles() { - return (Collection) rawSettings.get(ClientConfigProperties.SESSION_DB_ROLES.getKey()); + return settings.getDBRoles(); } /** * Sets the comment that will be added to the query log record associated with the query. + * * @param logComment - comment to be added to the log * @return same instance of the builder */ public QuerySettings logComment(String logComment) { - this.logComment = logComment; - if (logComment != null && !logComment.isEmpty()) { - rawSettings.put(ClientConfigProperties.SETTING_LOG_COMMENT.getKey(), logComment); - } + settings.logComment(logComment); return this; } - private String logComment = null; - public String getLogComment() { - return logComment; + return settings.getLogComment(); } public static QuerySettings merge(QuerySettings source, QuerySettings override) { - QuerySettings merged = new QuerySettings(); - if (source != null) { - merged.rawSettings.putAll(source.rawSettings); - } - if (override != null && override != source) {// avoid copying the literally same object - merged.rawSettings.putAll(override.rawSettings); - } - return merged; + CommonSettings mergedSettings = source.settings.copyAndMerge(override.settings); + return new QuerySettings(mergedSettings); } } diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/PreparedStatementTest.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/PreparedStatementTest.java index 88363c6a0..fd76f1d53 100644 --- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/PreparedStatementTest.java +++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/PreparedStatementTest.java @@ -1036,7 +1036,6 @@ void testMethodsNotAllowedToBeCalled() throws Exception { Assert.assertThrows(SQLException.class, () -> ps.addBatch(sql)); Assert.assertThrows(SQLException.class, () -> ps.executeQuery(sql)); - Assert.assertThrows(SQLException.class, () -> ps.executeQueryImpl(sql, null)); Assert.assertThrows(SQLException.class, () -> ps.execute(sql)); Assert.assertThrows(SQLException.class, () -> ps.execute(sql, new int[]{0})); Assert.assertThrows(SQLException.class, () -> ps.execute(sql, new String[]{""})); From c09962fcaaf0688fd641f1e64c506d313ab43b10 Mon Sep 17 00:00:00 2001 From: Sergey Chernov Date: Thu, 21 Aug 2025 16:28:44 -0700 Subject: [PATCH 2/5] copy settings before adjusting for request --- .../com/clickhouse/client/api/Client.java | 80 ++++++++++--------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/client-v2/src/main/java/com/clickhouse/client/api/Client.java b/client-v2/src/main/java/com/clickhouse/client/api/Client.java index b290c478a..089ec4282 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/Client.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/Client.java @@ -1204,14 +1204,17 @@ public CompletableFuture insert(String tableName, List data, settings = new InsertSettings(); } + final InsertSettings requestSettings = new InsertSettings(buildRequestSettings(settings.getAllSettings())); + String operationId = registerOperationMetrics(); - settings.setOperationId(operationId); + requestSettings.setOperationId(operationId); globalClientStats.get(operationId).start(ClientMetrics.OP_DURATION); globalClientStats.get(operationId).start(ClientMetrics.OP_SERIALIZATION); boolean hasDefaults = this.tableSchemaHasDefaults.get(tableName); ClickHouseFormat format = hasDefaults? ClickHouseFormat.RowBinaryWithDefaults : ClickHouseFormat.RowBinary; + requestSettings.setOption(ClientConfigProperties.INPUT_OUTPUT_FORMAT.getKey(), format); TableSchema tableSchema = tableSchemaCache.get(tableName); if (tableSchema == null) { throw new IllegalArgumentException("Table schema not found for table: " + tableName + ". Did you forget to register it?"); @@ -1235,8 +1238,7 @@ public CompletableFuture insert(String tableName, List data, Integer retry = (Integer) configuration.get(ClientConfigProperties.RETRY_ON_FAILURE.getKey()); final int maxRetries = retry == null ? 0 : retry; - settings.setOption(ClientConfigProperties.INPUT_OUTPUT_FORMAT.getKey(), format); - final InsertSettings finalSettings = new InsertSettings(buildRequestSettings(settings.getAllSettings())); + requestSettings.setOption(ClientConfigProperties.INPUT_OUTPUT_FORMAT.getKey(), format); Supplier supplier = () -> { long startTime = System.nanoTime(); // Selecting some node @@ -1246,7 +1248,7 @@ public CompletableFuture insert(String tableName, List data, for (int i = 0; i <= maxRetries; i++) { // Execute request try (ClassicHttpResponse httpResponse = - httpClientHelper.executeRequest(selectedEndpoint, finalSettings.getAllSettings(), lz4Factory, + httpClientHelper.executeRequest(selectedEndpoint, requestSettings.getAllSettings(), lz4Factory, out -> { out.write("INSERT INTO ".getBytes()); out.write(tableName.getBytes()); @@ -1278,14 +1280,14 @@ public CompletableFuture insert(String tableName, List data, OperationMetrics metrics = new OperationMetrics(clientStats); String summary = HttpAPIClientHelper.getHeaderVal(httpResponse.getFirstHeader(ClickHouseHttpProto.HEADER_SRV_SUMMARY), "{}"); ProcessParser.parseSummary(summary, metrics); - String queryId = HttpAPIClientHelper.getHeaderVal(httpResponse.getFirstHeader(ClickHouseHttpProto.HEADER_QUERY_ID), finalSettings.getQueryId(), String::valueOf); + String queryId = HttpAPIClientHelper.getHeaderVal(httpResponse.getFirstHeader(ClickHouseHttpProto.HEADER_QUERY_ID), requestSettings.getQueryId(), String::valueOf); metrics.operationComplete(); metrics.setQueryId(queryId); return new InsertResponse(metrics); } catch (Exception e) { lastException = httpClientHelper.wrapException(String.format("Query request failed (Attempt: %s/%s - Duration: %s)", (i + 1), (maxRetries + 1), System.nanoTime() - startTime), e); - if (httpClientHelper.shouldRetry(e, finalSettings.getAllSettings())) { + if (httpClientHelper.shouldRetry(e, requestSettings.getAllSettings())) { LOG.warn("Retrying.", e); selectedEndpoint = getNextAliveNode(); } else { @@ -1296,7 +1298,7 @@ public CompletableFuture insert(String tableName, List data, throw new ClientException("Insert request failed after attempts: " + (maxRetries + 1) + " - Duration: " + (System.nanoTime() - startTime), lastException); }; - return runAsyncOperation(supplier, settings.getAllSettings()); + return runAsyncOperation(supplier, requestSettings.getAllSettings()); } @@ -1415,8 +1417,13 @@ public CompletableFuture insert(String tableName, DataStreamWriter writer, ClickHouseFormat format, InsertSettings settings) { + if (settings == null) { + throw new IllegalArgumentException("Settings cannot be null"); + } + final InsertSettings requestSettings = new InsertSettings(buildRequestSettings(settings.getAllSettings())); + requestSettings.setOption(ClientConfigProperties.INPUT_OUTPUT_FORMAT.getKey(), format); - String operationId = settings.getOperationId(); + String operationId = requestSettings.getOperationId(); ClientStatisticsHolder clientStats = null; if (operationId != null) { clientStats = globalClientStats.remove(operationId); @@ -1430,17 +1437,14 @@ public CompletableFuture insert(String tableName, Supplier responseSupplier; - final int writeBufferSize = settings.getInputStreamCopyBufferSize() <= 0 ? + final int writeBufferSize = requestSettings.getInputStreamCopyBufferSize() <= 0 ? (int) configuration.get(ClientConfigProperties.CLIENT_NETWORK_BUFFER_SIZE.getKey()) : - settings.getInputStreamCopyBufferSize(); + requestSettings.getInputStreamCopyBufferSize(); if (writeBufferSize <= 0) { throw new IllegalArgumentException("Buffer size must be greater than 0"); } - settings.setOption(ClientConfigProperties.INPUT_OUTPUT_FORMAT.getKey(), format); - final InsertSettings finalSettings = new InsertSettings(buildRequestSettings(settings.getAllSettings())); - StringBuilder sqlStmt = new StringBuilder("INSERT INTO ").append(tableName); if (columnNames != null && !columnNames.isEmpty()) { sqlStmt.append(" ("); @@ -1451,7 +1455,7 @@ public CompletableFuture insert(String tableName, sqlStmt.append(")"); } sqlStmt.append(" FORMAT ").append(format.name()); - finalSettings.serverSetting(ClickHouseHttpProto.QPARAM_QUERY_STMT, sqlStmt.toString()); + requestSettings.serverSetting(ClickHouseHttpProto.QPARAM_QUERY_STMT, sqlStmt.toString()); responseSupplier = () -> { long startTime = System.nanoTime(); // Selecting some node @@ -1461,7 +1465,7 @@ public CompletableFuture insert(String tableName, for (int i = 0; i <= retries; i++) { // Execute request try (ClassicHttpResponse httpResponse = - httpClientHelper.executeRequest(selectedEndpoint, finalSettings.getAllSettings(), lz4Factory, + httpClientHelper.executeRequest(selectedEndpoint, requestSettings.getAllSettings(), lz4Factory, out -> { writer.onOutput(out); out.close(); @@ -1478,14 +1482,14 @@ public CompletableFuture insert(String tableName, OperationMetrics metrics = new OperationMetrics(finalClientStats); String summary = HttpAPIClientHelper.getHeaderVal(httpResponse.getFirstHeader(ClickHouseHttpProto.HEADER_SRV_SUMMARY), "{}"); ProcessParser.parseSummary(summary, metrics); - String queryId = HttpAPIClientHelper.getHeaderVal(httpResponse.getFirstHeader(ClickHouseHttpProto.HEADER_QUERY_ID), finalSettings.getQueryId(), String::valueOf); + String queryId = HttpAPIClientHelper.getHeaderVal(httpResponse.getFirstHeader(ClickHouseHttpProto.HEADER_QUERY_ID), requestSettings.getQueryId(), String::valueOf); metrics.operationComplete(); metrics.setQueryId(queryId); return new InsertResponse(metrics); } catch (Exception e) { lastException = httpClientHelper.wrapException(String.format("Insert failed (Attempt: %s/%s - Duration: %s)", (i + 1), (retries + 1), System.nanoTime() - startTime), e); - if (httpClientHelper.shouldRetry(e, finalSettings.getAllSettings())) { + if (httpClientHelper.shouldRetry(e, requestSettings.getAllSettings())) { LOG.warn("Retrying.", e); selectedEndpoint = getNextAliveNode(); } else { @@ -1502,10 +1506,10 @@ public CompletableFuture insert(String tableName, } } LOG.warn("Insert request failed after attempts: " + (retries + 1) + " - Duration: " + (System.nanoTime() - startTime)); - throw lastException; + throw (lastException == null ? new ClientException("Failed to complete insert operation") : lastException); }; - return runAsyncOperation(responseSupplier, settings.getAllSettings()); + return runAsyncOperation(responseSupplier, requestSettings.getAllSettings()); } /** @@ -1564,8 +1568,10 @@ public CompletableFuture query(String sqlQuery, Map query(String sqlQuery, Map responseSupplier; if (queryParams != null) { - settings.setOption(HttpAPIClientHelper.KEY_STATEMENT_PARAMS, queryParams); + requestSettings.setOption(HttpAPIClientHelper.KEY_STATEMENT_PARAMS, queryParams); } - final QuerySettings finalSettings = new QuerySettings(buildRequestSettings(settings.getAllSettings())); responseSupplier = () -> { long startTime = System.nanoTime(); // Selecting some node @@ -1585,7 +1590,7 @@ public CompletableFuture query(String sqlQuery, Map { + httpClientHelper.executeRequest(selectedEndpoint, requestSettings.getAllSettings(), lz4Factory, output -> { output.write(sqlQuery.getBytes(StandardCharsets.UTF_8)); output.close(); }); @@ -1602,22 +1607,22 @@ public CompletableFuture query(String sqlQuery, Map query(String sqlQuery, Map query(String sqlQuery, Map queryParams) { return query(sqlQuery, queryParams, null); @@ -1674,10 +1679,11 @@ public CompletableFuture queryRecords(String sqlQuery, Map { + return query(sqlQuery, params, requestSettings).thenApply(response -> { try { return new Records(response, newBinaryFormatReader(response)); @@ -1708,9 +1714,11 @@ public List queryAll(String sqlQuery, Map params, } try { int operationTimeout = getOperationTimeout(); - settings.setFormat(ClickHouseFormat.RowBinaryWithNamesAndTypes) - .waitEndOfQuery(true); - CompletableFuture f = query(sqlQuery, params, settings); + final QuerySettings requestSettings = new QuerySettings(buildRequestSettings(settings.getAllSettings())); + requestSettings.setFormat(ClickHouseFormat.RowBinaryWithNamesAndTypes); + requestSettings.waitEndOfQuery(true); + + CompletableFuture f = query(sqlQuery, params, requestSettings); try (QueryResponse response = operationTimeout == 0 ? f.get() : f.get(operationTimeout, TimeUnit.MILLISECONDS)) { List records = new ArrayList<>(); if (response.getResultRows() > 0) { From d592b5b53d9ea59ab12035f57ce23d6e585267ad Mon Sep 17 00:00:00 2001 From: Sergey Chernov Date: Fri, 22 Aug 2025 22:52:47 -0700 Subject: [PATCH 3/5] added more tests for settings --- .../client/api/insert/InsertSettings.java | 18 ++- .../com/clickhouse/client/SettingsTests.java | 126 +++++++++++++++++- 2 files changed, 142 insertions(+), 2 deletions(-) diff --git a/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java b/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java index 966d25302..d6fce810e 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java @@ -156,8 +156,24 @@ public InsertSettings appCompressedData(boolean enabled, String compressionMetho return this; } + /** + * + * @return true if client compression is enabled + * @deprecated because of typo + */ public boolean isClientRequestEnabled() { - return (Boolean) settings.getOption(ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getKey()); + Boolean flag = (Boolean) settings.getOption(ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getKey()); + return flag != null && flag; + } + + /** + * Returns indication if client request should be compressed (client side compression). + * + * @return true if client compression is enabled + */ + public boolean isClientCompressionEnabled() { + Boolean flag = (Boolean) settings.getOption(ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getKey()); + return flag != null && flag; } /** diff --git a/client-v2/src/test/java/com/clickhouse/client/SettingsTests.java b/client-v2/src/test/java/com/clickhouse/client/SettingsTests.java index befd6929f..f4331ae6d 100644 --- a/client-v2/src/test/java/com/clickhouse/client/SettingsTests.java +++ b/client-v2/src/test/java/com/clickhouse/client/SettingsTests.java @@ -1,13 +1,16 @@ package com.clickhouse.client; -import com.clickhouse.client.api.Client; import com.clickhouse.client.api.ClientConfigProperties; +import com.clickhouse.client.api.insert.InsertSettings; +import com.clickhouse.client.api.query.QuerySettings; import org.testng.Assert; import org.testng.annotations.Test; import java.util.Arrays; +import java.util.Collections; import java.util.List; +@Test(groups = {"unit"}) public class SettingsTests { @Test @@ -17,4 +20,125 @@ void testClientSettings() { List listB = ClientConfigProperties.valuesFromCommaSeparated(listA); Assert.assertEquals(listB, source); } + + @Test + void testMergeQuerySettings() { + QuerySettings settings1 = new QuerySettings().setQueryId("test1").httpHeader("key1", "value1"); + QuerySettings settings2 = new QuerySettings().httpHeader("key1", "value2"); + + QuerySettings merged = QuerySettings.merge(settings1, settings2); + Assert.assertNotSame(merged, settings1); + Assert.assertNotSame(merged, settings2); + + Assert.assertEquals(merged.getAllSettings().get(ClientConfigProperties.httpHeader("key1")), "value2"); + } + + @Test + void testQuerySettingsSpecific() throws Exception { + { + final QuerySettings settings = new QuerySettings(); + settings.setUseTimeZone("America/Los_Angeles"); + Assert.assertThrows(IllegalArgumentException.class, () -> settings.setUseServerTimeZone(true)); + settings.resetOption(ClientConfigProperties.USE_TIMEZONE.getKey()); + settings.setUseServerTimeZone(true); + } + + { + final QuerySettings settings = new QuerySettings(); + settings.setUseServerTimeZone(true); + Assert.assertTrue(settings.getUseServerTimeZone()); + Assert.assertThrows(IllegalArgumentException.class, () -> settings.setUseTimeZone("America/Los_Angeles")); + } + + { + final QuerySettings settings = new QuerySettings(); + settings.setDatabase("test_db1"); + Assert.assertEquals(settings.getDatabase(), "test_db1"); + } + + { + final QuerySettings settings = new QuerySettings(); + settings.setReadBufferSize(10000); + Assert.assertEquals(settings.getReadBufferSize(), 10000); + + Assert.assertThrows(IllegalArgumentException.class, () -> settings.setReadBufferSize(1000)); + } + + { + final QuerySettings settings = new QuerySettings(); + settings.setMaxExecutionTime(10000); + Assert.assertEquals(settings.getMaxExecutionTime(), 10000); + } + + { + final QuerySettings settings = new QuerySettings(); + settings.setDBRoles(Arrays.asList("role1", "role2")); + Assert.assertEquals(settings.getDBRoles(), Arrays.asList("role1", "role2")); + settings.setDBRoles(Collections.emptyList()); + Assert.assertEquals(settings.getDBRoles(), Collections.emptyList()); + } + + { + final QuerySettings settings = new QuerySettings(); + settings.logComment("comment1"); + Assert.assertEquals(settings.getLogComment(), "comment1"); + settings.logComment("comment2"); + Assert.assertEquals(settings.getLogComment(), "comment2"); + settings.logComment(null); + Assert.assertNull(settings.getLogComment()); + } + } + + @Test + public void testInsertSettingsSpecific() throws Exception { + { + final InsertSettings settings = new InsertSettings(); + settings.setDatabase("test_db1"); + Assert.assertEquals(settings.getDatabase(), "test_db1"); + } + + { + final InsertSettings settings = new InsertSettings(); + Assert.assertFalse(settings.isClientCompressionEnabled()); + settings.compressClientRequest(true); + Assert.assertTrue(settings.isClientCompressionEnabled()); + Assert.assertTrue(settings.isClientRequestEnabled()); + } + + + { + final InsertSettings settings = new InsertSettings(); + settings.httpHeader("key1", "value1"); + Assert.assertEquals(settings.getAllSettings().get(ClientConfigProperties.httpHeader("key1")), "value1"); + settings.httpHeader("key1", "value2"); + Assert.assertEquals(settings.getAllSettings().get(ClientConfigProperties.httpHeader("key1")), "value2"); + } + + + { + final InsertSettings settings = new InsertSettings(); + settings.serverSetting("key1", "value1"); + Assert.assertEquals(settings.getAllSettings().get(ClientConfigProperties.serverSetting("key1")), "value1"); + settings.serverSetting("key1", "value2"); + Assert.assertEquals(settings.getAllSettings().get(ClientConfigProperties.serverSetting("key1")), "value2"); + } + + { + final InsertSettings settings = new InsertSettings(); + settings.setDBRoles(Arrays.asList("role1", "role2")); + Assert.assertEquals(settings.getDBRoles(), Arrays.asList("role1", "role2")); + settings.setDBRoles(Collections.emptyList()); + Assert.assertEquals(settings.getDBRoles(), Collections.emptyList()); + } + + { + final InsertSettings settings = new InsertSettings(); + settings.logComment("comment1"); + Assert.assertEquals(settings.getLogComment(), "comment1"); + settings.logComment("comment2"); + Assert.assertEquals(settings.getLogComment(), "comment2"); + settings.logComment(null); + Assert.assertNull(settings.getLogComment()); + } + } } From 26e9fcf5e8ae477e846d561a2691243007abaf87 Mon Sep 17 00:00:00 2001 From: Sergey Chernov Date: Fri, 22 Aug 2025 23:13:35 -0700 Subject: [PATCH 4/5] added tests for that settings are not mutated while operation --- client-v2/pom.xml | 6 +++++ .../clickhouse/client/insert/InsertTests.java | 25 +++++++++++++++++++ .../clickhouse/client/query/QueryTests.java | 12 +++++++++ 3 files changed, 43 insertions(+) diff --git a/client-v2/pom.xml b/client-v2/pom.xml index 88e55688a..ef1a1c1ba 100644 --- a/client-v2/pom.xml +++ b/client-v2/pom.xml @@ -135,6 +135,12 @@ 2.0.16 test + + org.mockito + mockito-core + 5.19.0 + test + diff --git a/client-v2/src/test/java/com/clickhouse/client/insert/InsertTests.java b/client-v2/src/test/java/com/clickhouse/client/insert/InsertTests.java index 903abdf93..60514c224 100644 --- a/client-v2/src/test/java/com/clickhouse/client/insert/InsertTests.java +++ b/client-v2/src/test/java/com/clickhouse/client/insert/InsertTests.java @@ -26,6 +26,7 @@ import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorOutputStream; import org.apache.commons.compress.compressors.snappy.SnappyCompressorOutputStream; import org.apache.commons.lang3.StringEscapeUtils; +import org.mockito.Mockito; import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; import org.testng.Assert; import org.testng.annotations.AfterMethod; @@ -822,4 +823,28 @@ private boolean isVersionMatch(String versionExpression) { List serverVersion = client.queryAll("SELECT version()"); return ClickHouseVersion.of(serverVersion.get(0).getString(1)).check(versionExpression); } + + @Test(groups = { "integration" }, enabled = true) + public void testInsertSettingsNotChanged() throws Exception { + String tableName = "test_settings_not_changed"; + String createSQL = SamplePOJO.generateTableCreateSQL(tableName); + String uuid = UUID.randomUUID().toString(); + + initTable(tableName, createSQL); + + client.register(SamplePOJO.class, client.getTableSchema(tableName)); + List simplePOJOs = new ArrayList<>(); + + for (int i = 0; i < 1000; i++) { + simplePOJOs.add(new SamplePOJO()); + } + InsertSettings settings = Mockito.spy(new InsertSettings()); + settings.setQueryId(uuid); + + try (InsertResponse response = client.insert(tableName, simplePOJOs, settings).get(EXECUTE_CMD_TIMEOUT, TimeUnit.SECONDS)) { + Mockito.verify(settings, Mockito.times(1)).getAllSettings(); + Mockito.verify(settings, Mockito.times(1)).setQueryId(Mockito.eq(uuid)); + Mockito.verifyNoMoreInteractions(settings); + } + } } diff --git a/client-v2/src/test/java/com/clickhouse/client/query/QueryTests.java b/client-v2/src/test/java/com/clickhouse/client/query/QueryTests.java index 5b08248b7..b005ac914 100644 --- a/client-v2/src/test/java/com/clickhouse/client/query/QueryTests.java +++ b/client-v2/src/test/java/com/clickhouse/client/query/QueryTests.java @@ -38,6 +38,7 @@ import com.google.common.io.BaseEncoding; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringEscapeUtils; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; @@ -2190,4 +2191,15 @@ public void testEmptyResponse() throws Exception { System.out.println(response.getResultRows()); } } + + @Test(groups = {"integration"}) + public void testSettingsNotChanged() throws Exception{ + final QuerySettings settings = Mockito.spy(new QuerySettings()); + try (QueryResponse response = client.query("select 1 FORMAT JSONEachRow", settings).get()) { + Mockito.verify(settings, Mockito.times(1)).getAllSettings(); + Mockito.verifyNoMoreInteractions(settings); + Assert.assertNull(settings.getFormat()); + Assert.assertEquals(response.getFormat(), ClickHouseFormat.JSONEachRow); + } + } } From 334881f9ec38848e543e695eb78d40b2ffd900c9 Mon Sep 17 00:00:00 2001 From: Sergey Chernov Date: Mon, 25 Aug 2025 14:07:28 -0700 Subject: [PATCH 5/5] added getOption(key, default) for CommonSettings --- .../clickhouse/client/api/insert/InsertSettings.java | 9 +++++---- .../client/api/internal/CommonSettings.java | 11 +++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java b/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java index d6fce810e..7cab9bb8c 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/insert/InsertSettings.java @@ -162,8 +162,7 @@ public InsertSettings appCompressedData(boolean enabled, String compressionMetho * @deprecated because of typo */ public boolean isClientRequestEnabled() { - Boolean flag = (Boolean) settings.getOption(ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getKey()); - return flag != null && flag; + return isClientCompressionEnabled(); } /** @@ -172,8 +171,10 @@ public boolean isClientRequestEnabled() { * @return true if client compression is enabled */ public boolean isClientCompressionEnabled() { - Boolean flag = (Boolean) settings.getOption(ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getKey()); - return flag != null && flag; + return (boolean) settings.getOption( + ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getKey(), + false + ); } /** diff --git a/client-v2/src/main/java/com/clickhouse/client/api/internal/CommonSettings.java b/client-v2/src/main/java/com/clickhouse/client/api/internal/CommonSettings.java index 3b415e311..d703570b7 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/internal/CommonSettings.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/internal/CommonSettings.java @@ -32,6 +32,17 @@ public Object getOption(String option) { return settings.get(option); } + /** + * Gets a configuration option. If not set then defaultValue is returned. + * + * @param option - config option key + * @param defaultValue - default option to return when option is not set + * @return configuration option value + */ + public Object getOption(String option, Object defaultValue) { + return settings.getOrDefault(option, defaultValue); + } + public boolean hasOption(String option) { return settings.containsKey(option); }