Skip to content

Commit b35806d

Browse files
committed
Redesigned to expose less. Added tests. Updated docs
1 parent 6262ef9 commit b35806d

24 files changed

Lines changed: 517 additions & 322 deletions

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727

2828
- **[client-v2]** `Client.Builder#useBearerTokenAuth(String)` now stores the bearer token under the `access_token` configuration key (with the `Bearer ` prefix) instead of writing it directly into `http_header_authorization`. The HTTP wire format is unchanged, but the token is no longer observable through `Client#getReadOnlyConfig()` under the `http_header_authorization` key.
2929

30+
- **[client-v2]** The public `ClickHouseBinaryFormatWriter` interface gained two methods, `setString(String, byte[])` and `setString(int, byte[])`, for writing raw `String`/`FixedString` bytes. Code that only *uses* the interface is unaffected, but any third party that *implements* `ClickHouseBinaryFormatWriter` directly is source- and binary-incompatible until it adds these methods (recompiling against the new version is required; otherwise an `AbstractMethodError` can occur at runtime).
31+
3032
### New Features
3133

3234
- **[client-v2]** Added `Session` API to encapsulate and manage ClickHouse session settings (`session_id`, `session_check`, `session_timeout`, `session_timezone`) as a reusable object. The `Session` instance can be applied to any request settings using `applyTo()`, and session state can be cleared via `clearSession()`. Additionally, added `resetOption(String)` to `InsertSettings`, `QuerySettings`, and `CommonSettings` to allow removing specific settings. Settings explicitly set to `null` will not be sent to the server, which is useful for overriding global settings.
@@ -37,7 +39,7 @@
3739

