Skip to content

Commit 2c86850

Browse files
authored
Merge branch 'main' into issue-2218
2 parents 21d436a + 6a27f85 commit 2c86850

34 files changed

+484
-377
lines changed

.github/workflows/benchmarks.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Benchmarks
2+
description: Runs minimal JMH benchmark
3+
4+
on:
5+
schedule:
6+
- cron: "55 15 * * *"
7+
workflow_dispatch:
8+
inputs:
9+
pr:
10+
description: "Pull request#"
11+
required: false
12+
13+
env:
14+
CHC_BRANCH: "main"
15+
CH_VERSION: "24.8"
16+
JAVA_VERSION: 17
17+
18+
concurrency:
19+
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.number || github.sha }}
20+
cancel-in-progress: true
21+
22+
jobs:
23+
jmh:
24+
if: ${{ startsWith(github.repository, 'ClickHouse/') }}
25+
name: "Mininal JMH Benchmarks"
26+
runs-on: "ubuntu-latest"
27+
timeout-minutes: 20
28+
steps:
29+
- name: Check out Git repository
30+
uses: actions/checkout@v4
31+
with:
32+
ref: ${{ env.CHC_BRANCH }}
33+
- name: Check out PR
34+
run: |
35+
git fetch --no-tags --prune --progress --no-recurse-submodules --depth=1 \
36+
origin pull/${{ github.event.inputs.pr }}/merge:merged-pr && git checkout merged-pr
37+
if: github.event.inputs.pr != ''
38+
- name: Install JDK and Maven
39+
uses: actions/setup-java@v4
40+
with:
41+
distribution: "temurin"
42+
java-version: ${{ env.JAVA_VERSION }}
43+
cache: "maven"
44+
- name: Build
45+
run: mvn --batch-mode --no-transfer-progress -Dj8 -DskipTests=true clean install
46+
- name: Prepare Dataset
47+
run: |
48+
cd ./performance &&
49+
mvn --batch-mode --no-transfer-progress clean compile exec:exec -Dexec.executable=java \
50+
-Dexec.args="-classpath %classpath com.clickhouse.benchmark.data.DataSetGenerator -input sample_dataset.sql -name default -rows 100000"
51+
- name: Run Benchmarks
52+
run: |
53+
cd ./performance &&
54+
mvn --batch-mode --no-transfer-progress clean compile exec:exec -Dexec.executable=java -Dexec.args="-classpath %classpath com.clickhouse.benchmark.BenchmarkRunner \
55+
-l 100000,10000 -m 3 -t 15 -b q,i -d file://default.csv"
56+
- name: Upload test results
57+
uses: actions/upload-artifact@v4
58+
if: success()
59+
with:
60+
name: result ${{ github.job }}
61+
path: |
62+
performance/jmh-results*

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.clickhouse.jdbc;
22

