CrateDB into Apache Arrow with ADBC
CrateDB 6.4, read and written through adbcBridge — the ADBC driver that loads the database's ODBC driver — verified on Linux, macOS arm64 and Windows x64. Everything below is the compatibility matrix's record for this row.
Status
PASS
PASS (CrateDB 6.4.3, PostgreSQL wire 14.0.0) — at 1f35a5c, after the entry accepted psqlodbc 18's decimal128(28, 3)
PASS (CrateDB 6.4.3, PostgreSQL wire 14.0.0; tzdata PyPI package required on Windows)
Driver and connection string
- ODBC driver
- psqlodbc 16 (PG wire)
- Wire
- PostgreSQL wire
- adbcBridge
- 0.1.1 (release)
The connection string the matrix used, as the connection strings reference records it (PostgreSQL wire); {drv} is the driver library or its name from odbcinst.ini, and the host, port and credentials are the test server's.
Driver={drv};Server=127.0.0.1;Port=15440;Database=doc;Uid=crate;
Python
import adbcbridge
# {drv}: the ODBC driver library (path), or its name from odbcinst.ini
conn = adbcbridge.connect(uri="Driver={drv};Server=127.0.0.1;Port=15440;Database=doc;Uid=crate;")
with conn.cursor() as cur:
cur.execute("SELECT * FROM my_table")
table = cur.fetch_arrow_table() # pyarrow.Table
Polars and pandas
import polars as pl, pandas as pd
df = pl.read_database("SELECT * FROM my_table", connection=conn) # Polars, Arrow-native
pdf = pd.read_sql("SELECT * FROM my_table", conn) # pandas 2.2+, ADBC connection
pip install adbcbridge brings the driver library; the CrateDB ODBC driver is installed the way its vendor documents, then named in Driver=. Rust, Go, C# and Java use the same connection string through their ADBC driver managers — see the docs.
What the matrix recorded
driver quirk handled: with autocommit off psqlodbc sends BEGIN;<statement> as one query string, and CrateDB tags every result of a multi-statement query with the leading text of the whole string (BEGIN;INSERT 1, where PostgreSQL sends BEGIN then INSERT 0 1), so SQLRowCount succeeds without writing its out-parameter for any write or DDL inside a transaction — the same driver and query string against stock PostgreSQL write the count (fixed generically in OdbcRowCount(), which now pre-fills *unknown* rather than *none*; reported upstream and fixed in CrateDB 6.4.4 by crate/crate#20088, the bridge handling stays for earlier versions); version() is CrateDB's own, so the PostgreSQL array-ingest form stays off (verified); server side: eventually consistent, so reads follow REFRESH TABLE; no binary or DATE column type; ingest 50.0k rows/s (45.6k with array binding; one multi-row INSERT per batch — row-at-a-time is ~0.9k rows/s because CrateDB fsyncs its translog once per statement, and psqlodbc sends a parameter array as separate single-row statements), fetch 726k rows/s
Native ADBC driver, compared
CrateDB speaks the PostgreSQL wire protocol, so Apache Arrow's native PostgreSQL ADBC driver (adbc-driver-postgresql 1.12.0) can be pointed at it too. On 2026-09-05 the same seven-step ADBC workload (connect, SELECT 1, DDL and inserts and a read, a 1,000-row adbc_ingest, table schema, catalog listing, read back) ran through both:
| Path | Result | First error |
|---|---|---|
| Native ADBC driver | fails at select1 | INVALID_ARGUMENT: [libpq] Failed to execute query: could not begin COPY: ERROR: line 1:6: no viable alternati |
| adbcBridge over ODBC | ✓ all seven steps |
Where the native driver stops it is by design of that driver, not a defect of CrateDB; the full table for all 28 wire-compatible databases, with each first error, is in the note.