From c9ea0a19f60ac8fec5b12137a4954adcf499630b Mon Sep 17 00:00:00 2001 From: Zhichun Wu Date: Mon, 24 Jan 2022 08:00:13 +0800 Subject: [PATCH] More data type aliases, return scale for number and datetime, and better binary string support --- .../clickhouse/client/ClickHouseDataType.java | 9 +- .../clickhouse/client/ClickHouseValue.java | 49 ++++++ .../clickhouse/client/ClickHouseValues.java | 2 + .../data/ClickHouseRowBinaryProcessor.java | 16 +- .../client/data/ClickHouseStringValue.java | 152 ++++++++++++++---- .../data/ClickHouseStringValueTest.java | 27 +++- .../jdbc/ClickHouseDatabaseMetaData.java | 9 +- .../internal/InputBasedPreparedStatement.java | 2 +- .../internal/SqlBasedPreparedStatement.java | 10 +- .../jdbc/ClickHouseDatabaseMetaDataTest.java | 7 +- .../jdbc/ClickHouseResultSetTest.java | 15 ++ 11 files changed, 240 insertions(+), 58 deletions(-) diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseDataType.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseDataType.java index bfbf38e77..c748fbd74 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseDataType.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseDataType.java @@ -74,10 +74,11 @@ public enum ClickHouseDataType { IPv6(Inet6Address.class, false, true, false, 16, 39, 0, 0, 0, "INET6"), FixedString(String.class, true, true, false, 0, 0, 0, 0, 0, "BINARY"), String(String.class, false, true, false, 0, 0, 0, 0, 0, "BINARY LARGE OBJECT", "BINARY VARYING", "BLOB", "BYTEA", - "CHAR", "CHAR LARGE OBJECT", "CHAR VARYING", "CHARACTER", "CHARACTER LARGE OBJECT", "CHARACTER VARYING", - "CLOB", "LONGBLOB", "LONGTEXT", "MEDIUMBLOB", "MEDIUMTEXT", "NATIONAL CHAR", "NATIONAL CHAR VARYING", - "NATIONAL CHARACTER", "NATIONAL CHARACTER LARGE OBJECT", "NATIONAL CHARACTER VARYING", "NCHAR", - "NCHAR LARGE OBJECT", "NCHAR VARYING", "NVARCHAR", "TEXT", "TINYBLOB", "TINYTEXT", "VARCHAR", "VARCHAR2"), + "CHAR", "CHARACTER", "CHARACTER LARGE OBJECT", "CHARACTER VARYING", "CHAR LARGE OBJECT", "CHAR VARYING", + "CLOB", "LONGBLOB", "LONGTEXT", "MEDIUMBLOB", "MEDIUMTEXT", "NATIONAL CHAR", "NATIONAL CHARACTER", + "NATIONAL CHARACTER LARGE OBJECT", "NATIONAL CHARACTER VARYING", "NATIONAL CHAR VARYING", "NCHAR", + "NCHAR LARGE OBJECT", "NCHAR VARYING", "NVARCHAR", "TEXT", "TINYBLOB", "TINYTEXT", "VARBINARY", "VARCHAR", + "VARCHAR2"), AggregateFunction(String.class, true, true, false, 0, 0, 0, 0, 0), // implementation-defined intermediate state SimpleAggregateFunction(String.class, true, true, false, 0, 0, 0, 0, 0), Array(Object.class, true, true, false, 0, 0, 0, 0, 0), diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseValue.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseValue.java index 64b5b6cec..beed7df45 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseValue.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseValue.java @@ -538,6 +538,55 @@ default > T asObject(Class clazz) { } } + /** + * Gets binary value as byte array. + * + * @return non-null byte array + */ + default byte[] asBinary() { + return asBinary(0, null); + } + + /** + * Gets binary value as fixed length byte array. + * + * @param length byte length of value, 0 or negative number means no limit + * @return non-null byte array + */ + default byte[] asBinary(int length) { + return asBinary(length, null); + } + + /** + * Gets binary value as byte array. + * + * @param charset charset, null is same as default(UTF-8) + * @return non-null byte array + */ + default byte[] asBinary(Charset charset) { + return asBinary(0, charset); + } + + /** + * Gets binary value as byte array. + * + * @param length byte length of value, 0 or negative number means no limit + * @param charset charset, null is same as default(UTF-8) + * @return non-null byte array + */ + default byte[] asBinary(int length, Charset charset) { + if (isNullOrEmpty()) { + return ClickHouseValues.EMPTY_BYTE_ARRAY; + } + + byte[] bytes = asString().getBytes(charset == null ? StandardCharsets.UTF_8 : charset); + if (length > 0) { + ClickHouseChecker.notWithDifferentLength(bytes, length); + } + + return bytes; + } + /** * Gets value as unbounded string, using default charset(usually UTF-8). * diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseValues.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseValues.java index afb40a934..b461f0994 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseValues.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseValues.java @@ -76,7 +76,9 @@ public final class ClickHouseValues { public static final long[] EMPTY_LONG_ARRAY = new long[0]; public static final float[] EMPTY_FLOAT_ARRAY = new float[0]; public static final double[] EMPTY_DOUBLE_ARRAY = new double[0]; + public static final String EMPTY_ARRAY_EXPR = "[]"; + public static final String EMPTY_STRING_EXPR = "''"; public static final BigDecimal NANOS = new BigDecimal(BigInteger.TEN.pow(9)); diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseRowBinaryProcessor.java b/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseRowBinaryProcessor.java index 75017a081..813b6f84d 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseRowBinaryProcessor.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseRowBinaryProcessor.java @@ -331,13 +331,15 @@ private void buildMappingsForDataTypes() { // string and uuid buildMappings(deserializers, serializers, - (r, f, c, i) -> ClickHouseStringValue.of(r, BinaryStreamUtils.readFixedString(i, c.getPrecision())), - (v, f, c, o) -> BinaryStreamUtils.writeFixedString(o, v.asString(c.getPrecision()), - c.getPrecision()), - ClickHouseDataType.FixedString); - buildMappings(deserializers, serializers, - (r, f, c, i) -> ClickHouseStringValue.of(r, i.readUnicodeString()), - (v, f, c, o) -> BinaryStreamUtils.writeString(o, v.asString()), ClickHouseDataType.String); + (r, f, c, i) -> ClickHouseStringValue.of(r, i.readBytes(c.getPrecision())), + (v, f, c, o) -> o.write(v.asBinary(c.getPrecision())), ClickHouseDataType.FixedString); + buildMappings(deserializers, serializers, + (r, f, c, i) -> ClickHouseStringValue.of(r, i.readBytes(i.readVarInt())), + (v, f, c, o) -> { + byte[] bytes = v.asBinary(); + BinaryStreamUtils.writeVarInt(o, bytes.length); + o.write(bytes); + }, ClickHouseDataType.String); buildMappings(deserializers, serializers, (r, f, c, i) -> ClickHouseUuidValue.of(r, BinaryStreamUtils.readUuid(i)), (v, f, c, o) -> BinaryStreamUtils.writeUuid(o, v.asUuid()), ClickHouseDataType.UUID); diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseStringValue.java b/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseStringValue.java index 7e65e817d..01a260952 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseStringValue.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/data/ClickHouseStringValue.java @@ -35,8 +35,8 @@ public static ClickHouseStringValue ofNull() { * @return same object as {@code ref} or a new instance if it's null */ public static ClickHouseStringValue ofNull(ClickHouseValue ref) { - return ref instanceof ClickHouseStringValue ? ((ClickHouseStringValue) ref).set(null) - : new ClickHouseStringValue(null); + return ref instanceof ClickHouseStringValue ? ((ClickHouseStringValue) ref).set((String) null) + : new ClickHouseStringValue((String) null); } /** @@ -49,6 +49,16 @@ public static ClickHouseStringValue of(String value) { return of(null, value); } + /** + * Wrap the given value. + * + * @param bytes bytes + * @return object representing the value + */ + public static ClickHouseStringValue of(byte[] bytes) { + return of(null, bytes); + } + /** * Update value of the given object or create a new instance if {@code ref} is * null. @@ -62,75 +72,103 @@ public static ClickHouseStringValue of(ClickHouseValue ref, String value) { : new ClickHouseStringValue(value); } + /** + * Update value of the given object or create a new instance if {@code ref} is + * null. + * + * @param ref object to update, could be null + * @param bytes bytes + * @return same object as {@code ref} or a new instance if it's null + */ + public static ClickHouseStringValue of(ClickHouseValue ref, byte[] bytes) { + return ref instanceof ClickHouseStringValue ? ((ClickHouseStringValue) ref).set(bytes) + : new ClickHouseStringValue(bytes); + } + + private boolean binary; + private byte[] bytes; private String value; protected ClickHouseStringValue(String value) { update(value); } + protected ClickHouseStringValue(byte[] bytes) { + update(bytes); + } + protected ClickHouseStringValue set(String value) { + this.binary = false; + this.bytes = null; this.value = value; return this; } - /** - * Gets value. - * - * @return value - */ - public String getValue() { - return value; + protected ClickHouseStringValue set(byte[] bytes) { + this.binary = true; + this.bytes = bytes; + this.value = null; + return this; } @Override public ClickHouseStringValue copy(boolean deep) { - return new ClickHouseStringValue(value); + if (bytes == null || !binary) { + return new ClickHouseStringValue(value); + } + + byte[] b = bytes; + if (deep) { + b = new byte[bytes.length]; + System.arraycopy(bytes, 0, b, 0, bytes.length); + } + return new ClickHouseStringValue(b); } @Override public boolean isNullOrEmpty() { - return value == null; + return bytes == null && value == null; } @Override public boolean asBoolean() { // what about Y/N, Yes/No, enabled/disabled? - return !isNullOrEmpty() && Boolean.parseBoolean(value); + return !isNullOrEmpty() && Boolean.parseBoolean(asString()); } @Override public byte asByte() { - return isNullOrEmpty() ? (byte) 0 : Byte.parseByte(value); + return isNullOrEmpty() ? (byte) 0 : Byte.parseByte(asString()); } @Override public short asShort() { - return isNullOrEmpty() ? (short) 0 : Short.parseShort(value); + return isNullOrEmpty() ? (short) 0 : Short.parseShort(asString()); } @Override public int asInteger() { - return isNullOrEmpty() ? 0 : Integer.parseInt(value); + return isNullOrEmpty() ? 0 : Integer.parseInt(asString()); } @Override public long asLong() { - return isNullOrEmpty() ? 0L : Long.parseLong(value); + return isNullOrEmpty() ? 0L : Long.parseLong(asString()); } @Override public BigInteger asBigInteger() { - return isNullOrEmpty() ? null : new BigInteger(value); + return isNullOrEmpty() ? null : new BigInteger(asString()); } @Override public float asFloat() { - return isNullOrEmpty() ? 0F : Float.parseFloat(value); + return isNullOrEmpty() ? 0F : Float.parseFloat(asString()); } @Override public double asDouble() { - return isNullOrEmpty() ? 0D : Double.parseDouble(value); + return isNullOrEmpty() ? 0D : Double.parseDouble(asString()); } @Override @@ -140,49 +178,77 @@ public BigDecimal asBigDecimal(int scale) { @Override public LocalDate asDate() { - return isNullOrEmpty() ? null : LocalDate.parse(value, ClickHouseValues.DATE_FORMATTER); + return isNullOrEmpty() ? null : LocalDate.parse(asString(), ClickHouseValues.DATE_FORMATTER); } @Override public LocalTime asTime() { - return isNullOrEmpty() ? null : LocalTime.parse(value, ClickHouseValues.TIME_FORMATTER); + return isNullOrEmpty() ? null : LocalTime.parse(asString(), ClickHouseValues.TIME_FORMATTER); } @Override public LocalDateTime asDateTime(int scale) { - return isNullOrEmpty() ? null : LocalDateTime.parse(value, ClickHouseValues.DATETIME_FORMATTER); + return isNullOrEmpty() ? null : LocalDateTime.parse(asString(), ClickHouseValues.DATETIME_FORMATTER); } @Override public > T asEnum(Class enumType) { - return isNullOrEmpty() ? null : Enum.valueOf(enumType, value); + return isNullOrEmpty() ? null : Enum.valueOf(enumType, asString()); } @Override public Inet4Address asInet4Address() { - return ClickHouseValues.convertToIpv4(getValue()); + return ClickHouseValues.convertToIpv4(asString()); } @Override public Inet6Address asInet6Address() { - return ClickHouseValues.convertToIpv6(getValue()); + return ClickHouseValues.convertToIpv6(asString()); } @Override public Object asObject() { - return value; + return asString(); // bytes != null ? bytes : value; + } + + @Override + public byte[] asBinary() { + if (value != null && bytes == null) { + bytes = value.getBytes(StandardCharsets.UTF_8); + } + + return bytes != null ? bytes : ClickHouseValues.EMPTY_BYTE_ARRAY; + } + + @Override + public byte[] asBinary(int length, Charset charset) { + if (value != null && bytes == null) { + bytes = value.getBytes(charset == null ? StandardCharsets.UTF_8 : charset); + } + + if (bytes != null && length > 0) { + return ClickHouseChecker.notWithDifferentLength(bytes, length); + } else { + return bytes != null ? bytes : ClickHouseValues.EMPTY_BYTE_ARRAY; + } } @Override public String asString() { + if (bytes != null && value == null) { + value = new String(bytes, StandardCharsets.UTF_8); + } + return value; } @Override public String asString(int length, Charset charset) { if (value != null && length > 0) { - ClickHouseChecker.notWithDifferentLength(value.getBytes(charset == null ? StandardCharsets.UTF_8 : charset), - length); + if (bytes == null) { + bytes = value.getBytes(charset == null ? StandardCharsets.UTF_8 : charset); + } + ClickHouseChecker.notWithDifferentLength(bytes, length); } return value; @@ -190,17 +256,32 @@ public String asString(int length, Charset charset) { @Override public UUID asUuid() { - return isNullOrEmpty() ? null : UUID.fromString(value); + return isNullOrEmpty() ? null : UUID.fromString(asString()); } @Override public ClickHouseStringValue resetToNullOrEmpty() { - return set(null); + return set((String) null); } @Override public String toSqlExpression() { - return ClickHouseValues.convertToQuotedString(value); + if (isNullOrEmpty()) { + return ClickHouseValues.NULL_EXPR; + } + // else if (binary) { + // int len = bytes.length; + // if (len == 0) { + // return ClickHouseValues.EMPTY_STRING_EXPR; + // } + // StringBuilder builder = new StringBuilder(len * 3 + 5).append("char("); + // for (byte b : bytes) { + // builder.append(b).append(','); + // } + // builder.setLength(builder.length() - 1); + // return builder.append(')').toString(); + // } + return ClickHouseValues.convertToQuotedString(asString()); } @Override @@ -219,6 +300,11 @@ public ClickHouseStringValue update(byte value) { return set(String.valueOf(value)); } + @Override + public ClickHouseStringValue update(byte[] value) { + return set(value); + } + @Override public ClickHouseStringValue update(short value) { return set(String.valueOf(value)); @@ -313,12 +399,12 @@ public boolean equals(Object obj) { } ClickHouseStringValue v = (ClickHouseStringValue) obj; - return value == v.value || (value != null && value.equals(v.value)); + return Objects.equals(bytes, v.bytes) && Objects.equals(value, v.value); } @Override public int hashCode() { - return Objects.hash(value); + return Objects.hash(bytes, value); } @Override diff --git a/clickhouse-client/src/test/java/com/clickhouse/client/data/ClickHouseStringValueTest.java b/clickhouse-client/src/test/java/com/clickhouse/client/data/ClickHouseStringValueTest.java index 8c44cd6bd..2767636b6 100644 --- a/clickhouse-client/src/test/java/com/clickhouse/client/data/ClickHouseStringValueTest.java +++ b/clickhouse-client/src/test/java/com/clickhouse/client/data/ClickHouseStringValueTest.java @@ -24,15 +24,15 @@ public void testInitiation() { String value = null; ClickHouseStringValue v = ClickHouseStringValue.of(null, value); Assert.assertEquals(v.asString(), value); - Assert.assertEquals(v.getValue(), value); + Assert.assertEquals(v.asObject(), value); v = ClickHouseStringValue.of(null, value = ""); Assert.assertEquals(v.asString(), value); - Assert.assertEquals(v.getValue(), value); + Assert.assertEquals(v.asObject(), value); v = ClickHouseStringValue.of(null, value = "123"); Assert.assertEquals(v.asString(), value); - Assert.assertEquals(v.getValue(), value); + Assert.assertEquals(v.asObject(), value); // same instance but different value Assert.assertEquals(v, v.update("321")); @@ -55,6 +55,27 @@ public void testTypeConversion() { LocalDateTime.of(2021, 3, 4, 15, 6, 27, 123456789)); } + @Test(groups = { "unit" }) + public void testBinaryValue() { + Assert.assertEquals(ClickHouseStringValue.of((byte[]) null).asBinary(), new byte[0]); + Assert.assertEquals(ClickHouseStringValue.of((String) null).asBinary(), new byte[0]); + Assert.assertEquals(ClickHouseStringValue.of(new byte[0]).asBinary(), new byte[0]); + Assert.assertEquals(ClickHouseStringValue.of("").asBinary(), new byte[0]); + Assert.assertEquals(ClickHouseStringValue.of((byte[]) null).asBinary(0), new byte[0]); + Assert.assertEquals(ClickHouseStringValue.of((String) null).asBinary(0), new byte[0]); + Assert.assertEquals(ClickHouseStringValue.of(new byte[0]).asBinary(0), new byte[0]); + Assert.assertEquals(ClickHouseStringValue.of("").asBinary(0), new byte[0]); + + Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseStringValue.of("").asBinary(1)); + + Assert.assertEquals(ClickHouseStringValue.of("a").asBinary(1), new byte[] { 97 }); + Assert.assertEquals(ClickHouseStringValue.of("a").asBinary(0), new byte[] { 97 }); + Assert.assertEquals(ClickHouseStringValue.of("a").asBinary(), new byte[] { 97 }); + + Assert.assertEquals(ClickHouseStringValue.of(new byte[0]).toSqlExpression(), "''"); + Assert.assertEquals(ClickHouseStringValue.of(new byte[] { 97 }).toSqlExpression(), "'a'"); + } + @Test(groups = { "unit" }) public void testValue() throws Exception { // null value diff --git a/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/ClickHouseDatabaseMetaData.java b/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/ClickHouseDatabaseMetaData.java index 61d3535cf..781ec83f1 100644 --- a/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/ClickHouseDatabaseMetaData.java +++ b/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/ClickHouseDatabaseMetaData.java @@ -6,8 +6,12 @@ import java.sql.RowIdLifetime; import java.sql.SQLException; import java.sql.Types; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.temporal.Temporal; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -839,8 +843,9 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa r.getValue("CHAR_OCTET_LENGTH").update(column.getPrecision()); } - if (column.getScale() > 0 || column.getDataType() == ClickHouseDataType.Float32 - || column.getDataType() == ClickHouseDataType.Float64) { + Class clazz = column.getDataType().getObjectClass(); + if (column.getScale() > 0 || Number.class.isAssignableFrom(clazz) || Date.class.isAssignableFrom(clazz) + || Temporal.class.isAssignableFrom(clazz)) { r.getValue("DECIMAL_DIGITS").update(column.getScale()); } else { r.getValue("DECIMAL_DIGITS").resetToNullOrEmpty(); diff --git a/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/InputBasedPreparedStatement.java b/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/InputBasedPreparedStatement.java index 423dd51df..ceb8d77e8 100644 --- a/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/InputBasedPreparedStatement.java +++ b/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/InputBasedPreparedStatement.java @@ -188,7 +188,7 @@ public void setBytes(int parameterIndex, byte[] x) throws SQLException { ensureOpen(); int idx = toArrayIndex(parameterIndex); - values[idx].update(new String(x, StandardCharsets.UTF_8)); + values[idx].update(x); flags[idx] = true; } diff --git a/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/SqlBasedPreparedStatement.java b/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/SqlBasedPreparedStatement.java index 84066e8e5..0492b5f2a 100644 --- a/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/SqlBasedPreparedStatement.java +++ b/clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/SqlBasedPreparedStatement.java @@ -1,7 +1,6 @@ package com.clickhouse.jdbc.internal; import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; import java.sql.Array; import java.sql.Date; import java.sql.ParameterMetaData; @@ -30,6 +29,7 @@ import com.clickhouse.client.ClickHouseValues; import com.clickhouse.client.data.ClickHouseDateTimeValue; import com.clickhouse.client.data.ClickHouseDateValue; +import com.clickhouse.client.data.ClickHouseStringValue; import com.clickhouse.client.logging.Logger; import com.clickhouse.client.logging.LoggerFactory; import com.clickhouse.jdbc.ClickHousePreparedStatement; @@ -337,12 +337,10 @@ public void setBytes(int parameterIndex, byte[] x) throws SQLException { int idx = toArrayIndex(parameterIndex); ClickHouseValue value = templates[idx]; - if (value != null) { - value.update(x); - values[idx] = value.toSqlExpression(); - } else { - values[idx] = new String(x, StandardCharsets.UTF_8); + if (value == null) { + templates[idx] = value = ClickHouseStringValue.ofNull(); } + values[idx] = value.update(x).toSqlExpression(); } @Override diff --git a/clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHouseDatabaseMetaDataTest.java b/clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHouseDatabaseMetaDataTest.java index 90100880b..57d1e0805 100644 --- a/clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHouseDatabaseMetaDataTest.java +++ b/clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHouseDatabaseMetaDataTest.java @@ -18,12 +18,15 @@ private Object[][] getSelectedColumns() { return new Object[][] { // COLUMN_SIZE, DECIMAL_DIGITS, CHAR_OCTET_LENGTH // new Object[] { "Bool", 1, null, null }, // Bool was an alias before 21.12 - new Object[] { "Int8", 3, null, null }, - new Object[] { "UInt8", 3, null, null }, + new Object[] { "Int8", 3, 0, null }, + new Object[] { "UInt8", 3, 0, null }, new Object[] { "FixedString(3)", 3, null, 3 }, new Object[] { "String", 0, null, null }, + new Object[] { "Date", 10, 0, null }, + new Object[] { "DateTime64(5)", 29, 5, null }, new Object[] { "Decimal64(10)", 18, 10, null }, new Object[] { "Decimal(10,2)", 10, 2, null }, + new Object[] { "Decimal(12,0)", 12, 0, null }, new Object[] { "Float32", 12, 0, null }, new Object[] { "Float64", 22, 0, null } }; } diff --git a/clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHouseResultSetTest.java b/clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHouseResultSetTest.java index 412490810..afcb9f5a7 100644 --- a/clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHouseResultSetTest.java +++ b/clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHouseResultSetTest.java @@ -126,6 +126,21 @@ public void testArray() throws SQLException { } } + @Test(groups = "integration") + public void testIpAddress() throws SQLException { + try (ClickHouseConnection conn = newConnection(new Properties()); + Statement stmt = conn.createStatement()) { + ResultSet rs = stmt + .executeQuery("select toIPv4('116.253.40.133'), toIPv6('2001:44c8:129:2632:33:0:252:2')"); + Assert.assertTrue(rs.next()); + Assert.assertEquals(rs.getString(1), "116.253.40.133"); + Assert.assertEquals(rs.getObject(1).toString(), "/116.253.40.133"); + Assert.assertEquals(rs.getString(2), "2001:44c8:129:2632:33:0:252:2"); + Assert.assertEquals(rs.getObject(2).toString(), "/2001:44c8:129:2632:33:0:252:2"); + Assert.assertFalse(rs.next()); + } + } + @Test(groups = "integration") public void testTuple() throws SQLException { try (ClickHouseConnection conn = newConnection(new Properties());