Apache Arrow ADBC docs Β· Tools & Integrations πŸš€

adbcBridge is documented upstream as the way to reach a database over ADBC when it has an ODBC driver but no native ADBC one.

Integrated in omniload since 2026-09-17, as its fourth SQL backend, shipping in v0.17.0.

Every ODBC driver, an Arrow driver.

adbcBridge is one plain-C shared library that turns whatever ODBC driver is on your machine into an ADBC driver β€” columnar Arrow batches out, bulk ingest in, from Python, Rust, Go, Java, C# and R. No per-database driver to write, no rows to convert by hand.

ODBC (Open Database Connectivity) is the decades-old C API almost every database ships a driver for; ADBC (Arrow Database Connectivity) is the newer C API whose result sets are Apache Arrow columnar batches instead of row-at-a-time buffers. adbcBridge is the piece in between.

Who it is for
  • You need Arrow-native access to a database that has no native ADBC driver, and you would rather not hand-roll ODBC-to-Arrow conversion.
  • You already have ODBC drivers installed and configured, and want every language's ADBC client to use them.
  • You are building a data tool and want one code path that reaches hundreds of databases instead of one integration per vendor.

Where a database already has a first-class native ADBC driver (PostgreSQL, SQLite, DuckDB, and others), adbcBridge can hand the whole connection over to it: native delegation.

A steel bridge at dusk over still water; streams of data cross it as tall columns of pale light, becoming ordered on the far bank, where one lamp burns

Rows on the near bank, columns on the far one. Nothing is lost on the way across.

What it is

The long tail of databases has an ODBC driver. Now it has an Arrow one.

Native ADBC drivers exist for a handful of databases. The other few hundred β€” Db2, Oracle, Informix, Vertica, Firebird, Access, every warehouse behind a PostgreSQL or MySQL wire β€” ship an ODBC driver and nothing else. adbcBridge sits between the ADBC driver manager and that ODBC driver, and does the columnar work once, in C, for all of them.

Where a native ADBC driver is installed (PostgreSQL, SQLite, DuckDB), the same install hands the connection to it, so you get native speed without changing a line.

Python / R / Go / Rust / Java / C#
        β”‚  ADBC driver manager
        β–Ό
 libadbc_driver_odbc.so   ← adbcBridge
        β”‚  ODBC API (unixODBC / iODBC / Windows DM)
        β–Ό
 Db2 Β· Oracle Β· SQL Server Β· Vertica Β· Informix Β·
 Access Β· Snowflake Β· Redshift Β· SQLite Β· anything
 with an ODBC driver
The numbers

Three figures, each with its conditions attached.

Measured on four ordinary machines, never idle:

  • Linux laptop β€” Linux Mint 22.3, Core i9-13900HK, 14 cores, 31 GiB, unixODBC 2.3.12; the 53-database fleet on the same box β€” Docker containers and local files, Db2 for i alone on a public host β€”, ~23 GiB of other work resident.
  • Apple M4 Max β€” 16 cores, 64 GB, load 2.4–10.5 during runs, some servers under amd64 emulation.
  • Windows 11 laptop, Core i9-13900HK β€” 14 cores, 32 GB, Docker Desktop on WSL2, up to eight benchmark runs and ~30 idle containers at once; the full 46-entry re-measure.
  • Windows 11 laptop, Core i7-8550U β€” 4 cores, 7.7 GB, 26% run-to-run variance; the first campaign. Both Windows builds without prefetch or fan-out.

Cross-machine numbers are not comparable; each benchmark file opens with its host state.

53 Β· 45 Β· 48Linux 53 Β· macOS 45 Β· Windows 48 databases verified by one workload β€” types, NULLs, Unicode in parameters and in statement text, bulk ingest, batched reads, catalog, error mapping β€” with a read-only variant for the entries whose driver or server accepts no writes. Linux is the reference host; all three campaigns are closed, and every cell that is not a pass names its reason.
1.2–1.5Γ—faster than the native PostgreSQL ADBC driver on a 1,000,000-row read, by splitting the query across eight connections β€” on the Linux reference host, quiet. On the same host busy it is 0.97Γ—; on an M4 Max, where libpq alone streams 6.4 M rows/s, it is 0.60Γ—. Bulk ingest does not beat native anywhere (0.50–1.02Γ—) and cannot over ODBC: an INSERT writes twice the WAL of a COPY.
5 Γ— 53Linux 261 of 265 cells Β· macOS 215 of 225 Β· Windows 219 of 240 β€” Python, Rust, C#, Java and Go, each measured against the same binary, every empty cell explained with the exact error. On YDB all five languages land within 1,597–1,742 rows/s of each other; that agreement, not any one number, is the point.
Database (A–Z)LinuxmacOS arm64Windows x64
βœ“53βœ“45⊘7⊟1βœ“48βœ•3⊘2

