Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ target/
**/parser/ClickHouseSqlParserTokenManager.java
**/parser/Token*.java
**/parser/ParseException.java
java.prof
jmh-result.*
profile.html

# Shell scripts
*.sh
14 changes: 14 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
0.3.1-patch
* fix incorrect database used in DDL
* fix batch insert issue when no VALUES used in SQL statement
* fix issue of handling negative decimal128/256 values

0.3.1
* BREAKING CHANGE - move query from url to request body
* BREAKING CHANGE - always parse SQL(use extended API to skip that)
Expand All @@ -10,6 +15,7 @@
* fix parser issue when DESC statement contains alias
* support batch processing with arbitrary query - update and delete are not recommended so there'll be warnings
* support multi-statement sql - session will be used automatically and only the last result will be returned

0.3.0
* BREAKING CHANGE - dropped JDK 7 support
* BREAKING CHANGE - removed Guava dependency(and so is UnsignedLong)
Expand All @@ -23,6 +29,7 @@
* fix error when using ClickHouseCompression.none against 19.16
* fix NegativeArraySizeException when dealing with large array
* fix datetime/date display issue caused by timezone differences(between client and column/server)

0.2.6
* add new feature for sending compressed files/streams
* introduce an experimental SQL parser to fix parsing related issues - set connection setting use_new_parser to false to disable
Expand All @@ -33,6 +40,7 @@
* upgrade to lz4-java and improve performance of LZ4 stream
* use HTTP Basic Auth for credentials instead of query parameters
* use static version instead of property-based revision in pom.xml

0.2.5
* bump dependencies and include lz4 in shaded jar
* new API: ClickHouseRowBinaryStream.writeUInt64Array(UnsignedLong[])
Expand All @@ -42,20 +50,26 @@
* fix ResultSet.findColumn(String) issue
* fix the issue of not being able to use NULL constant in PreparedStatement
* fix toLowerCase issue for Turkish

0.2.4
* fix FORMAT clause append for queries, ending with comment

0.2.3
* added support for Decimals in RowBinary protocol

0.2.2
* close certificate keystore
* fix for Boolean data type

0.2.1
* implement some ResultSet metadata methods
* added support for "any_join_distinct_right_table_keys" setting
* nested array support

0.2
* new API for writing streams of data
* deprecation of send* methods in ClickHouseStatement interface

0.1.55
NOTE: behavior for byte[] parameters changed. See https://github.com/yandex/clickhouse-jdbc/pull/352
* support for sending stream of CSV data
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ ClickHouse JDBC driver
This is a basic and restricted implementation of jdbc driver for ClickHouse.
It has support of a minimal subset of features to be usable.


### Usage
```xml
<dependency>
<groupId>ru.yandex.clickhouse</groupId>
<artifactId>clickhouse-jdbc</artifactId>
<version>0.3.1</version>
<version>0.3.2</version>
</dependency>
```

