Skip to content

Commit f13d0ce

Browse files
authored
Merge pull request #2281 from ClickHouse/fix_jdbc_metadata_types
[jdbc-v2] Fixed getting database metadata
2 parents d5787d1 + 716a56f commit f13d0ce

File tree

12 files changed

+338
-46
lines changed

12 files changed

+338
-46
lines changed

clickhouse-data/src/main/java/com/clickhouse/data/ClickHouseColumn.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ private static ClickHouseColumn update(ClickHouseColumn column) {
129129
case Bool:
130130
column.template = ClickHouseBoolValue.ofNull();
131131
break;
132+
case Enum:
132133
case Enum8:
133134
case Enum16:
134135
column.template = ClickHouseEnumValue
@@ -746,7 +747,7 @@ public boolean isArray() {
746747
}
747748

748749
public boolean isEnum() {
749-
return dataType == ClickHouseDataType.Enum8 || dataType == ClickHouseDataType.Enum16;
750+
return dataType == ClickHouseDataType.Enum8 || dataType == ClickHouseDataType.Enum16 || dataType == ClickHouseDataType.Enum;
750751
}
751752

752753
public boolean isFixedLength() {

clickhouse-data/src/main/java/com/clickhouse/data/ClickHouseDataType.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public enum ClickHouseDataType {
5555
DateTime(LocalDateTime.class, true, false, false, 0, 29, 0, 0, 9, false, 0x11, "TIMESTAMP"),
5656
DateTime32(LocalDateTime.class, true, false, false, 4, 19, 0, 0, 0, false, 0x12),
5757
DateTime64(LocalDateTime.class, true, false, false, 8, 29, 3, 0, 9, false, 0x14), // we always write timezone as argument
58+
Enum(String.class, true, true, false, 0, 0, 0, 0, 0, false),
5859
Enum8(String.class, true, true, false, 1, 0, 0, 0, 0, false, 0x17, "ENUM"),
5960
Enum16(String.class, true, true, false, 2, 0, 0, 0, 0, false, 0x18),
6061
FixedString(String.class, true, true, false, 0, 0, 0, 0, 0, false, 0x16, "BINARY"),
@@ -90,6 +91,8 @@ public enum ClickHouseDataType {
9091
Decimal64(BigDecimal.class, true, false, true, 8, 18, 18, 0, 18, false, 0x1A),
9192
Decimal128(BigDecimal.class, true, false, true, 16, 38, 38, 0, 38, false, 0x1B),
9293
Decimal256(BigDecimal.class, true, false, true, 32, 76, 20, 0, 76, false, 0x1C),
94+
95+
BFloat16(Float.class, false, true, true, 2, 3, 0, 0, 16, false, 0x31),
9396
Float32(Float.class, false, true, true, 4, 12, 0, 0, 38, false, 0x0D, "FLOAT", "REAL", "SINGLE"),
9497
Float64(Double.class, false, true, true, 8, 22, 0, 0, 308, false, 0x0E, "DOUBLE", "DOUBLE PRECISION"),
9598
IPv4(Inet4Address.class, false, true, false, 4, 10, 0, 0, 0, false, 0x28, "INET4"),
@@ -99,10 +102,13 @@ public enum ClickHouseDataType {
99102
Polygon(Object.class, false, true, true, 0, 0, 0, 0, 0, true, 0x2C), // same as Array(Ring)
100103
MultiPolygon(Object.class, false, true, true, 0, 0, 0, 0, 0, true, 0x2C), // same as Array(Polygon)
101104
Ring(Object.class, false, true, true, 0, 0, 0, 0, 0, true, 0x2C), // same as Array(Point)
105+
LineString( Object.class, false, true, true, 0, 0, 0, 0, 0, true, 0x2C), // same as Array(Point)
106+
MultiLineString(Object.class, false, true, true, 0, 0, 0, 0, 0, true, 0x2C), // same as Array(Ring)
107+
102108
JSON(Object.class, false, false, false, 0, 0, 0, 0, 0, true, 0x30),
103109
@Deprecated
104110
Object(Object.class, true, true, false, 0, 0, 0, 0, 0, true),
105-
String(String.class, false, false, false, 0, 0, 0, 0, 0, false, 0x15, "BINARY LARGE OBJECT", "BINARY VARYING", "BLOB",
111+
String(String.class, false, true, false, 0, 0, 0, 0, 0, false, 0x15, "BINARY LARGE OBJECT", "BINARY VARYING", "BLOB",
106112
"BYTEA", "CHAR", "CHAR LARGE OBJECT", "CHAR VARYING", "CHARACTER", "CHARACTER LARGE OBJECT",
107113
"CHARACTER VARYING", "CLOB", "GEOMETRY", "LONGBLOB", "LONGTEXT", "MEDIUMBLOB", "MEDIUMTEXT",
108114
"NATIONAL CHAR", "NATIONAL CHAR VARYING", "NATIONAL CHARACTER", "NATIONAL CHARACTER LARGE OBJECT",
@@ -113,6 +119,8 @@ public enum ClickHouseDataType {
113119
Nested(Object.class, true, true, false, 0, 0, 0, 0, 0, true, 0x2F),
114120
Tuple(List.class, true, true, false, 0, 0, 0, 0, 0, true, 0x1F),
115121
Nothing(Object.class, false, true, false, 0, 0, 0, 0, 0, true, 0x00),
122+
LowCardinality(Object.class, true, true, false, 0, 0, 0, 0, 0, true, 0x26),
123+
Nullable( Object.class, true, true, false, 0, 0, 0, 0, 0, true, 0x23),
116124
SimpleAggregateFunction(String.class, true, true, false, 0, 0, 0, 0, 0, false, 0x2E),
117125
// implementation-defined intermediate state
118126
AggregateFunction(String.class, true, true, false, 0, 0, 0, 0, 0, true),
@@ -364,7 +372,7 @@ public byte getTag() {
364372
* @return true if the type name is an alias; false otherwise
365373
*/
366374
public static boolean isAlias(String typeName) {
367-
return typeName != null && !typeName.isEmpty() && allAliases.contains(typeName.trim().toUpperCase());
375+
return typeName != null && !typeName.isEmpty() && allAliases.contains(typeName.trim());
368376
}
369377

370378
/**

clickhouse-data/src/test/java/com/clickhouse/data/ClickHouseColumnTest.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,9 @@ public void testEnum(String typeName) {
253253
Assert.assertEquals(column.getEnumConstants().name(10), "Query'Finish");
254254
Assert.assertEquals(column.getEnumConstants().value("Query'Start"), 1);
255255
Assert.assertEquals(column.getEnumConstants().value("Query'Finish"), 10);
256-
Assert.assertTrue(column.isFixedLength(), "Should have fixed length in byte");
256+
if (column.getDataType() != ClickHouseDataType.Enum) { // virtual type
257+
Assert.assertTrue(column.isFixedLength(), "Should have fixed length in byte");
258+
}
257259
Assert.assertEquals(column.getEstimatedLength(), column.getDataType().getByteLength());
258260
}
259261

@@ -417,7 +419,8 @@ public boolean isWidenUnsignedTypes() {
417419
for (ClickHouseDataType type : ClickHouseDataType.values()) {
418420
// skip advanced types
419421
if (type.isNested() || type == ClickHouseDataType.AggregateFunction
420-
|| type == ClickHouseDataType.SimpleAggregateFunction) {
422+
|| type == ClickHouseDataType.SimpleAggregateFunction || type == ClickHouseDataType.Enum
423+
|| type == ClickHouseDataType.Nullable || type == ClickHouseDataType.BFloat16) {
421424
continue;
422425
}
423426

clickhouse-jdbc/pom.xml

+1-6
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,6 @@
4545
<groupId>org.apache.commons</groupId>
4646
<artifactId>commons-compress</artifactId>
4747
</dependency>
48-
49-
<dependency>
50-
<groupId>org.lz4</groupId>
51-
<artifactId>lz4-java</artifactId>
52-
</dependency>
5348
<dependency>
5449
<groupId>com.google.code.gson</groupId>
5550
<artifactId>gson</artifactId>
@@ -90,7 +85,7 @@
9085
<dependency>
9186
<groupId>org.lz4</groupId>
9287
<artifactId>lz4-java</artifactId>
93-
<scope>provided</scope>
88+
<version>${lz4.version}</version>
9489
</dependency>
9590
<dependency>
9691
<groupId>com.github.luben</groupId>

client-v2/src/test/java/com/clickhouse/client/datatypes/DataTypeTests.java

+19-4
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,18 @@ public void testVariantWithSimpleDataTypes() throws Exception {
156156
b.append(table).append(" ( rowId Int64, field Variant(String, ").append(dataType.name());
157157

158158
switch (dataType) {
159+
case BFloat16:
160+
// TODO: add support
161+
continue dataTypesLoop;
162+
// skipped
159163
case String:
160164
case FixedString:
161165
case Nothing:
162166
case Variant:
163167
case JSON:
164168
case Object:
165169
case Dynamic:
166-
// skipped
167-
continue dataTypesLoop;
168-
170+
// no tests or tested in other tests
169171
case Decimal:
170172
case Decimal32:
171173
case Decimal64:
@@ -179,6 +181,11 @@ public void testVariantWithSimpleDataTypes() throws Exception {
179181
case AggregateFunction:
180182
case Enum8:
181183
case Enum16:
184+
case Enum:
185+
case Nullable: // virtual type
186+
case LowCardinality: // virtual type
187+
case LineString: // same as Ring
188+
case MultiLineString: // same as MultiPolygon
182189
// tested separately
183190
continue dataTypesLoop;
184191

@@ -414,6 +421,9 @@ public void testDynamicWithPrimitives() throws Exception {
414421
int rowId = 0;
415422
for (ClickHouseDataType dataType : ClickHouseDataType.values()) {
416423
switch (dataType) {
424+
case BFloat16:
425+
// TODO: add support
426+
continue;
417427
case Array:
418428
case Map:
419429
case AggregateFunction:
@@ -428,6 +438,11 @@ public void testDynamicWithPrimitives() throws Exception {
428438
case Tuple:
429439
case Variant:
430440
case Decimal: // virtual type
441+
case Nullable: // virtual type
442+
case LowCardinality: // virtual type
443+
case Enum: // virtual type
444+
case LineString: // same as Ring
445+
case MultiLineString: // same as MultiPolygon
431446
// no tests or tested in other tests
432447
continue;
433448
default:
@@ -447,7 +462,7 @@ public void testDynamicWithPrimitives() throws Exception {
447462
}
448463
}
449464

450-
Assert.assertNotNull(value);
465+
Assert.assertNotNull(value, "Value for " + dataType.name() + " should not be null.");
451466

452467
List<DTOForDynamicPrimitivesTests> data = new ArrayList<>();
453468
data.add(new DTOForDynamicPrimitivesTests(rowId++, value));

jdbc-v2/pom.xml

+2-6
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,7 @@
5050
<artifactId>slf4j-api</artifactId>
5151
<version>${slf4j.version}</version>
5252
</dependency>
53-
<dependency>
54-
<groupId>org.lz4</groupId>
55-
<artifactId>lz4-java</artifactId>
56-
<optional>true</optional>
57-
</dependency>
53+
5854
<dependency>
5955
<groupId>com.google.code.gson</groupId>
6056
<artifactId>gson</artifactId>
@@ -63,7 +59,7 @@
6359
<dependency>
6460
<groupId>org.lz4</groupId>
6561
<artifactId>lz4-java</artifactId>
66-
<scope>provided</scope>
62+
<version>${lz4.version}</version>
6763
</dependency>
6864
<dependency>
6965
<groupId>com.github.luben</groupId>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ protected ResultSetImpl(ResultSetImpl resultSet) {
4848
this.parentStatement = resultSet.parentStatement;
4949
this.response = resultSet.response;
5050
this.reader = resultSet.reader;
51-
this.metaData = resultSet.metaData;
51+
this.metaData = new com.clickhouse.jdbc.metadata.ResultSetMetaData(this);
5252
this.closed = false;
5353
this.wasNull = false;
5454
this.defaultCalendar = parentStatement.connection.defaultCalendar;

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

+24-2
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,23 @@
1717
import java.time.ZonedDateTime;
1818
import java.time.temporal.TemporalAccessor;
1919
import java.util.ArrayList;
20+
import java.util.Collections;
2021
import java.util.HashMap;
2122
import java.util.List;
2223
import java.util.Map;
2324
import java.util.TreeMap;
24-
import java.util.regex.Matcher;
25-
import java.util.regex.Pattern;
2625

2726
public class JdbcUtils {
2827
//Define a map to store the mapping between ClickHouse data types and SQL data types
2928
private static final Map<ClickHouseDataType, SQLType> CLICKHOUSE_TO_SQL_TYPE_MAP = generateTypeMap();
29+
30+
public static final Map<String, SQLType> CLICKHOUSE_TYPE_NAME_TO_SQL_TYPE_MAP = Collections.unmodifiableMap(generateTypeMap().entrySet()
31+
.stream().collect(
32+
HashMap::new,
33+
(map, entry) -> map.put(entry.getKey().name(), entry.getValue()),
34+
HashMap::putAll
35+
));
36+
3037
private static Map<ClickHouseDataType, SQLType> generateTypeMap() {
3138
Map<ClickHouseDataType, SQLType> map = new TreeMap<>(); // TreeMap is used to sort the keys in natural order so FixedString will be before String :-) (type match should be more accurate)
3239
map.put(ClickHouseDataType.Int8, JDBCType.TINYINT);
@@ -46,6 +53,7 @@ private static Map<ClickHouseDataType, SQLType> generateTypeMap() {
4653
map.put(ClickHouseDataType.Decimal128, JDBCType.DECIMAL);
4754
map.put(ClickHouseDataType.String, JDBCType.VARCHAR);
4855
map.put(ClickHouseDataType.FixedString, JDBCType.VARCHAR);
56+
map.put(ClickHouseDataType.Enum, JDBCType.VARCHAR);
4957
map.put(ClickHouseDataType.Enum8, JDBCType.VARCHAR);
5058
map.put(ClickHouseDataType.Enum16, JDBCType.VARCHAR);
5159
map.put(ClickHouseDataType.Date, JDBCType.DATE);
@@ -56,6 +64,12 @@ private static Map<ClickHouseDataType, SQLType> generateTypeMap() {
5664
map.put(ClickHouseDataType.Array, JDBCType.ARRAY);
5765
map.put(ClickHouseDataType.Nested, JDBCType.ARRAY);
5866
map.put(ClickHouseDataType.Map, JDBCType.JAVA_OBJECT);
67+
map.put(ClickHouseDataType.Point, JDBCType.OTHER);
68+
map.put(ClickHouseDataType.Ring, JDBCType.OTHER);
69+
map.put(ClickHouseDataType.Polygon, JDBCType.OTHER);
70+
map.put(ClickHouseDataType.LineString, JDBCType.OTHER);
71+
map.put(ClickHouseDataType.MultiPolygon, JDBCType.OTHER);
72+
map.put(ClickHouseDataType.MultiLineString, JDBCType.OTHER);
5973
return map;
6074
}
6175

@@ -249,4 +263,12 @@ public static Object convert(Object value, Class<?> type) throws SQLException {
249263
throw new SQLException("Unsupported conversion from " + value.getClass().getName() + " to " + type.getName(), ExceptionUtils.SQL_STATE_DATA_EXCEPTION);
250264
}
251265

266+
public static String escapeQuotes(String str) {
267+
if (str == null || str.isEmpty()) {
268+
return str;
269+
}
270+
return str
271+
.replace("'", "\\'")
272+
.replace("\"", "\\\"");
273+
}
252274
}

0 commit comments

Comments
 (0)