3840
- **[client-v2, jdbc-v2]** Added support for ClickHouse `Geometry` type for ClickHouse `25.11+`, where `Geometry` changed from a `String` alias to `Variant(Point, Ring, LineString, MultiLineString, Polygon, MultiPolygon)` (client still compatible with older versions). Includes client read/write handling and JDBC type mapping for retrieving and inserting geometry values. Current writes infer the target geometry variant from array nesting depth, so `Ring` vs `LineString` and `Polygon` vs `MultiLineString` are not yet distinguishable through the generic `Geometry` write path. (https://github.com/ClickHouse/clickhouse-java/pull/2815)
3941

40-
- **[client-v2, jdbc-v2]** Added opt-in binary string support through the `binary_string_support` configuration property (or `Client.Builder#binaryStringSupport(boolean)`), disabled by default. When enabled, top-level `String` and `FixedString` columns are read into a `StringValue` that preserves the raw bytes instead of decoding them into a `String`, allowing non-UTF-8/binary content to round-trip byte-for-byte. `StringValue` exposes the bytes via `toByteArray()`/`asByteBuffer()` and lazily decodes a `String` via `asString()` (UTF-8 by default, or a caller-supplied `Charset`). Values nested inside containers (`Array`, `Map`, `Tuple`, `Nested`, `Variant`) continue to be read as `String`, since those types are not expected to carry large/binary strings. On the JDBC side, `ResultSet#getBinaryStream(int)` and `ResultSet#getBinaryStream(String)` are now implemented (previously unsupported) and, together with `getBytes(...)`, return the raw column bytes.
42+
- **[client-v2, jdbc-v2]** Added opt-in binary string support through the `binary_string_support` configuration property (or `Client.Builder#binaryStringSupport(boolean)`), disabled by default. The setting is resolved per operation from the merged client and query settings, so it can be overridden for a single request via the `binary_string_support` operation option (e.g. `QuerySettings#setOption(ClientConfigProperties.BINARY_STRING_SUPPORT.getKey(), true)`) independently of the client-level default. When enabled, top-level `String` and `FixedString` columns are read into a `StringValue` that preserves the raw bytes instead of decoding them into a `String`, allowing non-UTF-8/binary content to round-trip byte-for-byte. `StringValue` exposes the bytes via `toByteArray()`/`asByteBuffer()` and lazily decodes a `String` via `asString()` (UTF-8 by default, or a caller-supplied `Charset`). Values nested inside containers (`Array`, `Map`, `Tuple`, `Nested`, `Variant`) continue to be read as `String`, since those types are not expected to carry large/binary strings. On the JDBC side, `ResultSet#getBinaryStream(int)` and `ResultSet#getBinaryStream(String)` are now implemented (previously unsupported) and, together with `getBytes(...)`, return the raw column bytes.
4143

4244
- **[jdbc-v2]** `ResultSet#getObject(int|String, Map<String, Class<?>>)` now accepts ClickHouse type names as map keys in addition to the JDBC `SQLType` names it has always accepted. Only unwrapped type names are used for the lookup — `Nullable(...)` and `LowCardinality(...)` wrappers are stripped and do not affect resolution, so a key like `"Int32"` matches both `Int32` and `Nullable(Int32)` columns; keys like `"Nullable(Int32)"` are not recognized. Lookup order is the `ClickHouseDataType` enum name (e.g. `"Int32"`, `"String"`, `"DateTime"`) then the JDBC `SQLType` name (e.g. `"INTEGER"`, `"VARCHAR"`, `"TIMESTAMP"`); a missing entry leaves the value uncoerced. The feature is supported for primitive ClickHouse types only — `Array`, `Tuple`, `Map`, `Nested`, and geometry types are not supported and continue to be returned in their native form regardless of the user-supplied map. Existing maps keyed only by JDBC `SQLType` names continue to work unchanged.
4345

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

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.clickhouse.client.api.command.CommandResponse;
44
import com.clickhouse.client.api.command.CommandSettings;
55
import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
6+
import com.clickhouse.client.api.data_formats.ClickHouseFormatReader;
67
import com.clickhouse.client.api.data_formats.NativeFormatReader;
78
import com.clickhouse.client.api.data_formats.RowBinaryFormatReader;
89
import com.clickhouse.client.api.data_formats.RowBinaryWithNamesAndTypesFormatReader;
@@ -135,8 +136,6 @@ public class Client implements AutoCloseable {
135136

136137
private final Map<ClickHouseDataType, Class<?>> typeHintMapping;
137138

138-
private final boolean binaryStringSupport;
139-
140139
// Server context
141140
private String dbUser;
142141
private String serverVersion;
@@ -202,7 +201,6 @@ private Client(Collection<Endpoint> endpoints, Map<String,String> configuration,
202201
this.serverVersion = configuration.getOrDefault(ClientConfigProperties.SERVER_VERSION.getKey(), "unknown");
203202
this.dbUser = configuration.getOrDefault(ClientConfigProperties.USER.getKey(), ClientConfigProperties.USER.getDefObjVal());
204203
this.typeHintMapping = (Map<ClickHouseDataType, Class<?>>) this.configuration.get(ClientConfigProperties.TYPE_HINT_MAPPING.getKey());
205-
this.binaryStringSupport = ClientConfigProperties.BINARY_STRING_SUPPORT.getOrDefault(this.configuration);
206204
}
207205

208206
/**
@@ -1123,10 +1121,10 @@ public Builder typeHintMapping(Map<ClickHouseDataType, Class<?>> typeHintMapping
11231121
}
11241122

11251123
/**
1126-
* Enables reading top-level {@code String} and {@code FixedString} columns as
1127-
* {@link com.clickhouse.client.api.data_formats.StringValue}, preserving the raw bytes instead of
1128-
* decoding them into a {@link String}. Values nested inside containers (Array, Map, Tuple, Nested,
1129-
* Variant) are still read as {@link String}.
1124+
* Enables reading {@code String} and {@code FixedString} columns into an intermediate {@code byte[]}
1125+
* (a new array each time) instead of decoding them into a {@link String}. This improves working with
1126+
* large strings and allows {@link ClickHouseFormatReader#getByteArray} to be used more effectively. Can also be configured
1127+
* per operation.
11301128
*
11311129
* @param enable - if the feature is enabled
11321130
* @return this builder instance
@@ -2126,17 +2124,17 @@ public ClickHouseBinaryFormatReader newBinaryFormatReader(QueryResponse response
21262124
switch (response.getFormat()) {
21272125
case Native:
21282126
reader = new NativeFormatReader(response.getInputStream(), response.getSettings(),
2129-
byteBufferPool, typeHintMapping, binaryStringSupport);
2127+
byteBufferPool, typeHintMapping);
21302128
break;
21312129
case RowBinaryWithNamesAndTypes:
2132-
reader = new RowBinaryWithNamesAndTypesFormatReader(response.getInputStream(), response.getSettings(), byteBufferPool, typeHintMapping, binaryStringSupport);
2130+
reader = new RowBinaryWithNamesAndTypesFormatReader(response.getInputStream(), response.getSettings(), byteBufferPool, typeHintMapping);
21332131
break;
21342132
case RowBinaryWithNames:
2135-
reader = new RowBinaryWithNamesFormatReader(response.getInputStream(), response.getSettings(), schema, byteBufferPool, typeHintMapping, binaryStringSupport);
2133+
reader = new RowBinaryWithNamesFormatReader(response.getInputStream(), response.getSettings(), schema, byteBufferPool, typeHintMapping);
21362134
break;
21372135
case RowBinary:
21382136
reader = new RowBinaryFormatReader(response.getInputStream(), response.getSettings(), schema,
2139-
byteBufferPool, typeHintMapping, binaryStringSupport);
2137+
byteBufferPool, typeHintMapping);
21402138
break;
21412139
default:
21422140
throw new IllegalArgumentException("Binary readers doesn't support format: " + response.getFormat());

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

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

3+
import com.clickhouse.client.api.data_formats.ClickHouseFormatReader;
34
import com.clickhouse.client.api.data_formats.internal.AbstractBinaryFormatReader;
45
import com.clickhouse.client.api.enums.SSLMode;
56
import com.clickhouse.client.api.internal.ClickHouseLZ4OutputStream;
@@ -182,10 +183,9 @@ public Object parseValue(String value) {
182183
TYPE_HINT_MAPPING("type_hint_mapping", Map.class),
183184

184185
/**
185-
* When enabled, top-level {@code String} and {@code FixedString} columns are read into a
186-
* {@link com.clickhouse.client.api.data_formats.StringValue} that preserves the raw bytes instead of
187-
* decoding them into a {@link String}. Values nested inside containers (Array, Map, Tuple, Nested, Variant)
188-
* are still read as {@link String}, since those types are not expected to carry large/binary strings.
186+
* When enabled, {@code String} and {@code FixedString} columns are read into an intermediate {@code byte[]}
187+
* instead of decoding them into a {@link String}. Improves working with large strings and lets
188+
* {@link ClickHouseFormatReader#getByteArray} be used more effectively. Can be configured per operation.
189189
*/
190190
BINARY_STRING_SUPPORT("binary_string_support", Boolean.class, "false"),
191191

client-v2/src/main/java/com/clickhouse/client/api/data_formats/NativeFormatReader.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,7 @@ public class NativeFormatReader extends AbstractBinaryFormatReader {
2929
public NativeFormatReader(InputStream inputStream, QuerySettings settings,
3030
BinaryStreamReader.ByteBufferAllocator byteBufferAllocator,
3131
Map<ClickHouseDataType, Class<?>> typeHintMapping) {
32-
this(inputStream, settings, byteBufferAllocator, typeHintMapping, false);
33-
}
34-
35-
public NativeFormatReader(InputStream inputStream, QuerySettings settings,
36-
BinaryStreamReader.ByteBufferAllocator byteBufferAllocator,
37-
Map<ClickHouseDataType, Class<?>> typeHintMapping,
38-
boolean binaryStringSupport) {
39-
super(inputStream, settings, null, byteBufferAllocator, typeHintMapping, binaryStringSupport);
32+
super(inputStream, settings, null, byteBufferAllocator, typeHintMapping);
4033
try {
4134
readBlock();
4235
} catch (IOException e) {

client-v2/src/main/java/com/clickhouse/client/api/data_formats/RowBinaryFormatReader.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,7 @@ public RowBinaryFormatReader(InputStream inputStream,
1919
TableSchema schema,
2020
BinaryStreamReader.ByteBufferAllocator byteBufferAllocator,
2121
Map<ClickHouseDataType, Class<?>> typeHintMapping) {
22-
this(inputStream, querySettings, schema, byteBufferAllocator, typeHintMapping, false);
23-
}
24-
25-
public RowBinaryFormatReader(InputStream inputStream,
26-
QuerySettings querySettings,
27-
TableSchema schema,
28-
BinaryStreamReader.ByteBufferAllocator byteBufferAllocator,
29-
Map<ClickHouseDataType, Class<?>> typeHintMapping,
30-
boolean binaryStringSupport) {
31-
super(inputStream, querySettings, schema, byteBufferAllocator, typeHintMapping, binaryStringSupport);
22+
super(inputStream, querySettings, schema, byteBufferAllocator, typeHintMapping);
3223
readNextRecord();
3324
}
3425

client-v2/src/main/java/com/clickhouse/client/api/data_formats/RowBinaryWithNamesAndTypesFormatReader.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,7 @@ public RowBinaryWithNamesAndTypesFormatReader(InputStream inputStream,
2222
QuerySettings querySettings,
2323
BinaryStreamReader.ByteBufferAllocator byteBufferAllocator,
2424
Map<ClickHouseDataType, Class<?>> typeHintMapping) {
25-
this(inputStream, querySettings, byteBufferAllocator, typeHintMapping, false);
26-
}
27-
28-
public RowBinaryWithNamesAndTypesFormatReader(InputStream inputStream,
29-
QuerySettings querySettings,
30-
BinaryStreamReader.ByteBufferAllocator byteBufferAllocator,
31-
Map<ClickHouseDataType, Class<?>> typeHintMapping,
32-
boolean binaryStringSupport) {
33-
super(inputStream, querySettings, null, byteBufferAllocator, typeHintMapping, binaryStringSupport);
25+
super(inputStream, querySettings, null, byteBufferAllocator, typeHintMapping);
3426
readSchema();
3527
}
3628

client-v2/src/main/java/com/clickhouse/client/api/data_formats/RowBinaryWithNamesFormatReader.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,7 @@ public RowBinaryWithNamesFormatReader(InputStream inputStream,
2323
TableSchema schema,
2424
BinaryStreamReader.ByteBufferAllocator byteBufferAllocator,
2525
Map<ClickHouseDataType, Class<?>> typeHintMapping) {
26-
this(inputStream, querySettings, schema, byteBufferAllocator, typeHintMapping, false);
27-
}
28-
29-
public RowBinaryWithNamesFormatReader(InputStream inputStream,
30-
QuerySettings querySettings,
31-
TableSchema schema,
32-
BinaryStreamReader.ByteBufferAllocator byteBufferAllocator,
33-
Map<ClickHouseDataType, Class<?>> typeHintMapping,
34-
boolean binaryStringSupport) {
35-
super(inputStream, querySettings, schema, byteBufferAllocator, typeHintMapping, binaryStringSupport);
26+
super(inputStream, querySettings, schema, byteBufferAllocator, typeHintMapping);
3627
int nCol = 0;
3728
try {
3829
nCol = BinaryStreamReader.readVarInt(input);

client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/AbstractBinaryFormatReader.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.clickhouse.client.api.ClientException;
55
import com.clickhouse.client.api.DataTypeUtils;
66
import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
7-
import com.clickhouse.client.api.data_formats.StringValue;
87
import com.clickhouse.client.api.internal.DataTypeConverter;
98
import com.clickhouse.client.api.internal.MapUtils;
109
import com.clickhouse.client.api.internal.ServerSettings;
@@ -78,10 +77,6 @@ public abstract class AbstractBinaryFormatReader implements ClickHouseBinaryForm
7877
private long lastNextCallTs; // for exception to detect slow reader
7978

8079
protected AbstractBinaryFormatReader(InputStream inputStream, QuerySettings querySettings, TableSchema schema, BinaryStreamReader.ByteBufferAllocator byteBufferAllocator, Map<ClickHouseDataType, Class<?>> defaultTypeHintMap) {
81-
this(inputStream, querySettings, schema, byteBufferAllocator, defaultTypeHintMap, false);
82-
}
83-
84-
protected AbstractBinaryFormatReader(InputStream inputStream, QuerySettings querySettings, TableSchema schema, BinaryStreamReader.ByteBufferAllocator byteBufferAllocator, Map<ClickHouseDataType, Class<?>> defaultTypeHintMap, boolean binaryStringSupport) {
8580
this.input = inputStream;
8681
Map<String, Object> settings = querySettings == null ? Collections.emptyMap() : querySettings.getAllSettings();
8782
Boolean useServerTimeZone = (Boolean) settings.get(ClientConfigProperties.USE_SERVER_TIMEZONE.getKey());
@@ -93,6 +88,10 @@ protected AbstractBinaryFormatReader(InputStream inputStream, QuerySettings quer
9388
}
9489
boolean jsonAsString = MapUtils.getFlag(settings,
9590
ClientConfigProperties.serverSetting(ServerSettings.OUTPUT_FORMAT_BINARY_WRITE_JSON_AS_STRING), false);
91+
// Binary string support is resolved from the (already merged client + operation) query settings so it can be
92+
// toggled per operation, not just per client.
93+
boolean binaryStringSupport = MapUtils.getFlag(settings,
94+
ClientConfigProperties.BINARY_STRING_SUPPORT.getKey(), false);
9695
this.binaryStreamReader = new BinaryStreamReader(inputStream, timeZone, LOG, byteBufferAllocator, jsonAsString,
9796
defaultTypeHintMap, binaryStringSupport);
9897
if (schema != null) {

0 commit comments

Comments
 (0)