53 databases, one workload, three operating systems: Linux 53 pass; macOS 45 pass, 7 without a vendor driver for the OS, 1 whose server cannot run on that machine; Windows 48 pass, 3 recorded with the driver-side reason, 2 without a vendor driver. Every row below deep-links to its matrix entry.

Show all 53 rows
Database (A–Z)LinuxmacOS arm64Windows x64
Actian Ingresβœ“βŠ˜βœ•
Altibaseβœ“βŠ˜βŠ˜
Apache Cloudberryβœ“βœ“βœ“
Apache Dorisβœ“βœ“βœ“
Apache Igniteβœ“βŠ˜βœ“
ArcadeDBβœ“βœ“βœ“
Arrow Flight SQL (sqlflite)βœ“βœ“βœ“
Azure SQL Edgeβœ“βœ“βœ“
Citusβœ“βœ“βœ“
ClickHouseβœ“βœ“βœ“
CockroachDBβœ“βœ“βœ“
CrateDBβœ“βœ“βœ“
Databendβœ“βœ“βœ“
Doltβœ“βœ“βœ“
Dremioβœ“βœ“βœ“
DuckDBβœ“βœ“βœ“
Exasolβœ“βœ“βœ“
Firebirdβœ“βŠ˜βœ“
Google Spanner (emulator)βœ“βœ“βœ“
GreptimeDBβœ“βœ“βœ“
IBM Db2βœ“βœ“βœ“
IBM Db2 for iβœ“βœ“βŠ˜
IBM Informixβœ“βœ“βœ“
InfluxDB 3βœ“βœ“βœ“
Kineticaβœ“βŠ˜βœ•
MariaDBβœ“βœ“βœ“
MariaDB ColumnStoreβœ“βœ“βœ“
Materializeβœ“βœ“βœ“
MatrixOneβœ“βœ“βœ“
Microsoft Accessβœ“βœ“βœ“
MonetDBβœ“βœ“βœ“
MongoDB BI Connectorβœ“βœ“βœ“
MySQLβœ“βœ“βœ“
OceanBaseβœ“βœ“βœ“
openGaussβœ“βŠŸβœ“
OpenLink Virtuosoβœ“βœ“βœ“
OpenSearchβœ“βŠ˜βœ“
Oracleβœ“βœ“βœ“
Percona Serverβœ“βœ“βœ“
PostgreSQLβœ“βœ“βœ“
QuestDBβœ“βœ“βœ“
RisingWaveβœ“βœ“βœ“
SAP HANAβœ“βœ“βœ“
SingleStoreβœ“βœ“βœ“
SQL Serverβœ“βœ“βœ“
SQLiteβœ“βœ“βœ“
StarRocksβœ“βœ“βœ“
TDengineβœ“βœ“βœ•
TiDBβœ“βœ“βœ“
TimescaleDBβœ“βœ“βœ“
Verticaβœ“βŠ˜βœ“
YDBβœ“βœ“βœ“
YugabyteDBβœ“βœ“βœ“
  • βœ“passes the full compat workload
  • βœ•fails β€” hover the cell for the error, or open the row in the matrix
  • ⊘the vendor ships no driver for this OS
  • ⊟the server cannot run on this machine
  • Β·not attempted β€” hover for why, or open the row in the matrix

Every cell is a recorded fact from docs/COMPATIBILITY.md; all three columns are closed; every non-pass names its reason.

Method (Linux and macOS): the PostgreSQL ratio is the mean of three interleaved runs, a fresh process per timed run, sides alternated so load drift lands on both, every read checksum-compared against a reference; per-database and per-language rates are the median of three. The Windows column is single samples under contention, read as floors. Full tables, spreads and the host's load average for each: bench/. Full benchmark tables.

How it works

Block cursors in, Arrow buffers out, and a few things only this driver does.

Reads

