Skip to content

Commit 7ad16dd

Browse files
committed
Merge branch 'main' into support_variant_type
2 parents 14fbca6 + fdf6430 commit 7ad16dd

File tree

22 files changed

+400
-416
lines changed

22 files changed

+400
-416
lines changed

.github/workflows/nightly.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212

1313
env:
1414
CHC_BRANCH: "main"
15-
CHC_VERSION: "0.7.2"
15+
CHC_VERSION: "0.8.0"
1616
CH_VERSION: "24.8"
1717

1818
jobs:

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66
version:
77
description: "Release version"
88
required: true
9-
default: "0.7.2-SNAPSHOT"
9+
default: "0.8.0-SNAPSHOT"
1010

1111
env:
1212
CH_VERSION: "24.8"

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
## Latest
22

3+
## 0.8.0
4+
5+
### Highlights
6+
- We've updated `ClickHouseDriver` and `ClickHouseDataSource` to default to using the new (`jdbc-v2`) implementation of the JDBC driver. Setting `clickhouse.jdbc.v1=true` will revert this change.
7+
8+
#### JDBC Changes
9+
- `jdbc-v2` - Removed support for Transaction Support. Early versions of the driver only simulated transaction support, which could have unexpected results.
10+
- `jdbc-v2` - Removed support for Response Column Renaming. `ResultSet` was mutable - for efficiency sake they're now read-only
11+
- `jdbc-v2` - Removed support for Multi-Statement SQL. Multi-statement support was only simulated, now it strictly follows 1:1
12+
- `jdbc-v2` - Removed support for Named Parameters. Not part of the JDBC spec
13+
- `jdbc-v2` - Removed support for Stream-based `PreparedStatement`. Early version of the driver allowed for non-jdbc usage of `PreparedStatement` - if you desire such options, we recommend looking at client-v2.
14+
15+
### New Features
16+
- [client-v2, jdbc-v2] - Added support for Bearer token authentication like JWT. Now it is possible to specify encoded token while
17+
creating a client and change while runtime using `com.clickhouse.client.api.Client.updateBearerToken`. (https://github.com/ClickHouse/clickhouse-java/issues/1834, https://github.com/ClickHouse/clickhouse-java/issues/1988)
18+
- [client-v2] - Exposed connection pool metrics through Micrometer. It allows to monitor internal connection pool for number of active and leased connections. (https://github.com/ClickHouse/clickhouse-java/issues/1901)
19+
20+
### Bug Fixes
21+
- [client-v2] - Fixed construction of `User-Agent` header. Prev. implementation uses `class.getPackage().getImplementationVersion()` what returns
22+
incorrect title and version when library is shaded. New implementation uses build time information from resource files generated while build. (https://github.com/ClickHouse/clickhouse-java/issues/2007)
23+
- [client-v2] - Fixed multiple issues with handling connectivity disruption. Socket timeout is unlimited by default. Added retry on timeout. Added more information to exception message.
24+
Please read the issue for more details. (https://github.com/ClickHouse/clickhouse-java/issues/1994)
25+
- [client-v2] - Client doesn't close provided executor anymore letting application close it instead. (https://github.com/ClickHouse/clickhouse-java/issues/1956)
26+
- [client-v2] - Removed unnecessary initialization to make startup time shorter. (https://github.com/ClickHouse/clickhouse-java/issues/2032)
27+
328
## 0.7.2
429

530
### New Components

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,17 @@ public static List<Path> findFiles(String pattern, String... paths) throws IOExc
357357
}
358358

359359
if (!pattern.startsWith("glob:") && !pattern.startsWith("regex:")) {
360+
if (IS_WINDOWS) {
361+
final String reservedCharsWindows = "<>:\"|?*";
362+
pattern.chars().anyMatch(
363+
value -> {
364+
if (value < ' ' || reservedCharsWindows.indexOf(value) != -1) {
365+
throw new IllegalArgumentException("File path contains reserved character <%s>".formatted((char) value));
366+
}
367+
return false;
368+
}
369+
);
370+
}
360371
Path path = Paths.get(pattern);
361372
if (path.isAbsolute()) {
362373
return Collections.singletonList(path);

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.ArrayList;
88
import java.util.Arrays;
99
import java.util.Collections;
10+
import java.util.Locale;
1011
import java.util.HashMap;
1112
import java.util.LinkedList;
1213
import java.util.List;
@@ -96,8 +97,20 @@ public void testFindFiles() throws IOException {
9697
Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.findFiles(null));
9798
Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.findFiles(""));
9899

100+
if (System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("windows")) {
101+
Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.findFiles("READM?.md"));
102+
Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.findFiles("READM<?.md"));
103+
Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.findFiles("READM>.md"));
104+
Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.findFiles("READM|.md"));
105+
Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.findFiles("READM*.md"));
106+
Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.findFiles("READM<>:\\\"|?*.md"));
107+
Assert.assertThrows(IllegalArgumentException.class, () -> ClickHouseUtils.findFiles(" "));
108+
}
109+
else {
110+
Assert.assertEquals(ClickHouseUtils.findFiles("READM?.md").size(), 1);
111+
}
112+
99113
Assert.assertEquals(ClickHouseUtils.findFiles("README.md").size(), 1);
100-
Assert.assertEquals(ClickHouseUtils.findFiles("READM?.md").size(), 1);
101114
Assert.assertEquals(ClickHouseUtils.findFiles("glob:*.md").size(), 1);
102115
Assert.assertTrue(ClickHouseUtils.findFiles("glob:**.java", "src", "..").size() >= 1);
103116
Assert.assertTrue(ClickHouseUtils.findFiles("glob:**.java", "src/test").size() >= 1);
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
package com.clickhouse.jdbc.comparison;
2+
3+
import com.clickhouse.client.ClickHouseProtocol;
4+
import com.clickhouse.client.ClickHouseServerForTest;
5+
import com.clickhouse.client.api.ClientConfigProperties;
6+
import com.clickhouse.jdbc.ConnectionImpl;
7+
import com.clickhouse.jdbc.JdbcIntegrationTest;
8+
import com.clickhouse.jdbc.internal.ClickHouseConnectionImpl;
9+
import org.testng.Assert;
10+
import org.testng.annotations.Test;
11+
12+
import java.sql.Connection;
13+
import java.sql.Date;
14+
import java.sql.PreparedStatement;
15+
import java.sql.ResultSet;
16+
import java.sql.SQLException;
17+
import java.sql.Statement;
18+
import java.sql.Timestamp;
19+
import java.util.GregorianCalendar;
20+
import java.util.Properties;
21+
import java.util.TimeZone;
22+
23+
import static org.testng.Assert.assertEquals;
24+
import static org.testng.Assert.assertFalse;
25+
import static org.testng.Assert.assertThrows;
26+
import static org.testng.Assert.assertTrue;
27+
28+
public class DateTimeComparisonTest extends JdbcIntegrationTest {
29+
public Connection getJdbcConnectionV1(Properties properties) throws SQLException {
30+
Properties info = new Properties();
31+
info.setProperty("user", "default");
32+
info.setProperty("password", ClickHouseServerForTest.getPassword());
33+
info.setProperty("database", ClickHouseServerForTest.getDatabase());
34+
35+
if (properties != null) {
36+
info.putAll(properties);
37+
}
38+
39+
return new ClickHouseConnectionImpl(getJDBCEndpointString(), info);
40+
}
41+
42+
public Connection getJdbcConnectionV2(Properties properties) throws SQLException {
43+
Properties info = new Properties();
44+
info.setProperty("user", "default");
45+
info.setProperty("password", ClickHouseServerForTest.getPassword());
46+
info.setProperty("database", ClickHouseServerForTest.getDatabase());
47+
48+
if (properties != null) {
49+
info.putAll(properties);
50+
}
51+
52+
info.setProperty(ClientConfigProperties.DATABASE.getKey(), ClickHouseServerForTest.getDatabase());
53+
54+
return new ConnectionImpl(getJDBCEndpointString(), info);
55+
}
56+
57+
public String getJDBCEndpointString() {
58+
return "jdbc:ch:" + (isCloud() ? "" : "http://") +
59+
ClickHouseServerForTest.getClickHouseAddress(ClickHouseProtocol.HTTP, false) + "/" + (isCloud() ? ClickHouseServerForTest.getDatabase() : "");
60+
}
61+
62+
private void run(String query) throws SQLException {
63+
try (Connection connection = getJdbcConnectionV2(null)) {
64+
try (Statement stmt = connection.createStatement()) {
65+
stmt.execute("CREATE DATABASE IF NOT EXISTS " + ClickHouseServerForTest.getDatabase());
66+
stmt.execute(query);
67+
}
68+
}
69+
}
70+
71+
@Test (groups = "integration", enabled = true)
72+
public void setDateTest() throws SQLException {
73+
run("DROP TABLE IF EXISTS test_date");
74+
run("CREATE TABLE IF NOT EXISTS test_date (id Int8, d1 Date, d2 Date, d3 Date) ENGINE = MergeTree ORDER BY id");
75+
76+
try (Connection connV1 = getJdbcConnectionV1(null)) {
77+
try (PreparedStatement stmtV1 = connV1.prepareStatement("INSERT INTO test_date VALUES (1, ?, ?, ?)")) {//INSERT with V1
78+
stmtV1.setDate(1, java.sql.Date.valueOf("2021-01-01"));
79+
stmtV1.setDate(2, java.sql.Date.valueOf("2021-01-01"), new GregorianCalendar());
80+
stmtV1.setDate(3, java.sql.Date.valueOf("2021-01-01"), new GregorianCalendar(TimeZone.getTimeZone("UTC")));
81+
stmtV1.execute();
82+
}
83+
}
84+
85+
try (Connection connV1 = getJdbcConnectionV1(null);
86+
Connection connV2 = getJdbcConnectionV2(null)) {
87+
try (Statement stmtV1 = connV1.createStatement();
88+
Statement stmtV2 = connV2.createStatement()) {
89+
ResultSet rsV1 = stmtV1.executeQuery("SELECT * FROM test_date");
90+
ResultSet rsV2 = stmtV2.executeQuery("SELECT * FROM test_date");
91+
assertTrue(rsV1.next());
92+
assertTrue(rsV2.next());
93+
94+
assertEquals(rsV2.getDate(2), rsV1.getDate(2));
95+
assertEquals(rsV2.getDate(3, new GregorianCalendar()), rsV1.getDate(3, new GregorianCalendar()));
96+
assertEquals(rsV2.getDate(4, new GregorianCalendar(TimeZone.getTimeZone("UTC"))),
97+
rsV1.getDate(4, new GregorianCalendar(TimeZone.getTimeZone("UTC"))));
98+
}
99+
}
100+
}
101+
102+
103+
@Test (groups = "integration", enabled = true)
104+
public void setTimeTest() throws SQLException {
105+
run("DROP TABLE IF EXISTS test_time");
106+
run("CREATE TABLE IF NOT EXISTS test_time (id Int8, t1 Datetime, t2 Datetime, t3 Datetime) ENGINE = MergeTree ORDER BY id");
107+
108+
try (Connection connV1 = getJdbcConnectionV1(null)) {
109+
try (PreparedStatement stmtV1 = connV1.prepareStatement("INSERT INTO test_time VALUES (1, ?, ?, ?)")) {//INSERT with V1
110+
stmtV1.setTime(1, java.sql.Time.valueOf("12:34:56"));
111+
stmtV1.setTime(2, java.sql.Time.valueOf("12:34:56"), new GregorianCalendar());
112+
stmtV1.setTime(3, java.sql.Time.valueOf("12:34:56"), new GregorianCalendar(TimeZone.getTimeZone("UTC")));
113+
stmtV1.execute();
114+
}
115+
}
116+
117+
try (Connection connV1 = getJdbcConnectionV1(null);
118+
Connection connV2 = getJdbcConnectionV2(null)) {
119+
try (Statement stmtV1 = connV1.createStatement();
120+
Statement stmtV2 = connV2.createStatement()) {
121+
ResultSet rsV1 = stmtV1.executeQuery("SELECT * FROM test_time");
122+
ResultSet rsV2 = stmtV2.executeQuery("SELECT * FROM test_time");
123+
assertTrue(rsV1.next());
124+
assertTrue(rsV2.next());
125+
126+
assertEquals(rsV2.getTime(2), rsV1.getTime(2));
127+
assertEquals(rsV2.getTime(3, new GregorianCalendar()), rsV1.getTime(3, new GregorianCalendar()));
128+
assertEquals(rsV2.getTime(4, new GregorianCalendar(TimeZone.getTimeZone("UTC"))),
129+
rsV1.getTime(4, new GregorianCalendar(TimeZone.getTimeZone("UTC"))));
130+
}
131+
}
132+
}
133+
134+
@Test (groups = "integration", enabled = true)
135+
public void setTimestampTest() throws SQLException {
136+
run("DROP TABLE IF EXISTS test_timestamp");
137+
run("CREATE TABLE IF NOT EXISTS test_timestamp (id Int8, t1 Datetime64(3), t2 Datetime64(6), t3 Datetime64(9), t4 DateTime64(9)) ENGINE = MergeTree ORDER BY id");
138+
139+
Timestamp ts = new Timestamp(System.currentTimeMillis());
140+
141+
try (Connection connV1 = getJdbcConnectionV1(null)) {
142+
try (PreparedStatement stmtV1 = connV1.prepareStatement("INSERT INTO test_timestamp VALUES (1, ?, ?, ?, ?)")) {//INSERT with V1
143+
stmtV1.setTimestamp(1, java.sql.Timestamp.valueOf("2021-01-01 01:23:45"));
144+
stmtV1.setTimestamp(2, java.sql.Timestamp.valueOf("2021-01-01 01:23:45"), new GregorianCalendar());
145+
stmtV1.setTimestamp(3, java.sql.Timestamp.valueOf("2021-01-01 01:23:45"), new GregorianCalendar(TimeZone.getTimeZone("UTC")));
146+
stmtV1.setTimestamp(4, ts);
147+
stmtV1.execute();
148+
}
149+
}
150+
151+
try (Connection connV1 = getJdbcConnectionV1(null);
152+
Connection connV2 = getJdbcConnectionV2(null)) {
153+
try (Statement stmtV1 = connV1.createStatement();
154+
Statement stmtV2 = connV2.createStatement()) {
155+
ResultSet rsV1 = stmtV1.executeQuery("SELECT * FROM test_timestamp");
156+
ResultSet rsV2 = stmtV2.executeQuery("SELECT * FROM test_timestamp");
157+
assertTrue(rsV1.next());
158+
assertTrue(rsV2.next());
159+
160+
assertEquals(rsV2.getTimestamp(2), rsV1.getTimestamp(2));
161+
assertEquals(rsV2.getTimestamp(3, new GregorianCalendar()), rsV1.getTimestamp(3, new GregorianCalendar()));
162+
assertEquals(rsV2.getTimestamp(4, new GregorianCalendar(TimeZone.getTimeZone("UTC"))),
163+
rsV1.getTimestamp(4, new GregorianCalendar(TimeZone.getTimeZone("UTC"))));
164+
assertEquals(rsV2.getTimestamp(5), rsV1.getTimestamp(5));
165+
}
166+
}
167+
}
168+
}

0 commit comments

Comments
 (0)