Skip to content

Commit a90da54

Browse files
authored
Merge pull request #592 from zhicwu/client-name
Add client_name connection setting
2 parents f4e786f + 553c907 commit a90da54

File tree

7 files changed

+119
-15
lines changed

7 files changed

+119
-15
lines changed

clickhouse-jdbc/src/main/java/ru/yandex/clickhouse/domain/ClickHouseDataType.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import java.sql.Timestamp;
99
import java.util.Collections;
1010
import java.util.HashMap;
11-
import java.util.List;
1211
import java.util.Map;
1312
import java.util.UUID;
1413

@@ -103,14 +102,25 @@ public enum ClickHouseDataType {
103102

104103
static {
105104
Map<String, ClickHouseDataType> map = new HashMap<>();
105+
String errorMsg = "[%s] is used by type [%s]";
106+
ClickHouseDataType used = null;
106107
for (ClickHouseDataType t : ClickHouseDataType.values()) {
107-
assert map.put(t.name(), t) == null;
108+
used = map.put(t.name(), t);
109+
if (used != null) {
110+
throw new IllegalStateException(java.lang.String.format(errorMsg, t.name(), used.name()));
111+
}
108112
String nameInUpperCase = t.name().toUpperCase();
109113
if (!nameInUpperCase.equals(t.name())) {
110-
assert map.put(nameInUpperCase, t) == null;
114+
used = map.put(nameInUpperCase, t);
115+
if (used != null) {
116+
throw new IllegalStateException(java.lang.String.format(errorMsg, nameInUpperCase, used.name()));
117+
}
111118
}
112119
for (String alias: t.aliases) {
113-
assert map.put(alias.toUpperCase(), t) == null;
120+
used = map.put(alias.toUpperCase(), t);
121+
if (used != null) {
122+
throw new IllegalStateException(java.lang.String.format(errorMsg, alias, used.name()));
123+
}
114124
}
115125
}
116126
name2type = Collections.unmodifiableMap(map);

clickhouse-jdbc/src/main/java/ru/yandex/clickhouse/response/ClickHouseResultSet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
727727
ClickHouseColumnInfo columnInfo = getColumnInfo(columnIndex);
728728
TimeZone tz = getEffectiveTimeZone(columnInfo);
729729
return columnInfo.isArray()
730-
? (T) getArray(columnIndex)
730+
? (Array.class.isAssignableFrom(type) ? (T) getArray(columnIndex) : (T) getArray(columnIndex).getArray())
731731
: ClickHouseValueParser.getParser(type).parse(getValue(columnIndex), columnInfo, tz);
732732
}
733733

clickhouse-jdbc/src/main/java/ru/yandex/clickhouse/response/parser/ClickHouseDateValueParser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ protected final LocalDate parseAsLocalDate(String value) {
189189
}
190190

191191
protected final LocalDateTime parseAsLocalDateTime(String value) {
192-
int index = value == null ? -1 : value.indexOf('.');
192+
int index = Objects.requireNonNull(value).indexOf('.');
193193
if (index > 0) {
194194
int endIndex = -1;
195195
for (int i = index + 1, len = value.length(); i < len; i++) {

clickhouse-jdbc/src/main/java/ru/yandex/clickhouse/settings/ClickHouseConnectionSettings.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,15 @@ public enum ClickHouseConnectionSettings implements DriverPropertyCreator {
5050
"Whether to use timezone from server on Date parsing in getDate(). " +
5151
"If false, Date returned is a wrapper of a timestamp at start of the day in client timezone. " +
5252
"If true - at start of the day in server or use_timezone timezone."),
53+
CLIENT_NAME("client_name", "", "client_name or http_user_agent show up in system.query_log table, depending on the protocol you're using."),
5354
@Deprecated
5455
USE_NEW_PARSER("use_new_parser", true, "Whether to use JavaCC based SQL parser or not.")
5556
;
5657

5758
private final String key;
5859
private final Object defaultValue;
5960
private final String description;
60-
private final Class clazz;
61+
private final Class<?> clazz;
6162

6263
ClickHouseConnectionSettings(String key, Object defaultValue, String description) {
6364
this.key = key;
@@ -74,7 +75,7 @@ public Object getDefaultValue() {
7475
return defaultValue;
7576
}
7677

77-
public Class getClazz() {
78+
public Class<?> getClazz() {
7879
return clazz;
7980
}
8081

clickhouse-jdbc/src/main/java/ru/yandex/clickhouse/settings/ClickHouseProperties.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public class ClickHouseProperties {
9797
private Boolean anyJoinDistinctRightTableKeys;
9898
private Boolean sendProgressInHttpHeaders;
9999
private Boolean waitEndOfQuery;
100+
private String clientName;
100101
@Deprecated
101102
private boolean useNewParser;
102103

@@ -129,6 +130,7 @@ public ClickHouseProperties(Properties info) {
129130
this.useTimeZone = (String)getSetting(info, ClickHouseConnectionSettings.USE_TIME_ZONE);
130131
this.useServerTimeZoneForDates = (Boolean)getSetting(info, ClickHouseConnectionSettings.USE_SERVER_TIME_ZONE_FOR_DATES);
131132
this.useObjectsInArrays = (Boolean)getSetting(info, ClickHouseConnectionSettings.USE_OBJECTS_IN_ARRAYS);
133+
this.clientName = (String)getSetting(info, ClickHouseConnectionSettings.CLIENT_NAME);
132134
this.useNewParser = (Boolean)getSetting(info, ClickHouseConnectionSettings.USE_NEW_PARSER);
133135

134136
this.maxParallelReplicas = getSetting(info, ClickHouseQueryParam.MAX_PARALLEL_REPLICAS);
@@ -197,6 +199,7 @@ public Properties asProperties() {
197199
ret.put(ClickHouseConnectionSettings.USE_TIME_ZONE.getKey(), String.valueOf(useTimeZone));
198200
ret.put(ClickHouseConnectionSettings.USE_SERVER_TIME_ZONE_FOR_DATES.getKey(), String.valueOf(useServerTimeZoneForDates));
199201
ret.put(ClickHouseConnectionSettings.USE_OBJECTS_IN_ARRAYS.getKey(), String.valueOf(useObjectsInArrays));
202+
ret.put(ClickHouseConnectionSettings.CLIENT_NAME.getKey(), String.valueOf(clientName));
200203
ret.put(ClickHouseConnectionSettings.USE_NEW_PARSER.getKey(), String.valueOf(useNewParser));
201204

202205
ret.put(ClickHouseQueryParam.MAX_PARALLEL_REPLICAS.getKey(), maxParallelReplicas);
@@ -268,6 +271,7 @@ public ClickHouseProperties(ClickHouseProperties properties) {
268271
setUseTimeZone(properties.useTimeZone);
269272
setUseServerTimeZoneForDates(properties.useServerTimeZoneForDates);
270273
setUseObjectsInArrays(properties.useObjectsInArrays);
274+
setClientName(properties.clientName);
271275
setUseNewParser(properties.useNewParser);
272276
setMaxParallelReplicas(properties.maxParallelReplicas);
273277
setMaxPartitionsPerInsertBlock(properties.maxPartitionsPerInsertBlock);
@@ -684,6 +688,14 @@ public void setUseObjectsInArrays(boolean useObjectsInArrays) {
684688
this.useObjectsInArrays = useObjectsInArrays;
685689
}
686690

691+
public String getClientName() {
692+
return this.clientName;
693+
}
694+
695+
public void setClientName(String clientName) {
696+
this.clientName = clientName;
697+
}
698+
687699
@Deprecated
688700
public boolean isUseNewParser() {
689701
return useNewParser;

clickhouse-jdbc/src/main/java/ru/yandex/clickhouse/util/ClickHouseHttpClientBuilder.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public ClickHouseHttpClientBuilder(ClickHouseProperties properties) {
6767
}
6868

6969
public CloseableHttpClient buildClient() throws Exception {
70-
return HttpClientBuilder.create()
70+
HttpClientBuilder builder = HttpClientBuilder.create()
7171
.setConnectionManager(getConnectionManager())
7272
.setRetryHandler(getRequestRetryHandler())
7373
.setConnectionReuseStrategy(getConnectionReuseStrategy())
@@ -76,8 +76,14 @@ public CloseableHttpClient buildClient() throws Exception {
7676
.setDefaultHeaders(getDefaultHeaders())
7777
.setDefaultCredentialsProvider(getDefaultCredentialsProvider())
7878
.disableContentCompression() // gzip is not needed. Use lz4 when compress=1
79-
.disableRedirectHandling()
80-
.build();
79+
.disableRedirectHandling();
80+
81+
String clientName = properties != null ? properties.getClientName() : null;
82+
if (!Utils.isNullOrEmptyString(clientName)) {
83+
builder.setUserAgent(clientName);
84+
}
85+
86+
return builder.build();
8187
}
8288

8389
private HttpRequestRetryHandler getRequestRetryHandler() {

clickhouse-jdbc/src/test/java/ru/yandex/clickhouse/integration/ClickHouseDataTypeTest.java

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package ru.yandex.clickhouse.integration;
22

3+
import static org.testng.Assert.assertNull;
34
import static org.testng.Assert.assertEquals;
45
import static org.testng.Assert.assertTrue;
56

@@ -24,12 +25,14 @@
2425
import java.util.Calendar;
2526
import java.util.Objects;
2627
import java.util.TimeZone;
28+
import java.util.UUID;
2729

2830
import org.testng.annotations.AfterTest;
2931
import org.testng.annotations.BeforeTest;
3032
import org.testng.annotations.DataProvider;
3133
import org.testng.annotations.Test;
3234

35+
import ru.yandex.clickhouse.ClickHouseArray;
3336
import ru.yandex.clickhouse.ClickHouseConnection;
3437
import ru.yandex.clickhouse.ClickHouseContainerForTest;
3538
import ru.yandex.clickhouse.ClickHouseDataSource;
@@ -47,7 +50,7 @@ private LocalDate instantToLocalDate(Instant instant, ZoneId zone) {
4750
ZoneRules rules = zone.getRules();
4851
ZoneOffset offset = rules.getOffset(instant);
4952
long localSecond = instant.getEpochSecond() + offset.getTotalSeconds();
50-
long localEpochDay = Math.floorDiv(localSecond, 24 * 3600);
53+
long localEpochDay = Math.floorDiv(localSecond, 24 * 3600L);
5154
return LocalDate.ofEpochDay(localEpochDay);
5255
}
5356

@@ -56,7 +59,7 @@ private LocalTime instantToLocalTime(Instant instant, ZoneId zone) {
5659
Objects.requireNonNull(zone, "zone");
5760
ZoneOffset offset = zone.getRules().getOffset(instant);
5861
long localSecond = instant.getEpochSecond() + offset.getTotalSeconds();
59-
int secondsADay = 24 * 3600;
62+
long secondsADay = 24 * 3600L;
6063
int secsOfDay = (int) (localSecond - Math.floorDiv(localSecond, secondsADay) * secondsADay);
6164
return LocalTime.ofNanoOfDay(secsOfDay * 1000_000_000L + instant.getNano());
6265
}
@@ -322,8 +325,9 @@ public void testDateTimeWithTimeZone(String d1TimeZone, String d2TimeZone, Strin
322325
assertEquals(r.getDate("d2"), expectedDate);
323326
assertEquals(r.getObject("d2", Date.class), expectedDate);
324327
}
325-
//expectedDate = new Date(testInstant.atZone(connServerTz.getServerTimeZone().toZoneId())
326-
// .truncatedTo(ChronoUnit.DAYS).toInstant().toEpochMilli());
328+
// expectedDate = new
329+
// Date(testInstant.atZone(connServerTz.getServerTimeZone().toZoneId())
330+
// .truncatedTo(ChronoUnit.DAYS).toInstant().toEpochMilli());
327331
try (Statement s = connServerTz.createStatement(); ResultSet r = s.executeQuery(query);) {
328332
assertTrue(r.next());
329333
assertEquals(r.getDate("d0"), expectedDate);
@@ -877,6 +881,77 @@ public void testDateWithTimeZone(String testTimeZone) throws Exception {
877881
}
878882
}
879883

884+
@Test
885+
public void testUUID() throws Exception {
886+
try (Statement s = conn.createStatement()) {
887+
s.execute("DROP TABLE IF EXISTS test_uuid");
888+
s.execute(
889+
"CREATE TABLE IF NOT EXISTS test_uuid(u0 UUID, u1 Nullable(UUID), u2 Array(UUID), u3 Array(Nullable(UUID))) ENGINE = Memory");
890+
} catch (ClickHouseException e) {
891+
return;
892+
}
893+
894+
try (Statement s = conn.createStatement()) {
895+
UUID uuid = UUID.randomUUID();
896+
String str = uuid.toString();
897+
s.execute("insert into test_uuid values ('" + str + "', null, ['" + str + "'], [null])");
898+
899+
try (ResultSet rs = s.executeQuery("select * from test_uuid")) {
900+
assertTrue(rs.next());
901+
902+
assertEquals(rs.getString(1), str);
903+
assertEquals(rs.getObject(1), uuid);
904+
assertEquals(rs.getObject(1, UUID.class), uuid);
905+
906+
assertNull(rs.getString(2));
907+
assertNull(rs.getObject(2));
908+
assertNull(rs.getObject(2, UUID.class));
909+
910+
assertEquals(rs.getString(3), "['" + str + "']");
911+
assertEquals(rs.getArray(3).getArray(), new UUID[] { uuid });
912+
assertEquals(rs.getObject(3, ClickHouseArray.class).getArray(), new UUID[] { uuid });
913+
assertEquals(rs.getObject(3, UUID[].class), new UUID[] { uuid });
914+
915+
assertEquals(rs.getString(4), "[NULL]");
916+
assertEquals(rs.getArray(4).getArray(), new UUID[] { null });
917+
assertEquals(rs.getObject(4, ClickHouseArray.class).getArray(), new UUID[] { null });
918+
assertEquals(rs.getObject(4, UUID[].class), new UUID[] { null });
919+
}
920+
921+
s.execute("truncate table test_uuid");
922+
}
923+
}
924+
925+
@Test
926+
public void testDateTime64() throws Exception {
927+
try (Statement s = conn.createStatement()) {
928+
s.execute("DROP TABLE IF EXISTS test_datetime64");
929+
s.execute(
930+
"CREATE TABLE IF NOT EXISTS test_datetime64(d0 DateTime64(3, 'UTC'), d1 Nullable(DateTime64)) ENGINE = Memory");
931+
} catch (ClickHouseException e) {
932+
return;
933+
}
934+
935+
try (Statement s = conn.createStatement()) {
936+
s.execute("insert into test_datetime64 values (1, null)");
937+
938+
try (ResultSet rs = s.executeQuery("select * from test_datetime64")) {
939+
assertTrue(rs.next());
940+
assertEquals(rs.getObject(1), new Timestamp(1L));
941+
assertEquals(rs.getObject(1, Instant.class), Instant.ofEpochMilli(1L));
942+
assertEquals(rs.getObject(1, LocalDate.class), LocalDate.ofEpochDay(0));
943+
assertEquals(rs.getObject(1, LocalDateTime.class),
944+
Instant.ofEpochMilli(1L).atZone(ZoneId.of("UTC")).toLocalDateTime());
945+
assertNull(rs.getObject(2));
946+
assertNull(rs.getObject(2, Instant.class));
947+
assertNull(rs.getObject(2, LocalDate.class));
948+
assertNull(rs.getObject(2, LocalDateTime.class));
949+
}
950+
951+
s.execute("truncate table test_datetime64");
952+
}
953+
}
954+
880955
@Test
881956
public void testDateTimes() throws Exception {
882957
try (Statement s = conn.createStatement()) {

0 commit comments

Comments
 (0)