Skip to content

Commit 751dd15

Browse files
committed
reworked ArrayValue and how JDBC handles collection to optimize conversion
1 parent 6f75cb3 commit 751dd15

File tree

4 files changed

+73
-25
lines changed

4 files changed

+73
-25
lines changed

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,34 @@ public synchronized <T> List<T> asList() {
721721
}
722722
return (List<T>) list;
723723
}
724+
725+
/**
726+
* Returns internal array. This method is only useful to work with array of primitives (int[], boolean[]).
727+
* Otherwise use {@link #getArrayOfObjects()}
728+
*
729+
* @return
730+
*/
731+
public Object getArray() {
732+
return array;
733+
}
734+
735+
/**
736+
* Returns array of objects.
737+
* If item type is primitive then all elements will be converted into objects.
738+
*
739+
* @return
740+
*/
741+
public Object[] getArrayOfObjects() {
742+
if (itemType.isPrimitive()) {
743+
Object[] result = new Object[length];
744+
for (int i = 0; i < length; i++) {
745+
result[i] = Array.get(array, i);
746+
}
747+
return result;
748+
} else {
749+
return (Object[]) array;
750+
}
751+
}
724752
}
725753

726754
public static class EnumValue extends Number {

jdbc-v2/src/main/java/com/clickhouse/jdbc/PreparedStatementImpl.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,9 @@ private String encodeObject(Object x, Long length) throws SQLException {
801801
for (int i = 0; i < len; i++) {
802802
listString.append(encodeObject(java.lang.reflect.Array.get(x, i))).append(',');
803803
}
804-
listString.setLength(listString.length() - 1);
804+
if (len > 0) {
805+
listString.setLength(listString.length() - 1);
806+
}
805807
} else {
806808
appendArrayElements((Object[]) x, listString);
807809
}
@@ -811,10 +813,13 @@ private String encodeObject(Object x, Long length) throws SQLException {
811813
} else if (x instanceof Collection) {
812814
StringBuilder listString = new StringBuilder();
813815
listString.append('[');
814-
for (Object item : (Collection<?>) x) {
816+
Collection<?> collection = (Collection<?>) x;
817+
for (Object item : collection) {
815818
listString.append(encodeObject(item)).append(',');
816819
}
817-
listString.setLength(listString.length() - 1);
820+
if (!collection.isEmpty()) {
821+
listString.setLength(listString.length() - 1);
822+
}
818823
listString.append(']');
819824

820825
return listString.toString();
@@ -825,8 +830,10 @@ private String encodeObject(Object x, Long length) throws SQLException {
825830
for (Object key : tmpMap.keySet()) {
826831
mapString.append(encodeObject(key)).append(": ").append(encodeObject(tmpMap.get(key))).append(',');
827832
}
828-
if (!tmpMap.isEmpty())
829-
mapString.delete(mapString.length() - 2, mapString.length());
833+
if (!tmpMap.isEmpty()) {
834+
mapString.setLength(mapString.length() - 1);
835+
}
836+
830837
mapString.append('}');
831838

832839
return mapString.toString();
@@ -859,7 +866,9 @@ private void appendArrayElements(Object[] array, StringBuilder sb) throws SQLExc
859866
for (Object item : array) {
860867
sb.append(encodeObject(item)).append(',');
861868
}
862-
sb.setLength(sb.length() - 1);
869+
if (array.length > 0) {
870+
sb.setLength(sb.length() - 1);
871+
}
863872
}
864873

865874
private String arrayToTuple(Object[] array) throws SQLException {

jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcUtils.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -261,15 +261,21 @@ public static Object convert(Object value, Class<?> type, ClickHouseColumn colum
261261
} else if (type == java.sql.Time.class && value instanceof TemporalAccessor) {
262262
return java.sql.Time.valueOf(LocalTime.from((TemporalAccessor) value));
263263
} else if (type == java.sql.Array.class && value instanceof BinaryStreamReader.ArrayValue) {//It's cleaner to use getList but this handles the more generic getObject
264+
BinaryStreamReader.ArrayValue arrayValue = (BinaryStreamReader.ArrayValue) value;
264265
if (column != null && column.getArrayBaseColumn() != null) {
265-
return new Array(convertList(((BinaryStreamReader.ArrayValue) value).asList(), JdbcUtils.convertToJavaClass(column.getArrayBaseColumn().getDataType())), "Object", JDBCType.JAVA_OBJECT.getVendorTypeNumber());
266+
ClickHouseDataType baseType = column.getArrayBaseColumn().getDataType();
267+
Object[] convertedValues = convertArray(arrayValue.getArrayOfObjects(),
268+
JdbcUtils.convertToJavaClass(column.getArrayBaseColumn().getDataType()));
269+
return new Array(baseType.getName(), baseType.getVendorTypeNumber(), convertedValues);
266270
}
267-
return new Array(((BinaryStreamReader.ArrayValue) value).asList(), "Object", JDBCType.JAVA_OBJECT.getVendorTypeNumber());
271+
return new Array("Object", JDBCType.JAVA_OBJECT.getVendorTypeNumber(), arrayValue.getArrayOfObjects());
268272
} else if (type == java.sql.Array.class && value instanceof List<?>) {
269273
if (column != null && column.getArrayBaseColumn() != null) {
270-
return new Array(convertList(((List) value), JdbcUtils.convertToJavaClass(column.getArrayBaseColumn().getDataType())), "Object", JDBCType.JAVA_OBJECT.getVendorTypeNumber());
274+
ClickHouseDataType baseType = column.getArrayBaseColumn().getDataType();
275+
return new Array(baseType.getName(), JdbcUtils.CLICKHOUSE_TO_SQL_TYPE_MAP.getOrDefault(baseType, JDBCType.OTHER).getVendorTypeNumber(), convertList((List<?>) value, JdbcUtils.convertToJavaClass(column.getArrayBaseColumn().getDataType())) );
271276
}
272-
return new Array((List) value, "Object", JDBCType.JAVA_OBJECT.getVendorTypeNumber());
277+
// base type is unknown. all objects should be converted
278+
return new Array("Object", JDBCType.JAVA_OBJECT.getVendorTypeNumber(), ((List<?>) value).toArray());
273279
} else if (type == Inet4Address.class && value instanceof Inet6Address) {
274280
// Convert Inet6Address to Inet4Address
275281
return Inet4Address.getByName(value.toString());
@@ -286,14 +292,25 @@ public static Object convert(Object value, Class<?> type, ClickHouseColumn colum
286292
throw new SQLException("Unsupported conversion from " + value.getClass().getName() + " to " + type.getName(), ExceptionUtils.SQL_STATE_DATA_EXCEPTION);
287293
}
288294

289-
public static List<Object> convertList(List<Object> values, Class<?> type) throws SQLException {
295+
public static Object[] convertList(List<?> values, Class<?> type) throws SQLException {
296+
if (values == null) {
297+
return null;
298+
}
299+
300+
Object[] convertedValues = new Object[values.size()];
301+
for (int i = 0; i < values.size(); i++) {
302+
convertedValues[i] = convert(values.get(i), type);
303+
}
304+
return convertedValues;
305+
}
306+
307+
public static Object[] convertArray(Object[] values, Class<?> type) throws SQLException {
290308
if (values == null || type == null) {
291309
return values;
292310
}
293-
294-
List<Object> convertedValues = new ArrayList<>(values.size());
295-
for (Object value : values) {
296-
convertedValues.add(convert(value, type));
311+
Object[] convertedValues = new Object[values.length];
312+
for (int i = 0; i < values.length; i++) {
313+
convertedValues[i] = convert(values[i], type);
297314
}
298315
return convertedValues;
299316
}

jdbc-v2/src/main/java/com/clickhouse/jdbc/types/Array.java

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.sql.ResultSet;
88
import java.sql.SQLException;
99
import java.sql.SQLFeatureNotSupportedException;
10-
import java.util.Arrays;
1110
import java.util.List;
1211
import java.util.Map;
1312

@@ -17,16 +16,11 @@ public class Array implements java.sql.Array {
1716
int type; //java.sql.Types
1817
String elementTypeName;
1918

19+
/**
20+
* @deprecated
21+
*/
2022
public Array(List<Object> list, String elementTypeName, int itemType) throws SQLException {
21-
if (list == null) {
22-
throw ExceptionUtils.toSqlState(new IllegalArgumentException("List cannot be null"));
23-
}
24-
if (elementTypeName == null) {
25-
throw ExceptionUtils.toSqlState(new IllegalArgumentException("Array element type name cannot be null"));
26-
}
27-
this.array = list.toArray();
28-
this.type = itemType;
29-
this.elementTypeName = elementTypeName;
23+
this(elementTypeName, itemType, list.toArray());
3024
}
3125

3226
public Array(String elementTypeName, int itemType, Object[] elements) throws SQLException {

0 commit comments

Comments
 (0)