Columns are bound once with SQLBindCol into rowsets of up to 8 MiB and copied into Arrow buffers column-at-a-time; UTF-16 becomes UTF-8, decimals become decimal128, longs are chunked through SQLGetData. A column a driver describes as "unbounded" is bound at 2 KiB and re-read only when a value overflows, so one wide column no longer collapses the whole read to a row at a time.

Partitioned reads

AdbcStatementExecutePartitions splits one query into K slices β€” by ctid on a PostgreSQL heap, by key range on a leading primary-key column anywhere else, by yb_hash_code() on YugabyteDB β€” and reads them on K connections. The key column's NOT NULL comes from the catalog, never from "it is a primary key", so no row can fall between slices.

Writes

Bulk ingest binds parameter arrays where the driver honours them, and otherwise batches the stream into multi-row INSERT … VALUES, Oracle's INSERT ALL, or Firebird's UNION ALL SELECT β€” each form probed once per connection, and only after the plain form is refused. On PostgreSQL it sends INSERT … SELECT FROM unnest(arrays), 10,000 rows a statement, across up to 64 connections.

Delegation

adbc.odbc.delegate=auto looks for a native ADBC driver for the database behind the connection string and hands the whole driver over when one is found. The connection you configured is the connection you get; nothing is re-parsed.

Get it

Download the release, or build from source.

v0.1.3 carries the driver library for Linux x86_64 and aarch64, macOS arm64 and Windows x64, a Python wheel for each, the source distribution, the Rust crate, the NuGet package and the Maven jar with its sources and javadoc jars β€” fourteen files, every one built and tested by the release workflow from the tagged commit, with a SHA256SUMS to check them against and the release key's signature of it (SHA256SUMS.asc). Releases after v0.1.0 add a build-provenance attestation per asset (gh attestation verify) and an SPDX SBOM; the security policy, the support window and the private reporting channel are in Security and verification.

Linux verified

sudo apt install unixodbc-dev cmake
git clone https://github.com/singhpratech/adbcbridge
cd adbcbridge
./install.sh          # into ~/.local, no root
pip install adbc-driver-manager pyarrow

The reference host: Linux Mint 22.3 (Ubuntu 24.04 base), unixODBC 2.3.12, the 53-database matrix on the same machine (Docker containers and local files; Db2 for i alone on a public IBM i host over TLS). install.sh builds the library into ~/.local and writes the driver manifest the ADBC driver manager already searches, so driver="odbc" resolves with nothing else set. Step by step: docs/getting-started/install-linux.md.

macOS verified

brew install unixodbc cmake sqliteodbc
cmake -S . -B build \
  -DCMAKE_PREFIX_PATH="$(brew --prefix unixodbc)"
cmake --build build

Apple M4 Max, macOS 26.5, arm64: 45 of 53 databases pass the compat workload, Oracle, Db2 and Informix on the vendors' arm64 drivers among them; vendor drivers that ship only iODBC-width builds run through a bridge built against iODBC. SQLite reads 2.3 M rows/s, DuckDB 4.2 M. The eight entries without a macOS driver or a runnable server are recorded with the reason. Details: bench/BENCHMARKS-macos.md, docs/getting-started/install-macos.md.

Windows verified

cmake -S . -B build
cmake --build build --config Release
# -> build\Release\libadbc_driver_odbc.dll

Windows 11 x64, MSVC 2022, the OS's own driver manager: 48 of 53 databases pass the complete workload under Docker Desktop on WSL2; the five remaining cells are recorded one by one: three driver-side failures, two databases whose vendor ships no Windows driver. CI builds and tests 64- and 32-bit Windows on every push to main and every pull request. Five Windows-only driver quirks are handled in the bridge β€” Firebird's driver name, Informix parameters, Arrow Flight SQL's text path (read as binary, 1.8Γ— faster), Apache Ignite's narrow UTF-8 route and OpenLink Virtuoso's 4-byte indicator stride. The prefetch pipeline and parallel ingest are compiled out on Windows until a Win32 thread shim lands (on the roadmap). Details: bench/BENCHMARKS-windows.md, docs/getting-started/install-windows.md.

First query

The shortest working program, from Your first query: connect through the bridge by name, run a query, get a pyarrow.Table.

import adbc_driver_manager.dbapi as dbapi
import pyarrow as pa

