ADBC
Query Tables with DataFusion SQL and SPQL functions from any ADBC client.
Connect notebooks, BI tools, SQL terminals, and scripts in any language with an Arrow Database Connectivity (ADBC) driver manager to a Project's Tables, and get query results as Arrow. The Spiral ADBC driver runs the DataFusion integration inside your process, so its SQL is DataFusion's dialect with Spiral's SPQL functions added. Scans and SPQL calls run in the same process, next to storage; no query passes through Spiral's services.
Set up
For Python, install the SQL distribution:
pip install spiral-sqlThe package supplies the driver. Open a connection through spiral_sql.adbc.dbapi:
from spiral_sql.adbc import dbapi
with dbapi.connect("spiraldb://?project=demo") as connection:
with connection.cursor() as cursor:
cursor.execute("SELECT frame_id, camera FROM frames WHERE camera = ? LIMIT 10", ["front"])
print(cursor.fetch_arrow_table())spiral_sql.adbc.connect opens a low-level ADBC database, and
spiral_sql.adbc.driver_path() returns the bundled driver path for other driver
managers. This library exports AdbcDriverSpiraldbInit and includes its own
native table runtime; it does not require spiral-sdk or spiral-cli.
The SQL package has its own version and releases, so you can upgrade it independently.
Installing spiral-sdk[sql] or spiral-sdk[adbc] also installs spiral-sql.
For other languages or tools that load a driver library directly, use a driver
archive instead.
Download the driver archive for your platform. The current version and the URL
of each archive are at https://downloads.spiraldb.com/adbc/latest.json; each
release lives under https://downloads.spiraldb.com/adbc/<version>/. Archives
exist for macOS on Apple silicon and for Linux on x86-64 and ARM64 with glibc
2.28 or later.
Unpack the archive and keep its files together. Load
libadbc_driver_spiraldb (.dylib on macOS, .so on Linux) with your
driver manager; its entry point is AdbcDriverSpiraldbInit. For example, with
the Python driver manager:
import adbc_driver_manager.dbapi
connection = adbc_driver_manager.dbapi.connect(
driver="./adbc-driver-spiraldb/libadbc_driver_spiraldb.dylib",
entrypoint="AdbcDriverSpiraldbInit",
db_kwargs={"uri": "spiraldb://?project=demo"},
autocommit=True,
)
with connection.cursor() as cursor:
cursor.execute("SELECT frame_id, camera FROM frames WHERE camera = ? LIMIT 10", ["front"])
print(cursor.fetch_arrow_table())Video functions load the video runtime that the archive carries beside the
driver, and FFmpeg 9, which you install separately. The archive's README.md
lists the FFmpeg libraries and how to put them on the library search path.
Queries that do not decode video need neither.
For a terminal, run spiral-sql. When spiral-cli is also installed,
spiral sql forwards arguments to the same executable. Install the tools into
one environment with pip install 'spiral-cli[sql]', or install both on your
shell's PATH with uv tool install spiral-cli and uv tool install spiral-sql.
The tools share the SDK's configuration and credentials.
For an interactive SQL terminal with a schema browser, use Harlequin.
Connect to a Project
The database URI selects the Project and the version of its Tables that queries read:
| URI | Reads |
|---|---|
spiraldb://?project=demo | The head of the main branch. |
spiraldb://?project=demo&ref=feature-x | The head of another branch. |
spiraldb://?project=demo&ref=c<commit-id> | One exact commit. |
spiral:memory: | No Project: DataFusion's in-memory tables, shared by connections from one database. |
Opening a database selects the current branch head. Its connections share that snapshot and their session settings. Successful writes advance the shared catalog to the committed snapshot. Open a new database to read later external commits. A commit ref reads the same versions every time; see commits and branches.
The driver authenticates with the first credential it finds:
| Source | Set with |
|---|---|
| An access token that your application owns and refreshes | The spiral.access_token database option. Replace it on the open database with set_option. |
| A client ID and client secret | The standard username and password database options. |
| Credentials in the environment | SPIRAL_TOKEN, or a private key or client secret, as for the Rust SDK. |
| Your own sign-in | The tokens that spiral login saved; otherwise the driver opens a browser to sign in. |
The spiral.api_url and spiral.spfs_url database options override the
endpoints in your Spiral settings.
Query Tables
A Table's name in SQL is its address, in the
spiral catalog, with the Project ID as the schema. The URI's Project is the
default; use "project-id"."path@ref" to qualify another Project. Quote addresses that contain
/, -, ., or other characters outside letters, digits, _, and @;
the DataFusion page
gives the rules. Names are case-sensitive.
SELECT camera, count(*) AS frames
FROM "frames@main"
WHERE captured_at >= TIMESTAMP '2026-10-01 00:00:00'
GROUP BY camera
ORDER BY frames DESCStatements are DataFusion SQL: queries, joins, aggregates, window functions,
EXPLAIN, and SET. DataFusion sends column selection and simple filters into
each Spiral Scan and runs the rest of the query itself. The ADBC metadata calls
return schema information: GetObjects lists Project Tables that a query or
schema lookup has already resolved, and GetTableSchema resolves one Table's
Arrow schema directly.
Prepared statements bind Arrow parameters to ? placeholders in order or to
$1, $2, and so on. Parameter batches can contain multiple rows. Reusing a
prepared statement keeps the Table versions resolved when it was prepared.
Call SPQL functions
Every SPQL function is available under its full name. Quote the name, because it contains dots:
SELECT frame_id, "spql.str.upper"(camera) AS camera
FROM frames
WHERE "spql.str.contains"(camera, 'front')Arguments must already have a type that the function accepts; SPQL does not cast implicitly. Calls over a Table's columns run inside its Scan. The DataFusion page explains where the calls run and how they differ from DataFusion's own functions.
Write rows
A connection to a branch publishes Table creation, appends, overwrites and
removal as commits through the SDK. Omit the @ref suffix on write targets;
select the target branch in the connection URI. A connection to an exact commit
is read-only. New Tables use a root name such as frames.
ADBC bulk ingestion accepts Arrow data with the modes create, append,
replace, and create_append. On a Project connection these operations persist
the data. Each create or append publishes one commit. The driver collects the
bound input before writing.
The replace mode removes the old Table and creates its replacement in two
separate commits. If creation fails, the name can remain absent. Use DataFusion's
INSERT OVERWRITE for an atomic replacement of an existing Table's rows.
Successful writes become visible to new queries on the same connection and other connections sharing its database. Prepared plans keep their original versions. If another writer has advanced the branch, the write fails with a conflict; reopen the database to select the latest head before trying again.
In spiral:memory:, ingestion and DataFusion SQL DDL and DML operate on local
in-memory tables.
A Project connection can ingest into in-memory tables by setting both target
catalog datafusion and target schema public on its ingestion statement.
Query the resulting table as datafusion.public.<table>. These rows stay in
the local database session and are not published to the Project.
SQL the driver does not run
The driver has no SQL of its own, so statements that only Spiral understood do not parse, or fail to plan. Use the service that owns each Resource instead:
| Statement | Instead |
|---|---|
CREATE ENRICHMENT | The Enrichments service |
REFRESH LOCATION | The Locations service |
CREATE AUTOMATION, CALL | The service API or the SDK method for the operation |
USE DATASET, keyed tables | Query the Table by its address |
Availability
The connection always operates in autocommit mode; transactions are not supported. Read-only connection options, listing every Project Table, refreshing an open database to later external branch commits, table-type enumeration, cancellation, progress reporting, statistics and temporary tables are not available. Partitioned results for queries over Project Tables or SPQL functions are not available. Substrait plans execute through DataFusion.