From 3e72e308b21f86eefda4933da3d9a831fc69f6e5 Mon Sep 17 00:00:00 2001 From: Polyglot AI <293096396+polyglotAI-bot@users.noreply.github.com> Date: Fri, 17 Jul 2026 22:49:17 +0000 Subject: [PATCH 1/4] Fix client-v2: serialize Nested columns in RowBinary writer RowBinaryFormatWriter threw `UnsupportedOperationException: Unsupported data type: Nested` when inserting into a table whose schema keeps an un-flattened `Nested(...)` column (created with `flatten_nested = 0`), because SerializerUtils.serializeData had no case for the Nested type and fell through to serializePrimitiveData's default throw. A `Nested(f1 T1, ..., fN TN)` column has the same RowBinary layout as `Array(Tuple(T1, ..., TN))` - a var-uint element count followed by that many tuples - which is exactly how BinaryStreamReader.readNested reads it. serializeData now serializes it symmetrically. Fixes: https://github.com/ClickHouse/clickhouse-java/issues/2477 --- CHANGELOG.md | 2 ++ .../internal/SerializerUtils.java | 22 +++++++++++++ .../internal/SerializerUtilsTest.java | 31 +++++++++++++++++++ .../datatypes/RowBinaryFormatWriterTest.java | 21 +++++++++++++ 4 files changed, 76 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebd7bba1f..753d2d196 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Bug Fixes +- **[client-v2]** Fixed `RowBinaryFormatWriter` throwing `UnsupportedOperationException: Unsupported data type: Nested` when inserting into a table with an un-flattened `Nested(...)` column (created with `flatten_nested = 0`). The `RowBinary` writer now serializes a `Nested(f1 T1, ..., fN TN)` column the same way it is read — identically to `Array(Tuple(T1, ..., TN))`. (https://github.com/ClickHouse/clickhouse-java/issues/2477) + - **[client-v2]** Fixed binary array decoding for nullable element types so `Array(Nullable(Float64))` and similar columns now return boxed arrays such as `Double[]` instead of `Object[]`. This keeps null-supporting arrays aligned with their element type while preserving the existing `Object[]` fallback for Variant/Dynamic/Geometry arrays. (https://github.com/ClickHouse/clickhouse-java/issues/2846) - **[client-v2]** Fixed `Float32`/`Float64` columns throwing `ClassCastException` when a value of a diff --git a/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/SerializerUtils.java b/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/SerializerUtils.java index 6ff4b4b79..d3d7a43bb 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/SerializerUtils.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/SerializerUtils.java @@ -72,6 +72,9 @@ public static void serializeData(OutputStream stream, Object value, ClickHouseCo case Map: serializeMapData(stream, value, column); break; + case Nested: + serializeNestedTypeData(stream, value, column); + break; case AggregateFunction: serializeAggregateFunction(stream, value, column); break; @@ -130,6 +133,25 @@ private static void serializeNestedData(OutputStream stream, Object value, Click serializeData(stream, value, column); } + /** + * Serializes a {@code Nested} column. In {@code RowBinary} a {@code Nested(f1 T1, ..., fN TN)} + * column has the same layout as {@code Array(Tuple(T1, ..., TN))}: a var-uint element count + * followed by that many tuples, each carrying the N field values in declaration order. The + * value is therefore a list (or array) of tuples, matching what + * {@link BinaryStreamReader#readNested(ClickHouseColumn)} produces on read. + */ + private static void serializeNestedTypeData(OutputStream stream, Object value, ClickHouseColumn column) throws IOException { + if (value == null) { + writeVarInt(stream, 0); + return; + } + List tuples = convertArrayValueToList(value); + writeVarInt(stream, tuples.size()); + for (Object tuple : tuples) { + serializeTupleData(stream, tuple, column); + } + } + private static final Map, ClickHouseColumn> PREDEFINED_TYPE_COLUMNS = getPredefinedTypeColumnsMap(); private static Map, ClickHouseColumn> getPredefinedTypeColumnsMap() { diff --git a/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java b/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java index 265cd1cfb..51172d212 100644 --- a/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java +++ b/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java @@ -217,6 +217,37 @@ private Object[][] nestedNullableData() throws Exception { }; } + @Test(dataProvider = "rowBinaryTypeData") + public void testRowBinaryTypeRoundTrip(String typeName, Object value) throws Exception { + ClickHouseColumn column = ClickHouseColumn.of("v", typeName); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + SerializerUtils.serializeData(out, value, column); + + Object actual = newReader(out.toByteArray()).readValue(column); + Assert.assertEquals(normalize(actual), normalize(value)); + } + + @DataProvider(name = "rowBinaryTypeData") + private Object[][] rowBinaryTypeData() { + return new Object[][] { + // A Nested(...) column has the same RowBinary layout as Array(Tuple(...)): a + // var-uint row count followed by that many tuples. Two rows detect a wrong count + // or a dropped field byte, which would shift every following tuple. + {"Nested(a Int32, b String)", + Arrays.asList(Arrays.asList(1, "x"), Arrays.asList(2, "y"))}, + + // A Nullable field in the MIDDLE of the nested tuple, with a trailing fixed-width + // Float64: a dropped null-marker byte misaligns the Float64 and is caught. The + // second row exercises the null branch of that field. + {"Nested(a Int32, b Nullable(String), c Float64)", + Arrays.asList(Arrays.asList(7, "opt", 9.5d), Arrays.asList(7, null, 8.5d))}, + + // An empty Nested serializes as a zero-length array. + {"Nested(a Int32, b String)", Arrays.asList()}, + }; + } + // Normalizes Tuple (Object[]) and Array (ArrayValue / List) results to nested Lists so // round-tripped values compare structurally regardless of the container representation the // reader returns. diff --git a/client-v2/src/test/java/com/clickhouse/client/datatypes/RowBinaryFormatWriterTest.java b/client-v2/src/test/java/com/clickhouse/client/datatypes/RowBinaryFormatWriterTest.java index 1a0ee2287..bf7ff3067 100644 --- a/client-v2/src/test/java/com/clickhouse/client/datatypes/RowBinaryFormatWriterTest.java +++ b/client-v2/src/test/java/com/clickhouse/client/datatypes/RowBinaryFormatWriterTest.java @@ -534,6 +534,27 @@ public void writeNestedTests() throws Exception { writeTest(tableName, tableCreate, rows); } + @Test (groups = { "integration" }) + public void writeNestedTypeTests() throws Exception { + String tableName = "rowBinaryFormatWriterTest_writeNestedTypeTests_" + UUID.randomUUID().toString().replace('-', '_'); + // flatten_nested = 0 keeps the column typed as Nested(...) in the schema instead of + // expanding it into parallel Array(...) sub-columns; the un-flattened Nested type is the + // one that has to be serialized as Array(Tuple(...)). + String tableCreate = "CREATE TABLE \"" + tableName + "\" " + + " (id Int32, " + + " n Nested(a UInt32, b Nullable(String)) " + + " ) Engine = MergeTree ORDER BY id SETTINGS flatten_nested = 0"; + + List nested = Arrays.asList(Arrays.asList(10L, "x"), Arrays.asList(20L, null)); + Field[][] rows = new Field[][] {{ + new Field("id", 1), //Row ID + new Field("n", nested).set(nested) //Nested + } + }; + + writeTest(tableName, tableCreate, rows); + } + @Test (groups = { "integration" }) public void writeNullableTests() throws Exception { String tableName = "rowBinaryFormatWriterTest_writeNullableTests_" + UUID.randomUUID().toString().replace('-', '_'); From e0f467482567482e6e5f867598915ae40f5eeec5 Mon Sep 17 00:00:00 2001 From: Polyglot AI <293096396+polyglotAI-bot@users.noreply.github.com> Date: Sun, 19 Jul 2026 12:31:08 +0000 Subject: [PATCH 2/4] test(client-v2): cover Object[][] (array-shaped) Nested values in round-trip Adds an Object[][] "matrix array" case to the Nested RowBinary round-trip DataProvider, exercising convertArrayValueToList's array branch and serializeTupleData's array branch (the existing cases used List shapes only). Documents that array-shaped Nested values round-trip correctly. --- .../api/data_formats/internal/SerializerUtilsTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java b/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java index 51172d212..46f269b58 100644 --- a/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java +++ b/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java @@ -237,6 +237,13 @@ private Object[][] rowBinaryTypeData() { {"Nested(a Int32, b String)", Arrays.asList(Arrays.asList(1, "x"), Arrays.asList(2, "y"))}, + // Same value as arrays instead of Lists: an Object[][] of Object[] rows (a + // "matrix" array). convertArrayValueToList takes the array branch and each row is + // serialized by serializeTupleData's array branch, producing the same bytes as the + // List-shaped case above. + {"Nested(a Int32, b String)", + new Object[][] {{1, "x"}, {2, "y"}}}, + // A Nullable field in the MIDDLE of the nested tuple, with a trailing fixed-width // Float64: a dropped null-marker byte misaligns the Float64 and is caught. The // second row exercises the null branch of that field. From 5112ee38c500647a579ad37beea5c47cfaef2a3b Mon Sep 17 00:00:00 2001 From: Polyglot AI <293096396+polyglotAI-bot@users.noreply.github.com> Date: Fri, 24 Jul 2026 21:02:09 +0000 Subject: [PATCH 3/4] Support Nested columns in jdbc-v2 java.sql.Array getResultSet A `java.sql.Array` wrapping an un-flattened `Nested(f1 T1, ..., fN TN)` column (tables created with `flatten_nested = 0`) threw from `getResultSet()`: `ArrayResultSet` derived the VALUE column as the first nested field instead of the element `Tuple(...)`, so reading each element tried to coerce the tuple `Object[]` to that field's scalar type. Resolve the element as the tuple for Nested columns (shared `elementColumn` helper, also used by the getArray element path). Insert (createArrayOf/setArray/ setObject) and read (getArray/getObject/getResultSet) of Nested columns are covered by a new jdbc-v2 integration test. Fixes: https://github.com/ClickHouse/clickhouse-java/issues/2477 --- CHANGELOG.md | 2 + docs/features.md | 1 + .../clickhouse/jdbc/types/ArrayResultSet.java | 30 +++++-- .../clickhouse/jdbc/JdbcDataTypeTests.java | 86 +++++++++++++++++++ 4 files changed, 114 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 753d2d196..d303d4ba4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - **[client-v2]** Fixed `RowBinaryFormatWriter` throwing `UnsupportedOperationException: Unsupported data type: Nested` when inserting into a table with an un-flattened `Nested(...)` column (created with `flatten_nested = 0`). The `RowBinary` writer now serializes a `Nested(f1 T1, ..., fN TN)` column the same way it is read — identically to `Array(Tuple(T1, ..., TN))`. (https://github.com/ClickHouse/clickhouse-java/issues/2477) +- **[jdbc-v2]** Fixed `java.sql.Array#getResultSet()` on an un-flattened `Nested(...)` column throwing `Value of class [Ljava.lang.Object; cannot be converted to class java.lang.Byte`. The array `ResultSet` now exposes each nested row as its `Tuple(f1 T1, ..., fN TN)` element type instead of the first nested field, so `getObject` returns the whole tuple. Insert (via `Connection#createArrayOf` + `setArray` or `setObject`) and read (via `getArray`/`getObject`) of `Nested(...)` columns are covered by tests. (https://github.com/ClickHouse/clickhouse-java/issues/2477) + - **[client-v2]** Fixed binary array decoding for nullable element types so `Array(Nullable(Float64))` and similar columns now return boxed arrays such as `Double[]` instead of `Object[]`. This keeps null-supporting arrays aligned with their element type while preserving the existing `Object[]` fallback for Variant/Dynamic/Geometry arrays. (https://github.com/ClickHouse/clickhouse-java/issues/2846) - **[client-v2]** Fixed `Float32`/`Float64` columns throwing `ClassCastException` when a value of a diff --git a/docs/features.md b/docs/features.md index 4237a80cd..1a753e9ee 100644 --- a/docs/features.md +++ b/docs/features.md @@ -75,6 +75,7 @@ Compatibility-sensitive traits: - Type mapping and conversions: Maps ClickHouse types to JDBC types and Java classes, including date/time handling and `java.time` support. - Custom result-set type map: `ResultSet#getObject(int|String, Map>)` accepts both ClickHouse type names and JDBC `SQLType` names as map keys. Only unwrapped type names are used — `Nullable(...)` and `LowCardinality(...)` wrappers are stripped before lookup, so a key like `"Int32"` matches both `Int32` and `Nullable(Int32)` columns, and keys like `"Nullable(Int32)"` are not recognized. Lookup order is `ClickHouseColumn#getDataType().name()` (e.g. `"Int32"`, `"String"`, `"DateTime"`) then `SQLType.getName()` (e.g. `"INTEGER"`, `"VARCHAR"`, `"TIMESTAMP"`); a missing entry leaves the value uncoerced (read as-is). The feature is supported for primitive ClickHouse types only — `Array`, `Tuple`, `Map`, `Nested`, and geometry types (`Point`, `Ring`, `LineString`, `Polygon`, `MultiPolygon`, `MultiLineString`, `Geometry`) bypass the type map and are returned in their native form. - Arrays and tuples: Supports JDBC arrays plus ClickHouse tuple values through custom `Array` and `Struct` implementations. +- Nested columns: Un-flattened `Nested(f1 T1, ..., fN TN)` columns (tables created with `flatten_nested = 0`) are exposed as JDBC `ARRAY` whose element type is `Tuple(f1 T1, ..., fN TN)`. They can be inserted through `Connection#createArrayOf`/`setArray` or `setObject` (a Java array of tuples) and read back through `getArray`/`getObject`; `java.sql.Array#getResultSet()` iterates the nested rows as `(INDEX, VALUE)` pairs where each `VALUE` is the tuple. - Geometry type mapping: For ClickHouse `25.11+`, where `Geometry` changed from a string alias to `Variant(Point, Ring, LineString, MultiLineString, Polygon, MultiPolygon)`, JDBC exposes `Geometry` as `ARRAY`, returns nested Java arrays from `getObject()`/`getArray()`, and accepts `Struct` or nested `Array` inputs for prepared-statement inserts depending on the geometry shape. - Client info propagation: Supports JDBC client info such as `ApplicationName` and forwards it to the underlying client name. - Wrapper support: Implements standard JDBC `Wrapper` and `unwrap` behavior on major JDBC objects. diff --git a/jdbc-v2/src/main/java/com/clickhouse/jdbc/types/ArrayResultSet.java b/jdbc-v2/src/main/java/com/clickhouse/jdbc/types/ArrayResultSet.java index 9965978dd..97da74a06 100644 --- a/jdbc-v2/src/main/java/com/clickhouse/jdbc/types/ArrayResultSet.java +++ b/jdbc-v2/src/main/java/com/clickhouse/jdbc/types/ArrayResultSet.java @@ -64,8 +64,7 @@ public ArrayResultSet(Object array, ClickHouseColumn column) { this.column = column; this.columnCount = 2; // INDEX, VALUE - List nestedColumns = column.getNestedColumns(); - ClickHouseColumn valueColumn = column.getArrayNestedLevel() == 1 ? column.getArrayBaseColumn() : nestedColumns.get(0); + ClickHouseColumn valueColumn = elementColumn(column); this.metadata = new ResultSetMetaDataImpl(Arrays.asList(INDEX_COLUMN, ClickHouseColumn.parse(VALUE_COLUMN + " " + valueColumn.getOriginalTypeName()).get(0)) , "", "", "", JdbcUtils.DATA_TYPE_CLASS_MAP, java.util.Collections.emptyMap()); @@ -74,6 +73,29 @@ public ArrayResultSet(Object array, ClickHouseColumn column) { indexConverterMap = defaultValueConverters.getConvertersForType(Integer.class); } + /** + * Resolves the type of a single element of {@code column} (an array-like column). A + * {@code Nested(f1 T1, ..., fN TN)} column is read as an array whose elements are + * {@code Tuple(f1 T1, ..., fN TN)}, so its element is that tuple rather than the first nested + * field; every other array-like column keeps its existing base/nested-column resolution. + */ + private static ClickHouseColumn elementColumn(ClickHouseColumn column) { + List nestedColumns = column.getNestedColumns(); + if (column.isNested()) { + StringBuilder tupleType = new StringBuilder(ClickHouseDataType.Tuple.name()).append('('); + for (int i = 0; i < nestedColumns.size(); i++) { + ClickHouseColumn field = nestedColumns.get(i); + if (i > 0) { + tupleType.append(", "); + } + tupleType.append(field.getColumnName()).append(' ').append(field.getOriginalTypeName()); + } + tupleType.append(')'); + return ClickHouseColumn.of(VALUE_COLUMN, tupleType.toString()); + } + return column.getArrayNestedLevel() == 1 ? column.getArrayBaseColumn() : nestedColumns.get(0); + } + @Override public boolean next() throws SQLException { if (pos + 1 >= length || length == 0) { @@ -139,9 +161,7 @@ private Object getValueAsObject(int columnIndex, Class type, Object defaultVa } if (type == Array.class) { - ClickHouseColumn nestedColumn = - column.getArrayNestedLevel() == 1 ? column.getArrayBaseColumn() : column.getNestedColumns().get(0); - return new com.clickhouse.jdbc.types.Array(nestedColumn, JdbcUtils.arrayToObjectArray(value)); + return new com.clickhouse.jdbc.types.Array(elementColumn(column), JdbcUtils.arrayToObjectArray(value)); } else { Map, Function> valueConverterMap = initValueConverterMapIfNeeded(value); return convertValue(value, type, valueConverterMap); diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/JdbcDataTypeTests.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/JdbcDataTypeTests.java index ed0b00cb9..a97f9bcba 100644 --- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/JdbcDataTypeTests.java +++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/JdbcDataTypeTests.java @@ -1516,6 +1516,92 @@ public void testArrayTypes() throws SQLException { } } + @Test(groups = { "integration" }) + public void testNestedType() throws SQLException { + runQuery("DROP TABLE IF EXISTS test_nested_jdbc"); + runQuery("CREATE TABLE test_nested_jdbc (order Int8, " + + "n Nested(a Int8, b Nullable(String)), " + + "tail Int32" + + ") ENGINE = MergeTree ORDER BY (order) SETTINGS flatten_nested = 0"); + + // A null in the Nullable field exercises null propagation through every read path. + Tuple[] nested = new Tuple[] { + new Tuple((byte) 1, "x"), + new Tuple((byte) 2, null), + }; + Tuple[] empty = new Tuple[0]; + + // Row 1: insert the Nested column through java.sql.Array (Connection#createArrayOf + setArray). + try (Connection conn = getJdbcConnection(); + PreparedStatement stmt = conn.prepareStatement("INSERT INTO test_nested_jdbc VALUES (1, ?, 100)")) { + stmt.setArray(1, conn.createArrayOf("Tuple(Int8, String)", nested)); + stmt.executeUpdate(); + } + + // Row 2: insert the same Nested value as a plain Java array of tuples (setObject). + try (Connection conn = getJdbcConnection(); + PreparedStatement stmt = conn.prepareStatement("INSERT INTO test_nested_jdbc VALUES (2, ?, 200)")) { + stmt.setObject(1, nested); + stmt.executeUpdate(); + } + + // Row 3: an empty Nested value, so the read paths cover a zero-row array. + try (Connection conn = getJdbcConnection(); + PreparedStatement stmt = conn.prepareStatement("INSERT INTO test_nested_jdbc VALUES (3, ?, 300)")) { + stmt.setObject(1, empty); + stmt.executeUpdate(); + } + + try (Connection conn = getJdbcConnection(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT order, n, tail FROM test_nested_jdbc ORDER BY order")) { + // Row 1 read through getArray + assertTrue(rs.next()); + assertEquals(rs.getByte("order"), (byte) 1); + assertNestedEquals(rs.getArray("n"), nested); + assertEquals(rs.getInt("tail"), 100); + + // Row 2 read through getObject + assertTrue(rs.next()); + assertEquals(rs.getByte("order"), (byte) 2); + assertNestedEquals((Array) rs.getObject("n"), nested); + assertEquals(rs.getInt("tail"), 200); + + // Row 3: empty Nested -> empty array and an empty getResultSet(). + assertTrue(rs.next()); + assertEquals(rs.getByte("order"), (byte) 3); + assertNestedEquals(rs.getArray("n"), empty); + assertEquals(rs.getInt("tail"), 300); + + assertFalse(rs.next()); + } + } + + private static void assertNestedEquals(Array nestedColumn, Tuple[] expected) throws SQLException { + // getArray() yields one element per nested row, each an Object[] of the tuple field values. + Object[] rows = (Object[]) nestedColumn.getArray(); + assertEquals(rows.length, expected.length); + for (int i = 0; i < expected.length; i++) { + assertTupleEquals((Object[]) rows[i], expected[i]); + } + + // getResultSet() exposes the same rows as (INDEX, VALUE) pairs. + try (ResultSet ars = nestedColumn.getResultSet()) { + int seen = 0; + while (ars.next()) { + assertEquals(ars.getInt(1), seen + 1); + assertTupleEquals((Object[]) ars.getObject(2), expected[seen]); + seen++; + } + assertEquals(seen, expected.length); + } + } + + private static void assertTupleEquals(Object[] actual, Tuple expected) { + assertEquals(String.valueOf(actual[0]), String.valueOf(expected.getValue(0))); + assertEquals(actual[1], expected.getValue(1)); // Nullable(String): null stays null + } + @Test(groups = { "integration" }) public void testStringsUsedAsBytes() throws Exception { runQuery("CREATE TABLE test_strings_as_bytes (order Int8, str String, fixed FixedString(10)) ENGINE = MergeTree ORDER BY ()"); From 9c0fed6d09faeb8290d3ea4fada4e633942124e7 Mon Sep 17 00:00:00 2001 From: Polyglot AI <293096396+polyglotAI-bot@users.noreply.github.com> Date: Sun, 26 Jul 2026 12:50:13 +0000 Subject: [PATCH 4/4] test(jdbc-v2): declare Nullable field in Nested createArrayOf element type testNestedType inserts into Nested(a Int8, b Nullable(String)); align the createArrayOf element type to Tuple(Int8, Nullable(String)) so the declared element type honestly matches the column. Rendering is unchanged (the array's base data type is Tuple either way, and a null field renders as NULL value-driven), so this only makes the declared type honest and removes brittleness if createArrayOf ever validates element types more strictly. --- .../src/test/java/com/clickhouse/jdbc/JdbcDataTypeTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/JdbcDataTypeTests.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/JdbcDataTypeTests.java index a97f9bcba..bcab0f373 100644 --- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/JdbcDataTypeTests.java +++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/JdbcDataTypeTests.java @@ -1534,7 +1534,7 @@ public void testNestedType() throws SQLException { // Row 1: insert the Nested column through java.sql.Array (Connection#createArrayOf + setArray). try (Connection conn = getJdbcConnection(); PreparedStatement stmt = conn.prepareStatement("INSERT INTO test_nested_jdbc VALUES (1, ?, 100)")) { - stmt.setArray(1, conn.createArrayOf("Tuple(Int8, String)", nested)); + stmt.setArray(1, conn.createArrayOf("Tuple(Int8, Nullable(String))", nested)); stmt.executeUpdate(); }