Expand Down Expand Up @@ -46,6 +47,7 @@ try (ClickHouseConnection conn = dataSource.getConnection();

Additionally, if you have a few instances, you can use `BalancedClickhouseDataSource`.


### Extended API
In order to provide non-JDBC complaint data manipulation functionality, proprietary API exists.
Entry point for API is `ClickHouseStatement#write()` method.
Expand All @@ -61,6 +63,7 @@ sth
.data(new File("/path/to/file.csv.gz"), ClickHouseFormat.CSV, ClickHouseCompression.gzip) // specify input
.send();
```

#### Configurable send
```java
import ru.yandex.clickhouse.ClickHouseStatement;
Expand All @@ -73,6 +76,7 @@ sth
.addDbParam(ClickHouseQueryParam.MAX_PARALLEL_REPLICAS, 2)
.send();
```

#### Send data in binary formatted with custom user callback
```java
import ru.yandex.clickhouse.ClickHouseStatement;
Expand All @@ -88,6 +92,12 @@ sth.write().send("INSERT INTO test.writer", new ClickHouseStreamCallback() {
},
ClickHouseFormat.RowBinary); // RowBinary or Native are supported
```


### Supported Server Versions
All [active releases](../ClickHouse/pulls?q=is%3Aopen+is%3Apr+label%3Arelease) are supported. You can still use the driver for older versions like 18.14 or 19.16 but please keep in mind that they're no longer supported.


### Compiling with maven
The driver is built with maven.
`mvn package -DskipTests=true`
Expand All @@ -96,5 +106,6 @@ To build a jar with dependencies use

`mvn package assembly:single -DskipTests=true`


### Build requirements
In order to build the jdbc client one need to have jdk 1.7 or higher.
In order to build the jdbc client one need to have jdk 1.8 or higher.
21 changes: 16 additions & 5 deletions clickhouse-benchmark/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

<properties>
<clickhouse4j-driver.version>1.4.4</clickhouse4j-driver.version>
<mariadb-driver.version>2.7.2</mariadb-driver.version>
<mysql-driver.version>8.0.23</mysql-driver.version>
<native-driver.version>2.5.4</native-driver.version>
<testcontainers.version>1.15.2</testcontainers.version>
<mariadb-driver.version>2.7.3</mariadb-driver.version>
<mysql-driver.version>8.0.25</mysql-driver.version>
<native-driver.version>2.5.6</native-driver.version>
<postgresql-driver.version>42.2.22</postgresql-driver.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jmh.version>1.27</jmh.version>
<jmh.version>1.32</jmh.version>
<shade.name>benchmarks</shade.name>
</properties>

Expand Down Expand Up @@ -97,6 +97,17 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql-driver.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,27 @@
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collections;
import java.util.Random;
import org.openjdk.jmh.annotations.Benchmark;

public class Basic extends JdbcBenchmark {
@Benchmark
public int selectOneRandomNumber(ClientState state) throws Throwable {
final int num = new Random().nextInt(1000);
public int insertOneRandomNumber(ClientState state) throws Throwable {
final int num = state.getRandomSample();

try (Statement stmt = executeQuery(state, "select ? as n", num)) {
ResultSet rs = stmt.getResultSet();
return executeInsert(state, "insert into test_insert(i) values(?)",
Collections.enumeration(Collections.singletonList(new Object[] { num })));
}

rs.next();
@Benchmark
public int selectOneRandomNumber(ClientState state) throws Throwable {
final int num = state.getRandomSample();

if (num != rs.getInt(1)) {
try (Statement stmt = executeQuery(state, "select ? as n", num); ResultSet rs = stmt.getResultSet();) {
if (!rs.next() || num != rs.getInt(1)) {
throw new IllegalStateException();
}

return num;
}
}

@Benchmark
public int insertOneRandomNumber(ClientState state) throws Throwable {
final int num = new Random().nextInt(1000);

return executeInsert(state, "insert into test_insert(i) values(?)",
Collections.enumeration(Collections.singletonList(new Object[] { num })));
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package tech.clickhouse.benchmark;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.Random;

import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
Expand All @@ -13,27 +16,43 @@

@State(Scope.Thread)
public class ClientState {
@Param(value = { "clickhouse4j", Constants.CLICKHOUSE_DRIVER, "clickhouse-native-jdbc-shaded",
"mariadb-java-client", "mysql-connector-java" })
// sample size used in 10k query/insert
private final int SAMPLE_SIZE = Integer.parseInt(System.getProperty("sampleSize", "10000"));
// floating range(to reduce server-side cache hits) used in 10k query/insert
private final int FLOATING_RANGE = Integer.parseInt(System.getProperty("floatingRange", "100"));

@Param(value = { "clickhouse4j", "clickhouse-jdbc", "clickhouse-native-jdbc-shaded", "mariadb-java-client",
"mysql-connector-java", "postgresql-jdbc" })
private String client;

@Param(value = { Constants.REUSE_CONNECTION, Constants.NEW_CONNECTION })
private String connection;

@Param(value = { Constants.NORMAL_STATEMENT, Constants.PREPARED_STATEMENT })
private String statement;

private Driver driver;
private String url;
private Connection conn;

private int randomSample;
private int randomNum;

@Setup(Level.Trial)
public void doSetup(ServerState serverState) throws Exception {
JdbcDriver driver = JdbcDriver.from(client);
JdbcDriver jdbcDriver = JdbcDriver.from(client);

try {
conn = ((java.sql.Driver) Class.forName(driver.getClassName()).getDeclaredConstructor().newInstance())
.connect(String.format(driver.getUrlTemplate(), serverState.getHost(),
serverState.getPort(driver.getDefaultPort()), serverState.getDatabase(),
serverState.getUser(), serverState.getPassword()), new Properties());
driver = (java.sql.Driver) Class.forName(jdbcDriver.getClassName()).getDeclaredConstructor().newInstance();
url = String.format(jdbcDriver.getUrlTemplate(), serverState.getHost(),
serverState.getPort(jdbcDriver.getDefaultPort()), serverState.getDatabase(), serverState.getUser(),
serverState.getPassword());
conn = driver.connect(url, new Properties());

try (Statement s = conn.createStatement()) {
s.execute("create table if not exists system.test_insert(i Nullable(UInt64), s Nullable(String), t Nullable(DateTime))engine=Memory");
s.execute("truncate table if exists system.test_insert");
s.execute(
"create table if not exists system.test_insert(i Nullable(UInt64), s Nullable(String), t Nullable(DateTime))engine=Memory");
}
} catch (SQLException e) {
e.printStackTrace();
Expand All @@ -43,17 +62,56 @@ public void doSetup(ServerState serverState) throws Exception {

@TearDown(Level.Trial)
public void doTearDown(ServerState serverState) throws SQLException {
try (Statement s = conn.createStatement()) {
s.execute("drop table if exists system.test_insert");
if (conn != null) {
conn.close();
}
}

@Setup(Level.Iteration)
public void prepare() {
if (!Constants.REUSE_CONNECTION.equalsIgnoreCase(connection)) {
try {
conn = driver.connect(url, new Properties());
} catch (SQLException e) {
throw new IllegalStateException("Failed to create new connection", e);
}
}
conn.close();

Random random = new Random();
randomSample = random.nextInt(SAMPLE_SIZE);
randomNum = random.nextInt(FLOATING_RANGE);
}

@TearDown(Level.Iteration)
public void shutdown() {
if (!Constants.REUSE_CONNECTION.equalsIgnoreCase(connection)) {
try {
conn.close();
} catch (SQLException e) {
throw new IllegalStateException("Failed to close connection", e);
} finally {
conn = null;
}
}
}

public int getSampleSize() {
return SAMPLE_SIZE;
}

public int getRandomSample() {
return randomSample;
}

public int getRandomNumber() {
return randomNum;
}

public Connection getConnection() {
return this.conn;
public Connection getConnection() throws SQLException {
return conn;
}

public boolean usePreparedStatement() {
return Constants.PREPARED_STATEMENT.equals(this.statement);
return Constants.PREPARED_STATEMENT.equalsIgnoreCase(this.statement);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
* Constant interface.
*/
public interface Constants {
public static final String CLICKHOUSE_DRIVER = "clickhouse-jdbc";

public static final String DEFAULT_HOST = "127.0.0.1";
public static final String DEFAULT_DB = "system";
public static final String DEFAULT_USER = "default";
public static final String DEFAULT_PASSWD = "";

public static final int GRPC_PORT = 9100;
public static final int HTTP_PORT = 8123;
public static final int MYSQL_PORT = 3307;
public static final int MYSQL_PORT = 9004;
public static final int NATIVE_PORT = 9000;
public static final int POSTGRESQL_PORT = 9005;

public static final String NORMAL_STATEMENT = "normal";
public static final String PREPARED_STATEMENT = "prepared";

public static final String REUSE_CONNECTION = "reuse";
public static final String NEW_CONNECTION = "new";
}
Loading