← All databases

Database · PostgreSQL wire

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

Linux✓ pass

PASS

macOS arm64✓ pass

PASS (CrateDB 6.4.3, PostgreSQL wire 14.0.0) — at 1f35a5c, after the entry accepted psqlodbc 18's decimal128(28, 3)

Windows x64✓ pass

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:

PathResultFirst error
Native ADBC driverfails at select1INVALID_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.

Read next