JDBC Driver
clickhouse-jdbc implements the standard JDBC interface using the latest java client.
We recommend using the latest java client directly if performance/direct access is critical.
Environment requirements
- OpenJDK version >= 8
Setup
- Maven
- Gradle (Kotlin)
- Gradle
Configuration
Driver Class: com.clickhouse.jdbc.ClickHouseDriver
com.clickhouse.jdbc.ClickHouseDriver is a facade class for the new and old JDBC implementations. It uses the new JDBC implementation by default.
You can use the old JDBC implementation by setting the clickhouse.jdbc.v1 property to true in the connection properties.
com.clickhouse.jdbc.Driver is new JDBC implementation.
com.clickhouse.jdbc.DriverV1 is old JDBC implementation.
URL Syntax: jdbc:(ch|clickhouse)[:<protocol>]://endpoint[:port][/<database>][?param1=value1¶m2=value2][#tag1,tag2,...], for example:
jdbc:clickhouse:http://localhost:8123jdbc:clickhouse:https://localhost:8443?ssl=true
There are a few things to note about the URL syntax:
- only one endpoint is allowed in the URL
- protocol should be specified when it is not the default one - 'HTTP'
- port should be specified when it is not the default one '8123'
- driver do not guess the protocol from the port, you need to specify it explicitly
sslparameter is not required when protocol is specified.
Connection Properties
Main configuration parameters are defined in the java client. They should be passed as is to the driver. Driver has some own properties that are not part of the client configuration they are listed below.
Driver properties:
| Property | Default | Description |
|---|---|---|
disable_frameworks_detection | true | Disable frameworks detection for User-Agent |
jdbc_ignore_unsupported_values | false | Suppresses SQLFeatureNotSupportedException where is doesn't affect the driver work |
clickhouse.jdbc.v1 | false | Use older JDBC implementation instead of new JDBC |
default_query_settings | null | Allows passing of default query settings with query operations |
jdbc_resultset_auto_close | true | Automatically closes ResultSet when Statement is closed |
beta.row_binary_for_simple_insert | false | Use PreparedStatement implementation based on RowBinary writer. Works only for INSERT INTO ... VALUES queries. |
jdbc_resultset_auto_close | true | Automatically closes ResultSet when Statement is closed |
jdbc_use_max_result_rows | false | Enables using server property max_result_rows to limit number of rows returned by query. When enabled, overrides user-set overflow mode. See JavaDoc for details. |
jdbc_sql_parser | JAVACC | Configures which SQL parser to use. Choices: ANTLR4, ANTLR4_PARAMS_PARSER, JAVACC. |
All server settings should be prefixed with clickhouse_setting_ (same as for the client configuration).
Example configuration:
what will be equivalent to the following JDBC URL:
Note: no need to url encode JDBC URL or properties, they will be automatically encoded.
Supported data types
JDBC Driver supports the same data formats as the underlying java client.
JDBC Type Mapping
Following mapping applies to:
ResultSet#getObject(columnIndex)- method will return object of the corresponding Java class. (Int8->java.lang.Byte,Int16->java.lang.Short, etc.)ResultSetMetaData#getColumnType(columnIndex)- method will return the corresponding JDBC type. (Int8->java.lang.Byte,Int16->java.lang.Short, etc.)
There are few ways to change the mapping:
ResultSet#getObject(columnIndex, class)- method will try to convert value toclasstype. There are some conversion limitations. See each section for details.
Numeric Types
| ClickHouse Type | JDBC Type | Java Class |
|---|---|---|
| Int8 | TINYINT | java.lang.Byte |
| Int16 | SMALLINT | java.lang.Short |
| Int32 | INTEGER | java.lang.Integer |
| Int64 | BIGINT | java.lang.Long |
| Int128 | OTHER | java.math.BigInteger |
| Int256 | OTHER | java.math.BigInteger |
| UInt8 | OTHER | java.lang.Short |
| UInt16 | OTHER | java.lang.Integer |
| UInt32 | OTHER | java.lang.Long |
| UInt64 | OTHER | java.math.BigInteger |
| UInt128 | OTHER | java.math.BigInteger |
| UInt256 | OTHER | java.math.BigInteger |
| Float32 | REAL | java.lang.Float |
| Float64 | DOUBLE | java.lang.Double |
| Decimal32 | DECIMAL | java.math.BigDecimal |
| Decimal64 | DECIMAL | java.math.BigDecimal |
| Decimal128 | DECIMAL | java.math.BigDecimal |
| Decimal256 | DECIMAL | java.math.BigDecimal |
| Bool | BOOLEAN | java.lang.Boolean |
- numeric types are interconvertible. So
Int8can be get asFloat64and vice versa.:rs.getObject(1, Float64.class)will returnFloat64value ofInt8column.rs.getLong(1)will returnLongvalue ofInt8column.rs.getByte(1)can returnBytevalue ofInt16column if it fits intoByte.
- conversion from wider to narrower type is not recommend because of data coruption risk.
Booltype acts as number, too.- All number types can be read as
java.lang.String.
String Types
| ClickHouse Type | JDBC Type | Java Class |
|---|---|---|
| String | VARCHAR | java.lang.String |
| FixedString | VARCHAR | java.lang.String |
Stringcan be read only asjava.lang.Stringorbyte[].FixedStringis read as is and will be padded with zeros to the length of the column. (For exampleFixedString(10)for'John'will be read as'John\0\0\0\0\0\0\0\0\0'.)
Enum Types
| ClickHouse Type | JDBC Type | Java Class |
|---|---|---|
| Enum8 | OTHER | java.lang.String |
| Enum16 | OTHER | java.lang.String |
Enum8andEnum16are mapped tojava.lang.Stringby default.- Enum values can be read as numeric values using designtated getter method or
getObject(columnIndex, Integer.class)method. Enum16is mapped to short and Enum8 is mapped to byte internally. ReadingEnum16as byte should be avoided because of data coruption risk.- Enum values can be set as string or numeric value in
PreparedStatement.
Date/Time Types
| ClickHouse Type | JDBC Type | Java Class |
|---|---|---|
| Date | DATE | java.sql.Date |
| Date32 | DATE | java.sql.Date |
| DateTime | TIMESTAMP | java.sql.Timestamp |
| DateTime64 | TIMESTAMP | java.sql.Timestamp |
| Time | TIME | java.sql.Time |
| Time64 | TIME | java.sql.Time |
- Date / Time types are mapped to
java.sqltypes for better compatibility with JDBC. However gettingjava.time.LocalDate,java.time.LocalDateTime,java.time.LocalTimeis possible by usingResultSet#getObject(columnIndex, Class<T>)with the corresponding class as the second argument.rs.getObject(1, java.time.LocalDate.class)will returnjava.time.LocalDatevalue ofDatecolumn.rs.getObject(1, java.time.LocalDateTime.class)will returnjava.time.LocalDateTimevalue ofDateTimecolumn.rs.getObject(1, java.time.LocalTime.class)will returnjava.time.LocalTimevalue ofTimecolumn.
Date,Date32,Time,Time64is not affected by the timezone of the server.DateTime,DateTime64is affected by the timezone of the server or session timezone.DateTimeandDateTime64can be retrieved asZonedDateTimeby usinggetObject(colIndex, ZonedDateTime.class).
Collection Types
| ClickHouse Type | JDBC Type | Java Class |
|---|---|---|
| Array | ARRAY | java.sql.Array |
| Tuple | OTHER | Object[] |
| Map | JAVA_OBJECT | java.util.Map |
Arrayis mapped tojava.sql.Arrayby default to be compatible with JDBC. This is also done to give more information about returned array value. Useful for type inference.ArrayimplementsgetResultSet()method to returnjava.sql.ResultSetwith the same content as the original array.- Collection types should not be read as
java.lang.Stringbecause it is not a valid way to represent the data (Ex. there is no quoting for string values in array). Mapis mapped toJAVA_OBJECTbecause value can be read only withgetObject(columnIndex, Class<T>)method.Mapis not ajava.sql.Structbecause it doesn't have named columns.
Tupleis mapped toObject[]because it can contain different types and usingListis not valid.Tuplecan be read asArrayby usinggetObject(columnIndex, Array.class)method. In this caseArray#baseTypeNamewill returnTuplecolumn definition.
Geo Types
| ClickHouse Type | JDBC Type | Java Class |
|---|---|---|
| Point | OTHER | double[] |
| Ring | OTHER | double[][] |
| Polygon | OTHER | double[][][] |
| MultiPolygon | OTHER | double[][][][] |
Nullable and LowCardinality Types
NullableandLowCardinalityare special types that wrap other types.Nullableaffects how type names are returned inResultSetMetaData
Special Types
| ClickHouse Type | JDBC Type | Java Class |
|---|---|---|
| UUID | OTHER | java.util.UUID |
| IPv4 | OTHER | java.net.Inet4Address |
| IPv6 | OTHER | java.net.Inet6Address |
| JSON | OTHER | java.lang.String |
| AggregateFunction | OTHER | (binary representation) |
| SimpleAggregateFunction | (wrapped type) | (wrapped class) |
UUIDis not JDBC standard type. However it is part of JDK. By defaultjava.util.UUIDis returned ongetObject()method.UUIDcan be read/written asStringby usinggetObject(columnIndex, String.class)method.IPv4andIPv6are not JDBC standard types. However they are part of JDK. By defaultjava.net.Inet4Addressandjava.net.Inet6Addressare returned ongetObject()method.IPv4andIPv6can be read/written asStringby usinggetObject(columnIndex, String.class)method.
Handling Dates, Times, and Timezones
java.sql.Date, java.sql.Time, and java.sql.Timestamp can complicate how Timezones are calculated - though they're of course supported,
you may want to consider using the java.time package. ZonedDateTime and
OffsetDateTime are both great replacements for java.sql.Timestamp, java.sql.Date, and java.sql.Time.
Date is stored without timezone, while DateTime is stored with timezone. This can lead to unexpected results if you're not careful.
Creating Connection
Supplying Credentials and Settings
Simple Statement
Insert
HikariCP
More Information
For more information, see our GitHub repository and Java Client documentation.
Troubleshooting
Logging
The driver uses slf4j for logging, and will use the first available implementation on the classpath.
Resolving JDBC Timeout on Large Inserts
When performing large inserts in ClickHouse with long execution times, you may encounter JDBC timeout errors like:
These errors can disrupt the data insertion process and affect system stability. To address this issue you may need to adjust a few timeout settings in the client's OS.
Mac OS
On Mac OS, the following settings can be adjusted to resolve the issue:
net.inet.tcp.keepidle: 60000net.inet.tcp.keepintvl: 45000net.inet.tcp.keepinit: 45000net.inet.tcp.keepcnt: 8net.inet.tcp.always_keepalive: 1
Linux
On Linux, the equivalent settings alone may not resolve the issue. Additional steps are required due to the differences in how Linux handles socket keep-alive settings. Follow these steps:
- Adjust the following Linux kernel parameters in
/etc/sysctl.confor a related configuration file:
net.inet.tcp.keepidle: 60000net.inet.tcp.keepintvl: 45000net.inet.tcp.keepinit: 45000net.inet.tcp.keepcnt: 8net.inet.tcp.always_keepalive: 1net.ipv4.tcp_keepalive_intvl: 75net.ipv4.tcp_keepalive_probes: 9net.ipv4.tcp_keepalive_time: 60 (You may consider lowering this value from the default 300 seconds)
- After modifying the kernel parameters, apply the changes by running the following command:
After Setting those settings, you need to ensure that your client enables the Keep Alive option on the socket:
Migration Guide
Key Changes
| Feature | V1 (Old) | V2 (New) |
|---|---|---|
| Transaction Support | Partially supported | Not supported |
| Response Column Renaming | Partially supported | Not supported |
| Multi-Statement SQL | Not supported | Not allowed |
| Named Parameters | Supported | Not supported (not in JDBC spec) |
Streaming Data With PreparedStatement | Supported | Not supported |
- JDBC V2 is implemented to be more lightweight and some features were removed.
- Streaming Data is not supported in JDBC V2 because it is not part of the JDBC spec and Java.
- JDBC V2 expects explicit configuration. No failover defaults.
- Protocol should be specified in the URL. No implicit protocol detection using port numbers.
Configuration Changes
There are only two enums:
com.clickhouse.jdbc.DriverProperties- the driver own configuration properties.com.clickhouse.client.api.ClientConfigProperties- the client configuration properties. Client configuration changes are described in the Java Client documentation.
Connection properties are parsed in the following way:
- URL is parsed first for properties. They override all other properties.
- Driver properties are not passed to the client.
- Endpoints (host, port, protocol) are parsed from the URL.
Example:
Data Types Changes
Numeric Types
| ClickHouse Type | Changed | JDBC Type (V2) | Java Class (V2) | JDBC Type (V1) | Java Class (V1) |
|---|---|---|---|---|---|
| Int8 | No | TINYINT | java.lang.Byte | TINYINT | java.lang.Byte |
| Int16 | No | SMALLINT | java.lang.Short | SMALLINT | java.lang.Short |
| Int32 | No | INTEGER | java.lang.Integer | INTEGER | java.lang.Integer |
| Int64 | No | BIGINT | java.lang.Long | BIGINT | java.lang.Long |
| Int128 | No | OTHER | java.math.BigInteger | OTHER | java.math.BigInteger |
| Int256 | No | OTHER | java.math.BigInteger | OTHER | java.math.BigInteger |
| UInt8 | Yes | OTHER | java.lang.Short | OTHER | com.clickhouse.data.value.UnsignedByte |
| UInt16 | Yes | OTHER | java.lang.Integer | OTHER | com.clickhouse.data.value.UnsignedShort |
| UInt32 | Yes | OTHER | java.lang.Long | OTHER | com.clickhouse.data.value.UnsignedInteger |
| UInt64 | Yes | OTHER | java.math.BigInteger | OTHER | com.clickhouse.data.value.UnsignedLong |
| UInt128 | No | OTHER | java.math.BigInteger | OTHER | java.math.BigInteger |
| UInt256 | No | OTHER | java.math.BigInteger | OTHER | java.math.BigInteger |
| Float32 | No | REAL | java.lang.Float | REAL | java.lang.Float |
| Float64 | No | DOUBLE | java.lang.Double | DOUBLE | java.lang.Double |
| Decimal32 | No | DECIMAL | java.math.BigDecimal | DECIMAL | java.math.BigDecimal |
| Decimal64 | No | DECIMAL | java.math.BigDecimal | DECIMAL | java.math.BigDecimal |
| Decimal128 | No | DECIMAL | java.math.BigDecimal | DECIMAL | java.math.BigDecimal |
| Decimal256 | No | DECIMAL | java.math.BigDecimal | DECIMAL | java.math.BigDecimal |
| Bool | No | BOOLEAN | java.lang.Boolean | BOOLEAN | java.lang.Boolean |
- The biggest differences is that unsigned types are mapped to java types for better portability.
String Types
| ClickHouse Type | Changed | JDBC Type (V2) | Java Class (V2) | JDBC Type (V1) | Java Class (V1) |
|---|---|---|---|---|---|
| String | No | VARCHAR | java.lang.String | VARCHAR | java.lang.String |
| FixedString | No | VARCHAR | java.lang.String | VARCHAR | java.lang.String |
FixedStringis read as is in both versions. For exampleFixedString(10)for'John'will be read as'John\0\0\0\0\0\0\0\0\0'.
Date/Time Types
| ClickHouse Type | Changed | JDBC Type (V2) | Java Class (V2) | JDBC Type (V1) | Java Class (V1) |
|---|---|---|---|---|---|
| Date | Yes | DATE | java.sql.Date | DATE | java.time.LocalDate |
| Date32 | Yes | DATE | java.sql.Date | DATE | java.time.LocalDate |
| DateTime | Yes | TIMESTAMP | java.sql.Timestamp | TIMESTAMP | java.time.OffsetDateTime |
| DateTime64 | Yes | TIMESTAMP | java.sql.Timestamp | TIMESTAMP | java.time.OffsetDateTime |
| Time | No | TIME | java.sql.Time | new type/not supported | new type/not supported |
| Time64 | No | TIME | java.sql.Time | new type/not supported | new type/not supported |
TimeandTime64are supported in V2 only as new types.DateTimeandDateTime64are mapped tojava.sql.Timestampfor better compatibility with JDBC.
Enum Types
| ClickHouse Type | Changed | JDBC Type (V2) | Java Class (V2) | JDBC Type (V1) | Java Class (V1) |
|---|---|---|---|---|---|
| Enum | No | VARCHAR | java.lang.String | OTHER | java.lang.String |
| Enum8 | No | VARCHAR | java.lang.String | OTHER | java.lang.String |
| Enum16 | No | VARCHAR | java.lang.String | OTHER | java.lang.String |
Collection Types
| ClickHouse Type | Changed | JDBC Type (V2) | Java Class (V2) | JDBC Type (V1) | Java Class (V1) |
|---|---|---|---|---|---|
| Array | Yes | ARRAY | java.sql.Array | ARRAY | Object[] or array of primitive types |
| Tuple | Yes | OTHER | Object[] | STRUCT | java.sql.Struct |
| Map | Yes | JAVA_OBJECT | java.util.Map | STRUCT | java.util.Map |
- In V2
Arrayis mapped tojava.sql.Arrayby default to be compatible with JDBC. This is also done to give more information about returned array value. Useful for type inference. - In V2
ArrayimplementsgetResultSet()method to returnjava.sql.ResultSetwith the same content as the original array. - V1 uses
STRUCTforMapbut returnsjava.util.Mapobject always. V2 fixes this by mappingMaptoJAVA_OBJECT. BesidesSTRUCTis invalid forMapbecause it doesn't have named columns. - V1 uses
STRUCTforTuplebut returnsList<Object>object always. V2 fixes this by mappingTupletoOTHERand returnsObject[]because usingListis not valid as different types can be present.
Geo Types
| ClickHouse Type | Changed | JDBC Type (V2) | Java Class (V2) | JDBC Type (V1) | Java Class (V1) |
|---|---|---|---|---|---|
| Point | No | OTHER | double[] | OTHER | double[] |
| Ring | No | OTHER | double[][] | OTHER | double[][] |
| Polygon | No | OTHER | double[][][] | OTHER | double[][][] |
| MultiPolygon | No | OTHER | double[][][][] | OTHER | double[][][][] |
Nullable and LowCardinality Types
NullableandLowCardinalityare special types that wrap other types.- No changes are made to these types in V2.
Special Types
| ClickHouse Type | Changed | JDBC Type (V2) | Java Class (V2) | JDBC Type (V1) | Java Class (V1) |
|---|---|---|---|---|---|
| JSON | Yes | OTHER | java.lang.String | not supported | not supported |
| AggregateFunction | No | OTHER | (binary representation) | OTHER | (binary representation) |
| SimpleAggregateFunction | No | (wrapped type) | (wrapped class) | (wrapped type) | (wrapped class) |
| UUID | No | OTHER | java.util.UUID | VARCHAR | java.util.UUID |
| IPv4 | No | OTHER | java.net.Inet4Address | VARCHAR | java.net.Inet4Address |
| IPv6 | No | OTHER | java.net.Inet6Address | VARCHAR | java.net.Inet6Address |
| Dynamic | Yes | OTHER | java.Object | not supported | not supported |
| Variant | Yes | OTHER | java.Object | not supported | not supported |
- V1 uses
VARCHARforUUIDbut returnsjava.util.UUIDobject always. V2 fixes this by mappingUUIDtoOTHERand returnsjava.util.UUIDobject. - V1 uses
VARCHARforIPv4andIPv6but returnsjava.net.Inet4Addressandjava.net.Inet6Addressobjects always. V2 fixes this by mappingIPv4andIPv6toOTHERand returnsjava.net.Inet4Addressandjava.net.Inet6Addressobjects. DynamicandVariantare new types in V2. Not supported in V1.JSONis based onDynamictype. Therefore it is supported only in V2.