SDKs & Tools

ADBC

Query Tables with DataFusion SQL and SPQL functions from any ADBC client.

In development

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-sql

The 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:

URIReads
spiraldb://?project=demoThe head of the main branch.
spiraldb://?project=demo&ref=feature-xThe 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:

SourceSet with
An access token that your application owns and refreshesThe spiral.access_token database option. Replace it on the open database with set_option.
A client ID and client secretThe standard username and password database options.
Credentials in the environmentSPIRAL_TOKEN, or a private key or client secret, as for the Rust SDK.
Your own sign-inThe 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 DESC

Statements 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:

StatementInstead
CREATE ENRICHMENTThe Enrichments service
REFRESH LOCATIONThe Locations service
CREATE AUTOMATION, CALLThe service API or the SDK method for the operation
USE DATASET, keyed tablesQuery 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.

Found a problem? Edit this page or report an issue.

On this page