# 1. Connect through the bridge to a SQLite file. `driver="odbc"` resolves the
#    bridge by name from the manifest an install wrote; `uri` is an ODBC
#    connection string.
conn = dbapi.connect(
    driver="odbc",
    db_kwargs={"uri": "Driver=SQLite3;Database=/tmp/first.db;"},
)

# 2. Run a query and get the result as a pyarrow.Table.
with conn.cursor() as cur:
    cur.execute("SELECT 42 AS answer, 'hello' AS greeting")
    table = cur.fetch_arrow_table()      # pyarrow.Table
    print(table)

The same program in Rust, C#, Java, Go and C, plus parameters and bulk ingest: Your first query.

Languages

One binary, loaded by name from five languages, and R.

Each binding dlopens the same libadbc_driver_odbc.so and calls AdbcDriverInit. The numbers are PostgreSQL 16, 10,000 rows ingested in one transaction and 100,000 read back into that language's own Arrow batches, adbc.odbc.delegate=never so every row really travels over ODBC.

LanguageADBC bindingingest rows/sfetch rows/sName the driver
Pythonadbc_driver_manager.dbapi278,0751,892,520dbapi.connect(driver="odbc", db_kwargs={"uri": "Driver=SQLite3;Database=my.db;"})
Rustadbc_driver_manager crate482,8222,078,465ManagedDriver::load_from_name("odbc", None, AdbcVersion::V110, LOAD_FLAG_DEFAULT, None)
Gogo/adbc/drivermgr395,9411,987,447drivermgr.Driver{}.NewDatabase(map[string]string{"driver": "odbc", "uri": ...})
Javaadbc-driver-jni450,0721,617,704JniDriver.PARAM_DRIVER.set(params, "odbc")
C#Apache.Arrow.Adbc401,6941,937,816AdbcDriverManager.FindLoadDriver("odbc")
Radbcdrivermanagerβ€”β€”adbc_database_init(adbc_driver("/path/to/libadbc_driver_odbc.so", entrypoint = "AdbcDriverInit"), uri = ...)

Five packages, one library inside each.

