← All databases

Database · PostgreSQL wire

RisingWave into Apache Arrow with ADBC

RisingWave 3.0, 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 (RisingWave, PostgreSQL wire 13.14) — compose bind-mount of risingwave.toml refused by Docker Desktop for this account; run with the README's docker run and the toml under /private/tmp

Windows x64✓ pass

PASS (RisingWave 3.0.3, PostgreSQL wire 13.14; the compose bind-mount of risingwave.toml works as-is from PowerShell)

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=14566;Database=dev;Uid=root;UseServerSidePrepare=0;

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=14566;Database=dev;Uid=root;UseServerSidePrepare=0;")
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 RisingWave 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

no adbc.odbc.* quirks, but the entry sets psqlodbc's UseServerSidePrepare=0: psqlodbc names every server-side statement _PLAN0x<statement-handle address> and RisingWave keeps the name after the handle is freed, so the next SQLPrepare under a reused name fails XX000 ... Duplicated statement name -- which the ordinary allocate/prepare/execute/free loop hits on its second query, with or without parameters (concurrently open handles get distinct names and all succeed, re-executing a prepared handle is fine, SQLExecDirect never collides); version() names RisingWave, so the PostgreSQL array-ingest form stays off (verified); server side: RisingWave's parser takes no length, precision or scale on a column type -- VARCHAR(50)/TIMESTAMP(6) are parser errors and NUMERIC(10,3) an unsupported type, so VARCHAR and NUMERIC are declared unqualified; FLOAT(p) is the one modifier it does take, and honours (1-24 gives real, 25-53 double precision) -- and a write reaches a scan only at the next barrier (the default 1 s interval here; a COMMIT does not bring it forward), so reads follow FLUSH, which forces a barrier straight away (tens of ms), or SET RW_IMPLICIT_FLUSH = true, which does that on every write; ingest 31.9k rows/s (35.3k with array binding), fetch 1.00M rows/s

Native ADBC driver, compared

RisingWave 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 connectINVALID_ARGUMENT: [libpq] Failed to execute query 'SELECT oid, typname, typreceive, typbasetype, typrelid, typ
adbcBridge over ODBC✓ all seven steps

Where the native driver stops it is by design of that driver, not a defect of RisingWave; the full table for all 28 wire-compatible databases, with each first error, is in the note.

Read next