33
import com.clickhouse.client.api.Client;
4+
import com.clickhouse.client.api.ClientConfigProperties;
45
import com.clickhouse.client.api.internal.ServerSettings;
56
import com.clickhouse.client.api.query.GenericRecord;
67
import com.clickhouse.client.api.query.QuerySettings;
@@ -50,6 +51,7 @@ public class ConnectionImpl implements Connection, JdbcV2Wrapper {
5051
protected String cluster;
5152
private String catalog;
5253
private String schema;
54+
private String appName;
5355
private QuerySettings defaultQuerySettings;
5456

5557
private final com.clickhouse.jdbc.metadata.DatabaseMetaData metadata;
@@ -62,14 +64,27 @@ public ConnectionImpl(String url, Properties info) throws SQLException {
6264
this.config = new JdbcConfiguration(url, info);
6365
this.onCluster = false;
6466
this.cluster = null;
67+
this.appName = "";
6568
String clientName = "ClickHouse JDBC Driver V2/" + Driver.driverVersion;
6669

70+
Map<String, String> clientProperties = config.getClientProperties();
71+
if (clientProperties.get(ClientConfigProperties.CLIENT_NAME.getKey()) != null) {
72+
this.appName = clientProperties.get(ClientConfigProperties.CLIENT_NAME.getKey()).trim();
73+
clientName = this.appName + " " + clientName; // Use the application name as client name
74+
} else if (clientProperties.get(ClientConfigProperties.PRODUCT_NAME.getKey()) != null) {
75+
// Backward compatibility for old property
76+
this.appName = clientProperties.get(ClientConfigProperties.PRODUCT_NAME.getKey()).trim();
77+
clientName = this.appName + " " + clientName; // Use the application name as client name
78+
}
79+
6780
if (this.config.isDisableFrameworkDetection()) {
6881
log.debug("Framework detection is disabled.");
6982
} else {
7083
String detectedFrameworks = Driver.FrameworksDetection.getFrameworksDetected();
7184
log.debug("Detected frameworks: {}", detectedFrameworks);
72-
clientName += " (" + detectedFrameworks + ")";
85+
if (!detectedFrameworks.trim().isEmpty()) {
86+
clientName += " (" + detectedFrameworks + ")";
87+
}
7388
}
7489

7590
this.client = this.config.applyClientProperties(new Client.Builder())
@@ -441,8 +456,6 @@ public boolean isValid(int timeout) throws SQLException {
441456
return true;
442457
}
443458

444-
private String appName = "";
445-
446459
@Override
447460
public void setClientInfo(String name, String value) throws SQLClientInfoException {
448461
if (ClientInfoProperties.APPLICATION_NAME.getKey().equals(name)) {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ protected static String parseJdbcEscapeSyntax(String sql) {
134134
// Handle outer escape syntax
135135
//sql = sql.replaceAll("\\{escape '([^']*)'\\}", "'$1'");
136136

137+
// Clean new empty lines in sql
138+
sql = sql.replaceAll("(?m)^\\s*$\\n?", "");
137139
// Add more replacements as needed for other JDBC escape sequences
138140
LOG.trace("Parsed SQL: {}", sql);
139141
return sql;

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.clickhouse.client.api.Client;
44
import com.clickhouse.client.api.ClientConfigProperties;
55
import com.clickhouse.jdbc.Driver;
6+
import com.google.common.collect.ImmutableMap;
67

78
import java.net.URI;
89
import java.sql.DriverPropertyInfo;
@@ -26,6 +27,9 @@ public class JdbcConfiguration {
2627
final boolean disableFrameworkDetection;
2728

2829
final Map<String, String> clientProperties;
30+
public Map<String, String> getClientProperties() {
31+
return ImmutableMap.copyOf(clientProperties);
32+
}
2933

3034
private final Map<String, String> driverProperties;
3135

@@ -62,6 +66,7 @@ public JdbcConfiguration(String url, Properties info) throws SQLException {
6266
if (bearerToken != null) {
6367
clientProperties.put(ClientConfigProperties.BEARERTOKEN_AUTH.getKey(), bearerToken);
6468
}
69+
6570
this.connectionUrl = createConnectionURL(tmpConnectionUrl, useSSL);
6671
this.isIgnoreUnsupportedRequests= Boolean.parseBoolean(getDriverProperty(DriverProperties.IGNORE_UNSUPPORTED_VALUES.getKey(), "false"));
6772
}
@@ -186,9 +191,7 @@ private void initProperties(Map<String, String> urlProperties, Properties provid
186191
}
187192
}
188193

189-
for (Map.Entry<String, String> entry : urlProperties.entrySet()) {
190-
props.put(entry.getKey(), entry.getValue());
191-
}
194+
props.putAll(urlProperties);
192195

193196
// Process all properties
194197
Map<String, DriverPropertyInfo> propertyInfos = new HashMap<>();

jdbc-v2/src/test/java/com/clickhouse/jdbc/ConnectionTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,35 @@ public void setAndGetClientInfoTest(String clientName) throws SQLException {
282282
}
283283
}
284284

285+
@Test(groups = { "integration" })
286+
public void influenceUserAgentClientNameTest() throws SQLException {
287+
String clientName = UUID.randomUUID().toString().replace("-", "");
288+
influenceUserAgentTest(clientName, "?" + ClientConfigProperties.CLIENT_NAME.getKey() + "=" + clientName);
289+
influenceUserAgentTest(clientName, "?" + ClientConfigProperties.PRODUCT_NAME.getKey() + "=" + clientName);
290+
}
291+
private void influenceUserAgentTest(String clientName, String urlParam) throws SQLException {
292+
Properties info = new Properties();
293+
info.setProperty("user", "default");
294+
info.setProperty("password", ClickHouseServerForTest.getPassword());
295+
info.setProperty(ClientConfigProperties.DATABASE.getKey(), ClickHouseServerForTest.getDatabase());
296+
297+
try (Connection localConnection = new ConnectionImpl(getEndpointString() + urlParam, info);
298+
Statement stmt = localConnection.createStatement()) {
299+
300+
final String testQuery = "SELECT '" + UUID.randomUUID() + "'";
301+
stmt.execute(testQuery);
302+
stmt.execute("SYSTEM FLUSH LOGS");
303+
304+
final String logQuery ="SELECT http_user_agent " +
305+
" FROM system.query_log WHERE query = '" + testQuery.replaceAll("'", "\\\\'") + "'";
306+
try (ResultSet rs = stmt.executeQuery(logQuery)) {
307+
Assert.assertTrue(rs.next());
308+
String userAgent = rs.getString("http_user_agent");
309+
Assert.assertTrue(userAgent.startsWith(clientName), "Expected to start with '" + clientName + "' but value was '" + userAgent + "'");
310+
}
311+
}
312+
}
313+
285314
@DataProvider(name = "setAndGetClientInfoTestDataProvider")
286315
public static Object[][] setAndGetClientInfoTestDataProvider() {
287316
return new Object[][] {

jdbc-v2/src/test/java/com/clickhouse/jdbc/StatementTest.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,73 @@ public void testSwitchDatabase() throws Exception {
573573
}
574574
}
575575
}
576+
577+
578+
@Test(groups = { "integration" })
579+
public void testNewLineSQLParsing() throws Exception {
580+
try (Connection conn = getJdbcConnection()) {
581+
String sqlCreate = "CREATE TABLE balance ( `id` UUID, `currency` String, `amount` Decimal(64, 18), `create_time` DateTime64(6), `_version` UInt64, `_sign` UInt8 ) ENGINE = ReplacingMergeTree PRIMARY KEY id ORDER BY id;";
582+
try (Statement stmt = conn.createStatement()) {
583+
int r = stmt.executeUpdate(sqlCreate);
584+
assertEquals(r, 0);
585+
}
586+
try (Statement stmt = conn.createStatement()) {
587+
String sqlInsert = "INSERT INTO balance VALUES (generateUUIDv4(), 'EUR', '42.42', now(), 144, 255);";
588+
int r = stmt.executeUpdate(sqlInsert);
589+
assertEquals(r, 1);
590+
}
591+
try (Statement stmt = conn.createStatement()) {
592+
String sqlSelect = new StringBuilder("-- SELECT amount FROM balance FINAL;\n")
593+
.append("SELECT amount FROM balance FINAL;").toString();
594+
ResultSet rs = stmt.executeQuery(sqlSelect);
595+
assertTrue(rs.next());
596+
}
597+
try (Statement stmt = conn.createStatement()) {
598+
String sqlSelect = new StringBuilder("-- SELECT * FROM balance\n")
599+
.append("\n")
600+
.append("WITH balance_cte AS (\n")
601+
.append("SELECT\n")
602+
.append("id, currency, amount\n")
603+
.append("FROM balance\n")
604+
.append("LIMIT 10\n")
605+
.append(")\n")
606+
.append("SELECT * FROM balance_cte;").toString();
607+
ResultSet rs = stmt.executeQuery(sqlSelect);
608+
assertTrue(rs.next());
609+
assertFalse(rs.next());
610+
}
611+
try (Statement stmt = conn.createStatement()) {
612+
String sqlSelect = new StringBuilder("-- SELECT amount FROM balance FINAL;\n")
613+
.append("\n")
614+
.append("SELECT amount FROM balance FINAL;").toString();
615+
ResultSet rs = stmt.executeQuery(sqlSelect);
616+
assertTrue(rs.next());
617+
}
618+
try (Statement stmt = conn.createStatement()) {
619+
String sqlSelect = new StringBuilder("-- SELECT amount FROM balance FINAL;\n")
620+
.append("\n")
621+
.append("SELECT amount /* test */FROM balance FINAL;").toString();
622+
ResultSet rs = stmt.executeQuery(sqlSelect);
623+
assertTrue(rs.next());
624+
}
625+
try (Statement stmt = conn.createStatement()) {
626+
String sqlSelect = new StringBuilder("-- SELECT amount FROM balance FINAL;\n")
627+
.append("\n")
628+
.append("SELECT amount FROM balance FINAL; /* test */").toString();
629+
ResultSet rs = stmt.executeQuery(sqlSelect);
630+
assertTrue(rs.next());
631+
}
632+
try (Statement stmt = conn.createStatement()) {
633+
String sqlSelect = new StringBuilder("-- SELECT amount FROM balance FINAL;\n")
634+
.append("\n")
635+
.append("SELECT amount FROM balance FINAL; /* test */ -- SELECT 1").toString();
636+
ResultSet rs = stmt.executeQuery(sqlSelect);
637+
assertTrue(rs.next());
638+
}
639+
}
640+
}
576641

642+
577643
@Test(groups = { "integration" })
578644
public void testNullableFixedStringType() throws Exception {
579645
try (Connection conn = getJdbcConnection()) {

performance/README.md

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,46 @@
11

2+
## JMH Benchmarks
23

3-
## DataSetGenerator
4+
5+
### Dependencies
6+
7+
8+
9+
### How to Run
10+
11+
12+
#### Generating Dataset
413

514
```shell
6-
mvn exec:java -Dscope=test -Dexec.mainClass="com.clickhouse.benchmark.data.ClickHouseDataTypesShort" -input <table_fields.sql> -rows <number_of_rows>
15+
mvn compile exec:exec -Dexec.executable=java -Dexec.args="-classpath %classpath com.clickhouse.benchmark.data.DataSetGenerator \
16+
-input sample_dataset.sql -name default -rows 10"
717
```
818

19+
#### Running Benchmarks
20+
21+
With default settings :
22+
```shell
23+
mvn compile exec:exec
24+
```
925

10-
## Performance Test
11-
12-
with custom dataset
26+
With custom measurement iterations:
1327
```shell
14-
mvn test-compile exec:java -Dexec.classpathScope=test -Dexec.mainClass="com.clickhouse.benchmark.BenchmarkRunner" -Dexec.args="--dataset=file://dataset_1741150759025.csv"
28+
mvn compile exec:exec -Dexec.executable=java -Dexec.args="-classpath %classpath com.clickhouse.benchmark.BenchmarkRunner -m 3"
1529
```
1630

31+
Other options:
32+
- "-d" - dataset name or file path (like `file://default.csv`)
33+
- "-l" - dataset limits to test coma separated (ex.: `-l 10000,10000`)
34+
- "-m" - number of measurement iterations
35+
- "-t" - time in seconds per iteration
36+
- "-b" - benchmark mask coma separated. Ex.: `-b writer,reader,i`. Default : `-b i,q`
37+
- "all" - Run alpl benchmarks
38+
- "i" - InsertClient - insert operation benchmarks
39+
- "q" - QueryClient - query operation benchmarks
40+
- "ci" - ConcurrentInsertClient - concurrent version of insert benchmarks
41+
- "cq" - ConcurrentQueryClient - concurrent version of query benchmarks
42+
- "lz" - Compression - compression related benchmarks
43+
- "writer" - Serializer - serialization only logic benchmarks
44+
- "reader" - DeSerilalizer - deserialization only logic benchmarks
45+
- "mixed" - MixedWorkload
46+

0 commit comments

Comments
 (0)