diff --git a/client-v2/pom.xml b/client-v2/pom.xml
index 0c6409cdf..57ff943a8 100644
--- a/client-v2/pom.xml
+++ b/client-v2/pom.xml
@@ -88,8 +88,26 @@
com.fasterxml.jackson.core
jackson-databind
- test
${jackson.version}
+ provided
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${jackson.version}
+ provided
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${jackson.version}
+ provided
+
+
+ com.google.code.gson
+ gson
+ ${gson.version}
+ provided
${project.parent.groupId}
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 d4f979026..d4e43ef22 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
@@ -3,11 +3,14 @@
import com.clickhouse.client.api.command.CommandResponse;
import com.clickhouse.client.api.command.CommandSettings;
import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
+import com.clickhouse.client.api.data_formats.JSONEachRowFormatReader;
import com.clickhouse.client.api.data_formats.NativeFormatReader;
import com.clickhouse.client.api.data_formats.RowBinaryFormatReader;
import com.clickhouse.client.api.data_formats.RowBinaryWithNamesAndTypesFormatReader;
import com.clickhouse.client.api.data_formats.RowBinaryWithNamesFormatReader;
import com.clickhouse.client.api.data_formats.internal.BinaryStreamReader;
+import com.clickhouse.client.api.data_formats.internal.JsonParser;
+import com.clickhouse.client.api.data_formats.internal.JsonParserFactory;
import com.clickhouse.client.api.data_formats.internal.MapBackedRecord;
import com.clickhouse.client.api.data_formats.internal.ProcessParser;
import com.clickhouse.client.api.enums.Protocol;
@@ -2077,6 +2080,11 @@ public ClickHouseBinaryFormatReader newBinaryFormatReader(QueryResponse response
reader = new RowBinaryFormatReader(response.getInputStream(), response.getSettings(), schema,
byteBufferPool, typeHintMapping);
break;
+ case JSONEachRow:
+ String jsonProcessor = ClientConfigProperties.JSON_PROCESSOR.getOrDefault(configuration);
+ JsonParser parser = JsonParserFactory.createParser(jsonProcessor, response.getInputStream());
+ reader = new JSONEachRowFormatReader(parser);
+ break;
default:
throw new IllegalArgumentException("Binary readers doesn't support format: " + response.getFormat());
}
diff --git a/client-v2/src/main/java/com/clickhouse/client/api/ClientConfigProperties.java b/client-v2/src/main/java/com/clickhouse/client/api/ClientConfigProperties.java
index e548a90f9..9c40e48dd 100644
--- a/client-v2/src/main/java/com/clickhouse/client/api/ClientConfigProperties.java
+++ b/client-v2/src/main/java/com/clickhouse/client/api/ClientConfigProperties.java
@@ -196,6 +196,15 @@ public Object parseValue(String value) {
* See ClickHouse Docs
*/
CUSTOM_SETTINGS_PREFIX("custom_settings_prefix", String.class, "custom_"),
+
+ /**
+ * Configures what JSON processor will be used for JSON formats. Choices:
+ *
+ * - JACKSON - uses Jackson library.
+ * - GSON - uses Gson library.
+ *
+ */
+ JSON_PROCESSOR("json_processor", String.class, "JACKSON"),
;
private static final Logger LOG = LoggerFactory.getLogger(ClientConfigProperties.class);
diff --git a/client-v2/src/main/java/com/clickhouse/client/api/data_formats/JSONEachRowFormatReader.java b/client-v2/src/main/java/com/clickhouse/client/api/data_formats/JSONEachRowFormatReader.java
new file mode 100644
index 000000000..d0615e526
--- /dev/null
+++ b/client-v2/src/main/java/com/clickhouse/client/api/data_formats/JSONEachRowFormatReader.java
@@ -0,0 +1,528 @@
+package com.clickhouse.client.api.data_formats;
+
+import com.clickhouse.client.api.data_formats.internal.JsonParser;
+import com.clickhouse.client.api.metadata.TableSchema;
+import com.clickhouse.data.ClickHouseColumn;
+import com.clickhouse.data.ClickHouseDataType;
+import com.clickhouse.data.value.ClickHouseBitmap;
+import com.clickhouse.data.value.ClickHouseGeoMultiPolygonValue;
+import com.clickhouse.data.value.ClickHouseGeoPointValue;
+import com.clickhouse.data.value.ClickHouseGeoPolygonValue;
+import com.clickhouse.data.value.ClickHouseGeoRingValue;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.ZonedDateTime;
+import java.time.temporal.TemporalAmount;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public class JSONEachRowFormatReader implements ClickHouseBinaryFormatReader {
+ private final JsonParser parser;
+ private TableSchema schema;
+ private Map currentRow;
+ private Map firstRow;
+ private boolean firstRowRead = false;
+
+ public JSONEachRowFormatReader(JsonParser parser) {
+ this.parser = parser;
+ try {
+ this.firstRow = parser.nextRow();
+ if (firstRow != null) {
+ List columns = new ArrayList<>();
+ for (String key : firstRow.keySet()) {
+ // For JSONEachRow we don't know the exact ClickHouse type, so we use a reasonable default.
+ // We can try to guess based on the value type in the first row.
+ columns.add(ClickHouseColumn.of(key, guessDataType(firstRow.get(key)), false));
+ }
+ this.schema = new TableSchema(columns);
+ } else {
+ this.schema = new TableSchema(new ArrayList<>());
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to initialize JSON reader", e);
+ }
+ }
+
+ private ClickHouseDataType guessDataType(Object value) {
+ if (value instanceof Number) {
+ if (value instanceof Integer || value instanceof Long || value instanceof BigInteger) {
+ return ClickHouseDataType.Int64;
+ } else if (value instanceof Double || value instanceof Float || value instanceof BigDecimal) {
+ double d = ((Number) value).doubleValue();
+ if (d == Math.floor(d) && !Double.isInfinite(d) && d <= Long.MAX_VALUE && d >= Long.MIN_VALUE) {
+ return ClickHouseDataType.Int64;
+ }
+ return ClickHouseDataType.Float64;
+ } else {
+ return ClickHouseDataType.Float64;
+ }
+ } else if (value instanceof Boolean) {
+ return ClickHouseDataType.Bool;
+ } else {
+ return ClickHouseDataType.String;
+ }
+ }
+
+ @Override
+ public T readValue(int colIndex) {
+ return (T) currentRow.get(schema.columnIndexToName(colIndex));
+ }
+
+ @Override
+ public T readValue(String colName) {
+ return (T) currentRow.get(colName);
+ }
+
+ @Override
+ public boolean hasValue(String colName) {
+ return currentRow.containsKey(colName) && currentRow.get(colName) != null;
+ }
+
+ @Override
+ public boolean hasValue(int colIndex) {
+ return hasValue(schema.columnIndexToName(colIndex));
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (!firstRowRead) {
+ return firstRow != null;
+ }
+ return true; // We'll find out in next()
+ }
+
+ @Override
+ public Map next() {
+ if (!firstRowRead) {
+ firstRowRead = true;
+ currentRow = firstRow;
+ return currentRow;
+ }
+ try {
+ currentRow = parser.nextRow();
+ return currentRow;
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to read next JSON row", e);
+ }
+ }
+
+ @Override
+ public String getString(String colName) {
+ Object val = currentRow.get(colName);
+ return val == null ? null : val.toString();
+ }
+
+ @Override
+ public byte getByte(String colName) {
+ return ((Number) currentRow.get(colName)).byteValue();
+ }
+
+ @Override
+ public short getShort(String colName) {
+ return ((Number) currentRow.get(colName)).shortValue();
+ }
+
+ @Override
+ public int getInteger(String colName) {
+ return ((Number) currentRow.get(colName)).intValue();
+ }
+
+ @Override
+ public long getLong(String colName) {
+ return ((Number) currentRow.get(colName)).longValue();
+ }
+
+ @Override
+ public float getFloat(String colName) {
+ return ((Number) currentRow.get(colName)).floatValue();
+ }
+
+ @Override
+ public double getDouble(String colName) {
+ return ((Number) currentRow.get(colName)).doubleValue();
+ }
+
+ @Override
+ public boolean getBoolean(String colName) {
+ Object val = currentRow.get(colName);
+ if (val instanceof Boolean) return (Boolean) val;
+ if (val instanceof Number) return ((Number) val).intValue() != 0;
+ return Boolean.parseBoolean(val.toString());
+ }
+
+ @Override
+ public BigInteger getBigInteger(String colName) {
+ Object val = currentRow.get(colName);
+ if (val == null) return null;
+ if (val instanceof BigInteger) return (BigInteger) val;
+ return new BigDecimal(val.toString()).toBigInteger();
+ }
+
+ @Override
+ public BigDecimal getBigDecimal(String colName) {
+ Object val = currentRow.get(colName);
+ if (val instanceof BigDecimal) return (BigDecimal) val;
+ return new BigDecimal(val.toString());
+ }
+
+ @Override
+ public Instant getInstant(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ZonedDateTime getZonedDateTime(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Duration getDuration(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Inet4Address getInet4Address(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Inet6Address getInet6Address(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public UUID getUUID(String colName) {
+ return UUID.fromString(currentRow.get(colName).toString());
+ }
+
+ @Override
+ public ClickHouseGeoPointValue getGeoPoint(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ClickHouseGeoRingValue getGeoRing(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ClickHouseGeoPolygonValue getGeoPolygon(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ClickHouseGeoMultiPolygonValue getGeoMultiPolygon(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List getList(String colName) {
+ return (List) currentRow.get(colName);
+ }
+
+ @Override
+ public byte[] getByteArray(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int[] getIntArray(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long[] getLongArray(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public float[] getFloatArray(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double[] getDoubleArray(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean[] getBooleanArray(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public short[] getShortArray(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getStringArray(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object[] getObjectArray(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getString(int index) {
+ return getString(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public byte getByte(int index) {
+ return getByte(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public short getShort(int index) {
+ return getShort(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public int getInteger(int index) {
+ return getInteger(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public long getLong(int index) {
+ return getLong(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public float getFloat(int index) {
+ return getFloat(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return getDouble(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public boolean getBoolean(int index) {
+ return getBoolean(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public BigInteger getBigInteger(int index) {
+ return getBigInteger(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public BigDecimal getBigDecimal(int index) {
+ return getBigDecimal(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public Instant getInstant(int index) {
+ return getInstant(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public ZonedDateTime getZonedDateTime(int index) {
+ return getZonedDateTime(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public Duration getDuration(int index) {
+ return getDuration(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public Inet4Address getInet4Address(int index) {
+ return getInet4Address(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public Inet6Address getInet6Address(int index) {
+ return getInet6Address(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public UUID getUUID(int index) {
+ return getUUID(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public ClickHouseGeoPointValue getGeoPoint(int index) {
+ return getGeoPoint(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public ClickHouseGeoRingValue getGeoRing(int index) {
+ return getGeoRing(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public ClickHouseGeoPolygonValue getGeoPolygon(int index) {
+ return getGeoPolygon(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public ClickHouseGeoMultiPolygonValue getGeoMultiPolygon(int index) {
+ return getGeoMultiPolygon(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public List getList(int index) {
+ return getList(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public byte[] getByteArray(int index) {
+ return getByteArray(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public int[] getIntArray(int index) {
+ return getIntArray(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public long[] getLongArray(int index) {
+ return getLongArray(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public float[] getFloatArray(int index) {
+ return getFloatArray(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public double[] getDoubleArray(int index) {
+ return getDoubleArray(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public boolean[] getBooleanArray(int index) {
+ return getBooleanArray(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public short[] getShortArray(int index) {
+ return getShortArray(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public String[] getStringArray(int index) {
+ return getStringArray(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public Object[] getObjectArray(int index) {
+ return getObjectArray(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public Object[] getTuple(int index) {
+ return getTuple(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public Object[] getTuple(String colName) {
+ return (Object[]) currentRow.get(colName);
+ }
+
+ @Override
+ public byte getEnum8(String colName) {
+ return getByte(colName);
+ }
+
+ @Override
+ public byte getEnum8(int index) {
+ return getByte(index);
+ }
+
+ @Override
+ public short getEnum16(String colName) {
+ return getShort(colName);
+ }
+
+ @Override
+ public short getEnum16(int index) {
+ return getShort(index);
+ }
+
+ @Override
+ public LocalDate getLocalDate(String colName) {
+ return LocalDate.parse(currentRow.get(colName).toString());
+ }
+
+ @Override
+ public LocalDate getLocalDate(int index) {
+ return getLocalDate(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public LocalTime getLocalTime(String colName) {
+ return LocalTime.parse(currentRow.get(colName).toString());
+ }
+
+ @Override
+ public LocalTime getLocalTime(int index) {
+ return getLocalTime(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public LocalDateTime getLocalDateTime(String colName) {
+ return LocalDateTime.parse(currentRow.get(colName).toString());
+ }
+
+ @Override
+ public LocalDateTime getLocalDateTime(int index) {
+ return getLocalDateTime(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public OffsetDateTime getOffsetDateTime(String colName) {
+ return OffsetDateTime.parse(currentRow.get(colName).toString());
+ }
+
+ @Override
+ public OffsetDateTime getOffsetDateTime(int index) {
+ return getOffsetDateTime(schema.columnIndexToName(index));
+ }
+
+ @Override
+ public TableSchema getSchema() {
+ return schema;
+ }
+
+ @Override
+ public ClickHouseBitmap getClickHouseBitmap(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ClickHouseBitmap getClickHouseBitmap(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TemporalAmount getTemporalAmount(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TemporalAmount getTemporalAmount(String colName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void close() throws Exception {
+ parser.close();
+ }
+}
diff --git a/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/GsonJsonParser.java b/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/GsonJsonParser.java
new file mode 100644
index 000000000..fe70ec93f
--- /dev/null
+++ b/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/GsonJsonParser.java
@@ -0,0 +1,39 @@
+package com.clickhouse.client.api.data_formats.internal;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+public class GsonJsonParser implements JsonParser {
+ private final Gson gson;
+ private final JsonReader reader;
+
+ public GsonJsonParser(InputStream inputStream) {
+ this.gson = new Gson();
+ this.reader = new JsonReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+ this.reader.setLenient(true); // JSONEachRow needs lenient reader for multiple root objects
+ }
+
+ @Override
+ public Map nextRow() throws Exception {
+ try {
+ if (reader.peek() == JsonToken.END_DOCUMENT) {
+ return null;
+ }
+ } catch (java.io.EOFException e) {
+ return null;
+ }
+ return gson.fromJson(reader, new TypeToken
-
com.fasterxml.jackson.core
jackson-databind
- test
${jackson.version}
+ provided
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${jackson.version}
+ provided
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${jackson.version}
+ provided
+
+
+
+ com.google.code.gson
+ gson
+ ${gson.version}
+ provided
+
+
+
${project.parent.groupId}
clickhouse-client
@@ -89,18 +110,6 @@
test
-
- com.fasterxml.jackson.core
- jackson-core
- ${jackson.version}
- test
-
-
- com.fasterxml.jackson.core
- jackson-databind
- ${jackson.version}
- test
-
com.fasterxml.jackson.dataformat
jackson-dataformat-yaml
@@ -211,4 +220,4 @@
-
\ No newline at end of file
+
diff --git a/jdbc-v2/src/main/java/com/clickhouse/jdbc/DriverProperties.java b/jdbc-v2/src/main/java/com/clickhouse/jdbc/DriverProperties.java
index 7027c95c1..bb6d4ce08 100644
--- a/jdbc-v2/src/main/java/com/clickhouse/jdbc/DriverProperties.java
+++ b/jdbc-v2/src/main/java/com/clickhouse/jdbc/DriverProperties.java
@@ -78,9 +78,17 @@ public enum DriverProperties {
*/
QUERY_ID_GENERATOR("jdbc_query_id_generator", null),
+ /**
+ * Configures what JSON processor will be used for JSON formats. Choices:
+ *
+ * - JACKSON - uses Jackson library.
+ * - GSON - uses Gson library.
+ *
+ */
+ JSON_PROCESSOR("json_processor", "JACKSON", Arrays.asList("JACKSON", "GSON")),
+
/**
* Controls logic of saving roles that were set using {@code SET } statement.
- * Default: true - save roles
*/
REMEMBER_LAST_SET_ROLES("remember_last_set_roles", String.valueOf(Boolean.TRUE)),
diff --git a/jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java b/jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java
index f50546393..59949c6f5 100644
--- a/jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java
+++ b/jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java
@@ -6,6 +6,7 @@
import com.clickhouse.client.api.query.QueryResponse;
import com.clickhouse.client.api.query.QuerySettings;
import com.clickhouse.client.api.sql.SQLUtils;
+import com.clickhouse.data.ClickHouseFormat;
import com.clickhouse.jdbc.internal.ExceptionUtils;
import com.clickhouse.jdbc.internal.FeatureManager;
import com.clickhouse.jdbc.internal.ParsedStatement;
@@ -177,11 +178,14 @@ protected ResultSetImpl executeQueryImpl(String sql, QuerySettings settings) thr
response = connection.getClient().query(lastStatementSql, mergedSettings).get(queryTimeout, TimeUnit.SECONDS);
}
- if (response.getFormat().isText()) {
- throw new SQLException("Only RowBinaryWithNameAndTypes is supported for output format. Please check your query.",
+ ClickHouseBinaryFormatReader reader;
+ if (response.getFormat() == ClickHouseFormat.JSONEachRow || !response.getFormat().isText()) {
+ reader = connection.getClient().newBinaryFormatReader(response);
+ } else {
+ throw new SQLException("Only RowBinaryWithNameAndTypes and JSONEachRow are supported for output format. Please check your query.",
ExceptionUtils.SQL_STATE_CLIENT_ERROR);
}
- ClickHouseBinaryFormatReader reader = connection.getClient().newBinaryFormatReader(response);
+
if (reader.getSchema() == null) {
long writtenRows = 0L;
try {
diff --git a/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcConfiguration.java b/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcConfiguration.java
index 9aa5ce61a..6fd387297 100644
--- a/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcConfiguration.java
+++ b/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcConfiguration.java
@@ -303,6 +303,8 @@ private void initProperties(Map urlProperties, Properties provid
prop.getKey().equalsIgnoreCase(DriverProperties.CUSTOM_SETTINGS.getKey())) {
ClientConfigProperties.toKeyValuePairs(prop.getValue())
.forEach((k, v) -> clientProperties.put(ClientConfigProperties.serverSetting(k), v));
+ } else if (prop.getKey().equalsIgnoreCase(DriverProperties.JSON_PROCESSOR.getKey())) {
+ clientProperties.put(prop.getKey(), prop.getValue());
}
driverProperties.put(prop.getKey(), prop.getValue());
} else {
diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/StatementTest.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/StatementTest.java
index 575dde388..f7fdb1295 100644
--- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/StatementTest.java
+++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/StatementTest.java
@@ -619,6 +619,38 @@ public void testTextFormatInResponse() throws Exception {
}
}
+ @Test(groups = {"integration"})
+ public void testJSONEachRowFormat() throws Exception {
+ Properties properties = new Properties();
+ properties.setProperty(DriverProperties.JSON_PROCESSOR.getKey(), "JACKSON");
+ try (Connection conn = getJdbcConnection(properties)) {
+ try (Statement stmt = conn.createStatement()) {
+ try (ResultSet rs = stmt.executeQuery("SELECT 1 AS num, 'test' AS str FORMAT JSONEachRow")) {
+ assertTrue(rs.next());
+ assertEquals(rs.getInt("num"), 1);
+ assertEquals(rs.getString("str"), "test");
+ assertFalse(rs.next());
+ }
+ }
+ }
+ }
+
+ @Test(groups = {"integration"})
+ public void testJSONEachRowFormatGson() throws Exception {
+ Properties properties = new Properties();
+ properties.setProperty(DriverProperties.JSON_PROCESSOR.getKey(), "GSON");
+ try (Connection conn = getJdbcConnection(properties)) {
+ try (Statement stmt = conn.createStatement()) {
+ try (ResultSet rs = stmt.executeQuery("SELECT 2 AS num, 'gson' AS str FORMAT JSONEachRow")) {
+ assertTrue(rs.next());
+ assertEquals(rs.getInt("num"), 2);
+ assertEquals(rs.getString("str"), "gson");
+ assertFalse(rs.next());
+ }
+ }
+ }
+ }
+
@Test(groups = "integration")
void testWithClause() throws Exception {
int count = 0;