JDBC 4.2 driver for QuestDB on top of the QuestDB Wire
Protocol (QWP) egress. The driver wraps org.questdb:questdb-client and
exposes a standard java.sql.Driver so QuestDB plugs into JDBC tooling
(DataGrip, DBeaver, Spring Data, JOOQ, JDBI, etc.) without going through the
Postgres-wire compatibility layer.
Status: alpha. The driver compiles, the unit suite is green, but it has not yet been exercised against a running QuestDB end-to-end. Expect rough edges. See the Known gaps section before adopting it for anything load-bearing.
QuestDB already ships a Postgres wire protocol implementation that any PostgreSQL JDBC driver can talk to. This driver exists for cases where:
- You want native QuestDB types (
SYMBOL,GEOHASH,LONG256,IPv4,TIMESTAMP_NS,DECIMAL64/128/256, arrays) without the Postgres-wire compatibility translations. - You want to take advantage of QWP's column-major streaming, zstd compression, multi-endpoint failover, and credit-based flow control.
- You want a smaller wire footprint than Postgres protocol on chatty workloads.
It is not a drop-in replacement for the Postgres wire protocol. SQL is the same; metadata, transactions, and tooling expectations are not.
<!-- Coordinates are not yet published to Maven Central.
Build locally with `mvn install` until the first release. -->
<dependency>
<groupId>org.questdb</groupId>
<artifactId>questdb-jdbc</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
String url = "jdbc:questdb://localhost:9000";
try (Connection conn = DriverManager.getConnection(url);
PreparedStatement ps = conn.prepareStatement(
"SELECT ts, sym, price FROM trades WHERE sym = $1 LIMIT 100")) {
ps.setString(1, "AAPL");
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.printf("%s %s %.4f%n",
rs.getTimestamp(1), rs.getString(2), rs.getDouble(3));
}
}
}DriverManager.getConnection auto-loads io.questdb.jdbc.QuestDBDriver via
the META-INF/services/java.sql.Driver SPI entry; no Class.forName call
is required on JDK 9+.
jdbc:questdb://host[:port][,host[:port]...][/path][?key=value&...]
jdbc:questdb:ws://... # explicit plain WebSocket
jdbc:questdb:wss://... # WebSocket over TLS
The default port is 9000 (QuestDB's HTTP / WebSocket port). The default
path is /read/v1.
URL query parameters and Properties entries pass straight through to
QwpQueryClient. Properties wins over the URL when both set the same
key. The most useful keys:
| Key | Meaning | Default |
|---|---|---|
path |
WebSocket endpoint | /read/v1 |
target |
any / primary / replica endpoint filter |
any |
failover |
Transparent failover on transport faults: on / off |
on |
username |
HTTP Basic auth username (paired with password) |
- |
password |
HTTP Basic auth password | - |
token |
OIDC bearer token | - |
auth |
Verbatim Authorization header value |
- |
client_id |
Sent as the X-QWP-Client-Id header |
- |
compression |
raw / zstd / auto |
raw |
compression_level |
zstd level [1, 22] | 3 |
max_batch_rows |
Per-batch row cap hint sent to the server | server-side |
tls_verify |
on / unsafe_off (only with wss) |
on |
tls_roots |
Path to a custom trust store (PKCS12 or JKS) | - |
tls_roots_password |
Trust store password | - |
Multiple endpoints separated by commas are walked in order at connect time and used as failover targets.
| QuestDB / QWP type | JDBC Types |
Java class returned |
|---|---|---|
BOOLEAN |
BOOLEAN |
Boolean |
BYTE |
TINYINT |
Byte |
SHORT |
SMALLINT |
Short |
CHAR |
CHAR |
Character |
INT |
INTEGER |
Integer |
LONG |
BIGINT |
Long |
FLOAT |
REAL |
Float |
DOUBLE |
DOUBLE |
Double |
STRING / VARCHAR |
VARCHAR |
String |
SYMBOL |
VARCHAR |
String |
DATE |
DATE |
java.sql.Date |
TIMESTAMP |
TIMESTAMP (us) |
java.sql.Timestamp |
TIMESTAMP_NS |
TIMESTAMP (ns) |
java.sql.Timestamp |
BINARY |
VARBINARY |
byte[] |
UUID |
OTHER |
java.util.UUID |
LONG256 |
OTHER |
hex String (0x...) |
GEOHASH |
OTHER |
base32 / binary String |
IPv4 |
OTHER |
dotted-quad String |
DECIMAL64/128/256 |
DECIMAL |
BigDecimal (server scale) |
DOUBLE_ARRAY |
ARRAY |
java.sql.Array of Double |
LONG_ARRAY |
ARRAY |
placeholder (see TODO) |
PreparedStatement setters cover the symmetric set: setBoolean,
setByte, setShort, setInt, setLong, setFloat, setDouble,
setBigDecimal (auto-picks DECIMAL64/128/256), setString,
setTimestamp, setDate, setTime, setObject(UUID). JDBC type codes
in setNull(idx, sqlType) are translated to the matching QWP wire type.
mvn clean package
mvn testJava 11+ and Maven 3 required. The QWP client jar is pulled from Maven Central; no local QuestDB checkout is needed for the build.
- Streaming
ResultSet: results are materialised into the heap up front. Large queries can OOM the client. Replacing the materialiser with a bounded blocking queue between the QWP I/O thread and the user thread is the obvious next step. LONG_ARRAYdecoding: client1.2.0only exposesgetDoubleArrayElements;LONG_ARRAYreturns a placeholder string until the upstream accessor lands.getTypeInfo: returns an empty result. Tools that introspect type metadata at connect time (DBeaver, IntelliJ Database) will fall back to defaults.getPrimaryKeys/getIndexInfo: empty. QuestDB has no primary keys; symbol-indexed columns could surface throughgetIndexInfobut that wiring is not done yet.PreparedStatement.getMetaData/ParameterMetaData: not implemented; QWP does not yet expose a server-side prepare/describe.Statement.setQueryTimeout: accepted but not enforced. Plumb a per-call scheduler that callscancel()on expiry.- Auto-generated keys,
CallableStatement, savepoints, client-driven transactions: intentionally unsupported. QuestDB has no row-id, no procedures, and QWP does not expose explicit transactions. - Integration tests: the suite covers URL parsing, type mapping,
ResultSetmechanics, and driver registration. End-to-end coverage against a running QuestDB is not yet wired.
Apache License 2.0. See LICENSE.txt.
- QuestDB -- the database
- java-questdb-client -- the Java client this driver builds on (ILP ingestion + QWP egress)
- c-questdb-client, go-questdb-client -- sister clients in C and Go