SingleStore into Apache Arrow with ADBC
SingleStore 9.1.1 (MySQL 5.7.32 wire), 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 (MySQL (via ODBC) 05.07.000032, @@memsql_version 9.1.1; MariaDB Connector/ODBC 3.2.9 built from source against unixODBC 2.3.12 — MySQL's own connector is iODBC-only on macOS; server amd64-emulated, singlestoredb-dev has no arm64 manifest; fetch ~55k rows/s, ingest ~116k rows/s warm)
PASS (MySQL (via ODBC) 5.7.32, @@memsql_version 9.1.1; MySQL Connector/ODBC 26.7.0 myodbc26w.dll, the entry verbatim with NO_SSPS=1 from the placeholder; singlestoredb-dev runs native amd64 under Docker Desktop, healthy in ~15 s; fetch 720–780k rows/s, ingest 61k rows/s on the first run and 107k warm — SingleStore compiles each query shape on first sight, as on Linux)
Driver and connection string
- ODBC driver
- MySQL Connector/ODBC 9.4 (MySQL wire)
- Wire
- MySQL wire
- adbcBridge
- 0.1.1 (release)
The connection string the matrix used, as the connection strings reference records it (MySQL 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=13320;User=root;Password=adbc;{plugin_dir}{no_ssps}
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=13320;User=root;Password=adbc;")
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 SingleStore 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 driver quirks and no tolerance flag the mysql entry does not already have (TINYINT(1) booleans, ANSI_QUOTES) — a distributed HTAP engine whose tables are columnstore by default and whose MySQL mode takes that entry's types unchanged; columnstore and rowstore were probed side by side and behave identically on every point the workload checks.
What this stack needed
mysql_native_passwordonly, so run from the tarball the connector needsPLUGIN_DIR=; the freeghcr.io/singlestore-labs/singlestoredb-devimage needs no licence key and no account (the oldercluster-in-a-boxwants aLICENSE_KEY), and its one-offCheckCapacitywarning — used capacity 3 units against the licence's 1 — is the Developer Image licence describing itself, with nothing in the workload refused.- One thing to know when writing timestamps here through MySQL Connector/ODBC, which costs precision in plain ODBC but not through adbcBridge, and which is the connector's doing rather than SingleStore's (a plain-ODBC probe on 2026-09-04 gave byte-identical results against a stock MySQL 8.4 server): the connector's
SQLGetTypeInforow fordatetimereportsCOLUMN_SIZE21 /MAXIMUM_SCALE0 and aDATETIME(6)result column is describedCOLUMN_SIZE19 /DECIMAL_DIGITS0, so neither carries the column's real fractional precision — pyodbc derives its bind scale from that column size (21 − 20 = 1 digit) and silently stores13:45:10.123456as13:45:10.1, on theNO_SSPS=1text path too; the same value as a SQL literal or bound as a string keeps all six digits, and adbcBridge binds its own scale rather than the driver's type table, so the microsecond assertion passes unchanged. - SingleStore's own free ODBC driver (singlestore-odbc-connector 1.2.2, a MariaDB Connector/ODBC fork) passes the same entry and is the cross-check for that: it reports
SingleStore/09.01.0001rather than the wire'sMySQL/5.7.32, describes the columnCOLUMN_SIZE26 /DECIMAL_DIGITS6 (pyodbc is exact through it), and needs neitherPLUGIN_DIR=nor theLD_PRELOAD, but itsSQLGetTypeInfofails underANSI_QUOTES—42S22 … Unknown column 'json' in 'field list' (1054), the name always being the first type the call would have returned, so the driver is building its type table from double-quoted string literals thatANSI_QUOTESturns into identifiers — the templateSELECT "%s" AS TYPE_NAME, …is visible in the driver binary (SQLColumns,SQLTablesand ordinary queries are unaffected); separately, itsSQLColumnswith a NULL catalog name segfaults the process onstrdup(NULL)inMADB_StmtColumnsNoInfoSchemawhenever at least one column matches, in eithersql_mode. adbcBridge absorbs that rather than failing —TypeNameOnetreats aSQLGetTypeInfothat does not succeed as "no such type" and falls through to the portable ANSI name — so the only visible difference is the ingest DDL's spelling (mediumtext/bit(1)through Connector/ODBC,text/tinyint(1)through SingleStore's), both valid and both passing the read-back. - The entry uses Connector/ODBC because the eleven other MySQL-wire entries already do.
- Ingest 164k rows/s (159k with array binding), the fastest of the MySQL-wire entries; fetch 1.26M rows/s.
- Measure twice: SingleStore compiles each query shape to machine code on first sight, and a cold-container run of the same benchmark gave 75k/109k — which reads as "arrays are 45% faster" and is really the compiler, since with plans cached the two forms land within 3% of each other, so
prefer_param_arraysis not wanted.
Native ADBC driver, compared
SingleStore speaks the MySQL wire protocol, so the ADBC Driver Foundry's native MySQL ADBC driver (0.6.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 | ✓ all seven steps | |
| adbcBridge over ODBC | ✓ all seven steps |
Where the native driver stops it is by design of that driver, not a defect of SingleStore; the full table for all 28 wire-compatible databases, with each first error, is in the note.