Each package finds the library the same way β€” an explicit override (ADBC_ODBC_DRIVER everywhere, ADBCBRIDGE_LIBRARY too in Rust, C#, Java and Go), the copy shipped inside the package, the ADBC driver manifest, the usual install directories β€” and Rust, C#, Java and Go list every place they looked in the error. All five are built and tested in the repository and attached to every release β€” v0.1.0 was the first β€” and published on PyPI, crates.io, NuGet, Maven Central and as a Go module.

Pythonwheel
pip install adbcbridge

On PyPI, and on the release page. The library rides inside a py3-none-<platform> wheel for Linux x86_64 and aarch64, macOS arm64 and Windows x64 β€” one wheel for every Python version, no extension module.

adbcbridge.connect(uri="Driver=SQLite3;Database=my.db;")
Rustcrate
cargo add adbcbridge

The crate carries the C sources; cargo build compiles the driver on the spot (unixODBC headers needed), and a test keeps the bundled copy in sync with the repository.

let driver = adbcbridge::load()?;
C#NuGet
dotnet add package AdbcBridge

netstandard2.0 and net8.0; the library ships as runtimes/<rid>/native assets and loads through Apache.Arrow.Adbc.

Driver.Connect("Driver=SQLite3;Database=my.db;")
JavaMaven Central
org.adbcbridge:adbcbridge:0.1.3

Over adbc-driver-jni; the natives live inside the jar and are extracted once per JVM. Sources and javadoc jars included.

AdbcBridge.open(allocator, "Driver=SQLite3;Database=my.db;", Map.of())
Gomodule
go get github.com/singhpratech/adbcbridge/go

Over drivermgr (cgo). A Go module cannot carry a prebuilt library, so it comes from install.sh, a release binary or the manifest β€” or a build tag embeds one.

adbcbridge.Open(ctx, alloc, "Driver=SQLite3;Database=my.db;", nil)

R has a smoke test but no benchmark yet. The 53-database version of this table, per language, is bench/LANGUAGE_BENCHMARKS.md. Note that Java here is Java as a client of this ODBC driver (through adbc-driver-jni); the JDBC bridge on the roadmap β€” reaching JDBC-only databases from any language β€” is a separate, future library.

Pipelines and tools

Not a database: the loaders and movers that drive it.

adbcBridge is an ADBC driver, so anything that speaks ADBC can use it without a connector of its own. Three that have been tried, with the measurements written up.

omniload integrated
omniload ingest --sql-backend adbcbridge

A fourth SQL backend for the dlt-based loader, built on its maintainer's request: SQLAlchemy reflects the table, the database's ODBC driver reads it, Arrow batches come out, and incremental append and merge work as before. Tested in omniload's own harness on PostgreSQL, CrateDB and SQL Server, and inside its container image. How it was built and tested.

Merged and released on 2026-09-17: panodata/omniload#362, reviewed by both maintainers, shipped the same day in omniload v0.17.0.

β€œPerfect. Thank you so much!” β€œYour contribution was included in v0.17.0, thank you again.”Andreas Motl, omniload maintainer, on the pull request
dltworks today
register_table_loader_backend("adbcbridge", …)

Two shapes, no change to dlt: a plain resource yielding record batches from adbcbridge.connect(), or a registered sql_table backend so incremental loading works as usual. One million PostgreSQL rows into DuckDB in 2.1 s, and the backend that keeps a timestamp(0) column at second precision. the measurements.

Fletchcustom driver
--source-driver <libadbc_driver_odbc>

A Go command line that moves tables between databases over ADBC. adbcBridge plugs in as a custom driver, with the ODBC connection string as the source URI: one million rows from PostgreSQL into SQLite in 1.3 s, and 200,000 rows out of CrateDB, where the native PostgreSQL driver stops at its first COPY, in 0.23 s. the measurements.

Verified, database by database

53 databases, 24 ODBC drivers, one workload.

"Reachable" would be the few hundred sources with an ODBC driver. These are the ones that passed the full compat workload against a real server or file, grouped by the driver that fronts them β€” because the driver, not the database, is where the surprises live.

PostgreSQL wire (psqlodbc)

PostgreSQL Β· CockroachDB Β· YugabyteDB Β· TimescaleDB Β· Citus Β· Apache Cloudberry Β· openGauss Β· CrateDB Β· QuestDB Β· RisingWave Β· Materialize Β· YDB Β· Google Spanner (PGAdapter) Β· ArcadeDB

MySQL wire (Connector/ODBC, MariaDB Connector)

MySQL Β· MariaDB Β· MariaDB ColumnStore Β· TiDB Β· Percona Server Β· Dolt Β· Databend Β· Apache Doris Β· StarRocks Β· OceanBase Β· MatrixOne Β· GreptimeDB Β· MongoDB BI Connector Β· SingleStore

Their own drivers

SQLite Β· DuckDB Β· SQL Server Β· Azure SQL Edge Β· Oracle Β· IBM Db2 Β· IBM Informix Β· MonetDB Β· Firebird Β· OpenLink Virtuoso Β· Vertica Β· Apache Ignite Β· TDengine Β· OpenSearch Β· ClickHouse Β· Microsoft Access Β· SAP HANA Β· Exasol Β· Altibase Β· Kinetica Β· Actian Ingres Β· IBM Db2 for i

Arrow Flight SQL ODBC

sqlflite Β· Dremio Β· InfluxDB 3

Explore the interactive matrix β€” every cell, every quirk β†’One page per database β†’

Stated rather than hidden. Three of those drivers were built from source for Linux here (Ignite, OpenSearch, TDengine); Ignite and OpenSearch publish no Linux build at all. Oracle's driver segfaults if a rowset is resized on an open LOB cursor, so the reader never does. Firebird's driver was silently writing NULLs over 64-bit integers after the first NULL, and our own DDL was giving it BLOBs for strings, which it reads one row at a time (fixed: VARCHAR, ~35Γ— faster to read back β€” 8,256 to 289k–295k rows/s). Db2's free driver has 32-bit SQLLEN. MySQL's driver cannot be loaded after pyarrow is imported, and unixODBC reports that as "file not found". All of it is in COMPATIBILITY.md and TROUBLESHOOTING.md.

Upstream

What the sweep found in other projects, reported with a reproduction.

Driving 53 databases through one driver on three operating systems turns up defects that belong upstream. Each goes back to its project with a reproduction that needs nothing from this one.

unixODBCanswered

The driver manager overwrites its own stack and heap, and the process aborts, on the first SQL error from a driver whose SQLWCHAR is 4 bytes. Found on macOS with two vendor drivers; reproduced on Linux with a 40-line fake driver; affects 2.3.12 and 2.3.14.

lurcher/unixODBC#239

Affects: OpenLink Virtuoso, sqlflite, Dremio, InfluxDB 3 (the two macOS drivers built to the 4-byte width) Β· Read the note

OpenLink Virtuoso2 fix PRs open

The macOS driver is built to iODBC's 4-byte SQLWCHAR and nothing says so β€” through unixODBC every application dies on its first SQL error. On Linux the ANSI driver treats SQL_C_WCHAR as wchar_t on both sides, stores and reads SQL_C_SBIGINT as 0, steps date parameter arrays by ColumnSize, and aborts on any Charset= but the literal UTF-8 β€” four programs. Two of them are now sent as fixes (2026-09-18): the abort turned out to be a double free of the charset name, and the date stride comes from the ODBC 3 type names missing from one size switch.

openlink/virtuoso-opensource#1469 Β· #1470 Β· #1471 Β· #1472 Β· #1473 Β· PR #1477 Β· PR #1478

Affects: OpenLink Virtuoso Β· Read the note

Arrow Flight SQL ODBCopen

The Apple Silicon build has the same undocumented width, a logger that breaks SQLAllocHandle when enabled, and docs that contradict each other on Apple Silicon support.

dremio/warpdrive#16

Affects: sqlflite, Dremio, InfluxDB 3 Β· Read the note

Firebird ODBC3 fixes in review

Column-wise parameter arrays step fixed-length C types at the BufferLength stride, so every row receives row 1's values; a SQL_BIGINT parameter once bound as SQL_C_DEFAULT keeps writing NULL; SQLPrepare discards the rows-fetched pointer set before it. Three plain-ODBC programs, reproduced on 3.0.1 and 3.5.0-rc1.

firebird-odbc-driver#299 Β· #300 Β· #301

Affects: Firebird Β· Read the note

taos-odbc (TDengine)open

Timestamp columns cannot be bound (SQLGetData converts them, SQLBindCol does not), timestamp parameters and most BOOL parameter types are refused, and a DECIMAL column fails the whole SELECT β€” each with the driver's own diagnostic and a program.

taosdata/taos-connector-odbc#63

Affects: TDengine Β· Read the note

Apache Dorisfix in review

Server-side prepare refuses a string parameter sent with MySQL type BLOB β€” what MySQL Connector/ODBC sends for every SQL_C_WCHAR parameter β€” so Unicode ODBC clients cannot insert through prepared statements: a NullPointerException on 2.1.0, a clean refusal on 4.1.3.

apache/doris#67301

Affects: Apache Doris Β· Read the note

clickhouse-odbc1 fixed Β· fix PR open

A bound SQL_NULL_DATA is ignored whenever a value buffer is attached, and parameter arrays stop after set 1 β€” the driver's one-set-per-SQLMoreResults protocol answers SQL_NO_DATA on the first call. Two programs; the affected-row count thread from 2021 re-measured on 1.5.5. The ignored SQL_NULL_DATA is now sent as a fix (2026-09-18): two lines in the driver decided nullability from the value pointer alone.

ClickHouse/clickhouse-odbc#582 Β· #335 Β· PR #586

Affects: ClickHouse Β· Read the note

psqlodbc2 fixed

An out-of-range int8 is narrowed to SQL_C_SLONG silently β€” 9223372036854775807 reads as βˆ’1 under SQL_SUCCESS; and with Protocol=7.4-0 a statement freed inside a transaction still sends SAVEPOINT;DEALLOCATE;RELEASE, whose failure on a server without savepoints is swallowed while COMMIT reports success. Wire captures included.

postgresql-interfaces/psqlodbc#207 Β· #208

Affects: PostgreSQL, QuestDB, Materialize Β· Read the note

QuestDB2 fixes in review

A BINARY column in a simple-query result is sent with format code 1 where PostgreSQL always sends text, so libpq and psqlodbc both cut the value at its first 0x00; and DEALLOCATE ALL throws a NullPointerException even on a fresh connection.

questdb/questdb#7566 Β· #7567

Affects: QuestDB Β· Read the note

CrateDBfixed

A multi-statement simple query returns every CommandComplete tagged with the whole string's leading text β€” BEGIN;INSERT 0, BEGIN;INSERT 1 β€” so tag-parsing clients get no row count inside a transaction. Side by side with PostgreSQL at the wire level.

crate/crate#20085

Affects: CrateDB Β· Read the note

OpenSearch SQL ODBCopen

Any character value converted to SQL_C_TYPE_TIMESTAMP comes back as today's date under SQL_SUCCESS; and SQLErrorW never clears the connection error, so unixODBC loops forever on any failed connect. Both traced to the source line.

opensearch-project/sql-odbc#101 Β· #102

Affects: OpenSearch Β· Read the note

Apache Ignite ODBCfix PR open

Column-wise parameter arrays test row 0's NULL indicator for every row: a NULL below it stores an empty string, or segfaults the client on a binary column when WriteInt8Array is handed βˆ’1 as a length. The offending lines in parameter.cpp, with a fix.

apache/ignite#13537

Affects: Apache Ignite Β· Read the note

MySQL Connector/ODBCopen

SQLDescribeCol describes a DATETIME(6) as 19 characters with 0 digits while returning 26; and a MySQL-wire server reporting a zero charset width makes SHOW VARIABLES kill the client with SIGFPE in get_column_size().

mysql/mysql-connector-odbc#20 Β· #21

Affects: MySQL, SingleStore, MatrixOne Β· Read the note

Materializefixed on main

DEALLOCATE "Name" keeps the quotes in its lookup, so a statement prepared at the protocol level with a mixed-case name β€” psqlodbc's _PLAN0x… β€” can never be released, and inside a transaction the failure aborts it. The server half of the psqlodbc row-loss pair; filed with a psycopg side-by-side against PostgreSQL 16, which releases it.

MaterializeInc/materialize#38605

Affects: Materialize Β· Read the note

ArcadeDB4 fixed

BEGIN, COMMIT and the savepoint statements were answered with a zero-field RowDescription before the command tag, so libpq reported PGRES_TUPLES_OK and the Arrow PostgreSQL ADBC driver stopped at Failed to begin transaction with autocommit off. Sent as a fix with a wire-level test and merged by the maintainer the same day (2026-09-17), who re-ran the module's integration suite and extended the fix to prefixed statements such as {sql}BEGIN.

Written up by ArcadeDB on 2026-09-21: ArcadeDB in the Apache Arrow Ecosystem, Through Its PostgreSQL Wire Protocol β€” their own account of all four findings, the two Arrow routes and the language benchmark.

ArcadeData/arcadedb#7815

Affects: ArcadeDB Β· Read the note

DuckDB ODBC2 fixes merged

SQLGetInfo(SQL_DBMS_VER) segfaults under unixODBC: inside the driver the call to SQLAllocHandle binds to the driver manager, fails, and the error path frees an uninitialized handle. Linked directly it answers SQL_SUCCESS with an empty string, read into one buffer and returned from another. Sent as a fix rather than a report, and merged by a DuckDB maintainer the same day (2026-09-17): the version now comes straight from the engine, with a test against pragma_version(). A second fix: a parameter array stored set 0's value in every row for every fixed-length type under SQL_SUCCESS; each set now gets its own value, with a test. Merged the same day too.

duckdb/duckdb-odbc#523 Β· #524

Affects: DuckDB Β· Read the note

SingleStore Connector/ODBC2 fixed

SQLGetTypeInfo fails with 42S22 Unknown column 'json' whenever sql_mode contains ANSI_QUOTES: the type-info result set is built from a SQL template with double-quoted string literals, which that mode turns into identifiers. And SQLColumns with a NULL catalog name segfaults the client on a connection opened without Database= β€” strdup(NULL) on the client library's empty current-database field. Both reproduced through pyodbc alone, with the source lines named.

memsql/singlestore-odbc-connector#45 Β· #46 Β· fixes: #48 Β· #47

Affects: SingleStore Β· Read the note

Twenty-seven reports across fifteen projects so far; forty more findings β€” connector versions, driver bindings, server behaviours, container images, and one (MatrixOne's BIT arrays) fixed on their main before it could be filed β€” are documented with their first error and conditions in docs/UPSTREAM.md.

Docs

Everything written down, in the order you will need it.

Open the documentation

The documentation follows one path β€” install the driver manager and a driver, run a first query, then go deep in your language β€” and ends in a reference that names every option, every connection string and every driver quirk with the measured reason behind it. Every command is copy-paste ready; every limitation is stated where you would hit it.