Skip to content

Commit 7694367

Browse files
committed
fixed DataTypeConverter for nested arrays when target accumulator was set to null
1 parent 5e1c4c4 commit 7694367

2 files changed

Lines changed: 71 additions & 4 deletions

File tree

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,12 +261,16 @@ protected void onItem(Object item, ListConversionState<Object> state) {
261261
}
262262

263263
public String convertAndReset(Object list, Appendable acc, ClickHouseColumn column) {
264+
// Save current state to handle re-entrancy (nested array conversion)
265+
ClickHouseColumn prevColumn = this.column;
266+
Appendable prevAppendable = this.appendable;
264267
try {
265268
setColumn(column);
266269
return super.convert(list, acc);
267270
} finally {
268-
this.column = null;
269-
setAccumulator(null);
271+
// Restore previous state for re-entrant calls
272+
this.column = prevColumn;
273+
setAccumulator(prevAppendable);
270274
}
271275
}
272276
}
@@ -292,12 +296,16 @@ protected void onItem(Object item, ListConversionState<List<?>> state) {
292296
}
293297

294298
public String convertAndReset(List<?> list, Appendable acc, ClickHouseColumn column) {
299+
// Save current state to handle re-entrancy (nested array conversion)
300+
ClickHouseColumn prevColumn = this.column;
301+
Appendable prevAppendable = this.appendable;
295302
try {
296303
setColumn(column);
297304
return super.convert(list, acc);
298305
} finally {
299-
this.column = null;
300-
setAccumulator(null);
306+
// Restore previous state for re-entrant calls
307+
this.column = prevColumn;
308+
setAccumulator(prevAppendable);
301309
}
302310
}
303311
}

jdbc-v2/src/test/java/com/clickhouse/jdbc/DataTypeTests.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,65 @@ public void testNestedArrays() throws Exception {
10671067
}
10681068
}
10691069

1070+
/**
1071+
* Test for https://github.com/ClickHouse/clickhouse-java/issues/2723
1072+
* getString() on nested arrays was failing with NullPointerException due to re-entrancy bug
1073+
* in DataTypeConverter when converting nested arrays to string representation.
1074+
*/
1075+
@Test(groups = { "integration" })
1076+
public void testNestedArrayToString() throws SQLException {
1077+
// Test 1: Simple nested array - getString on Array(Array(Int32))
1078+
try (Connection conn = getJdbcConnection()) {
1079+
try (Statement stmt = conn.createStatement()) {
1080+
try (ResultSet rs = stmt.executeQuery("SELECT [[1, 2, 3], [4, 5, 6]] as nested_array")) {
1081+
assertTrue(rs.next());
1082+
// This was throwing NullPointerException before the fix
1083+
String result = rs.getString("nested_array");
1084+
assertEquals(result, "[[1, 2, 3], [4, 5, 6]]");
1085+
}
1086+
}
1087+
}
1088+
1089+
// Test 2: Query similar to issue #2723 with splitByChar returning array
1090+
// The original issue was that getString() on an array column inside a CASE/WHEN
1091+
// would cause NPE. This test verifies that getString() works correctly on arrays.
1092+
try (Connection conn = getJdbcConnection()) {
1093+
try (Statement stmt = conn.createStatement()) {
1094+
String query = "SELECT " +
1095+
"splitByChar('_', 'field1_field2_field3') as split_result, " +
1096+
"CASE " +
1097+
" WHEN " +
1098+
" splitByChar('_', 'field1_field2_field3')[1] IN ('field1', 'field2') " +
1099+
" AND match( " +
1100+
" splitByChar('_', 'field1_field2_field3')[2], " +
1101+
" '(field1|field2|field3)' " +
1102+
" ) " +
1103+
" THEN 'Matched' " +
1104+
" ELSE 'NotMatched' " +
1105+
"END AS action_to_do";
1106+
try (ResultSet rs = stmt.executeQuery(query)) {
1107+
assertTrue(rs.next());
1108+
// The key test is that getString() doesn't throw NPE on array column
1109+
String splitResult = rs.getString("split_result");
1110+
assertEquals(splitResult, "['field1', 'field2', 'field3']");
1111+
String actionResult = rs.getString("action_to_do");
1112+
assertEquals(actionResult, "Matched");
1113+
}
1114+
}
1115+
}
1116+
1117+
// Test 3: Deeply nested arrays - Array(Array(Array(String)))
1118+
try (Connection conn = getJdbcConnection()) {
1119+
try (Statement stmt = conn.createStatement()) {
1120+
try (ResultSet rs = stmt.executeQuery("SELECT [[['a', 'b'], ['c']], [['d', 'e', 'f']]] as deep_nested")) {
1121+
assertTrue(rs.next());
1122+
String result = rs.getString("deep_nested");
1123+
assertEquals(result, "[[['a', 'b'], ['c']], [['d', 'e', 'f']]]");
1124+
}
1125+
}
1126+
}
1127+
}
1128+
10701129
@Test(groups = { "integration" })
10711130
public void testMapTypes() throws SQLException {
10721131
runQuery("CREATE TABLE test_maps (order Int8, "

0 commit comments

Comments
 (0)