Skip to content
adbc-driversPublic

About

ADBC driver for Firebolt

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Latest commit

 

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Firebolt ADBC driver

Query Firebolt from Python, R, Go and any other language with an ADBC driver manager. Results arrive as Apache Arrow, so they land straight in pyarrow, pandas or polars with no row-by-row conversion.

The driver is a single shared library loaded by your application; nothing is installed on the server.

Supported today

Connections http:// and https:// (always certificate-verified)
Authentication Firebolt SaaS: supported for engines v5 and later only, with a service account (docs/fb2-saas.md). Firebolt Core: authentication disabled, or a bearer token you already have (docs/authentication.md).
Platforms Linux x86_64/aarch64 (glibc 2.28+), macOS arm64, Windows x86_64
ADBC The ADBC 1.0.0 API (see Feature & Type Support)

Quickstart

This example runs Firebolt Core locally in Docker; to connect to Firebolt SaaS, see below. You need Docker and Python 3.9+. It takes about two minutes.

1. Install the driver manager and the driver (the driver via dbc):

pip install adbc-driver-manager pyarrow
dbc install firebolt --pre

2. Start a local Firebolt engine

docker run -d --name firebolt -p 3473:3473 ghcr.io/firebolt-db/engine:5.0.0-pre.0.20260927210425.e91cd5bd17f8
until curl -fs http://localhost:3473/ping >/dev/null; do sleep 1; done; echo ok

It starts with authentication disabled, so no credentials are needed.

3. Run a query

import adbc_driver_manager.dbapi as dbapi

with dbapi.connect(
    driver="firebolt", db_kwargs={"uri": "http://localhost:3473"}
) as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT 1 AS n, 'hello' AS greeting")
        print(cur.fetch_arrow_table())
pyarrow.Table
n: int32 not null
greeting: string not null
----
n: [[1]]
greeting: [["hello"]]

Connect to Firebolt SaaS

For engines v5 and later. Pass a service account and the account and engine names instead of a uri; the driver finds the engine for you:

import os
import adbc_driver_manager.dbapi as dbapi

with dbapi.connect(
    driver="firebolt",
    db_kwargs={
        "username": os.environ["FIREBOLT_CLIENT_ID"],  # service account ID
        "password": os.environ["FIREBOLT_CLIENT_SECRET"],  # service account secret
        "firebolt.account": "my_account",
        "firebolt.engine": "my_engine",
        "firebolt.database": "my_db",
    },
) as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT 1 AS n")
        print(cur.fetch_arrow_table())

Everything below works the same way. Options and details are in docs/fb2-saas.md.

Runnable versions of everything below are in examples/python/.

Common tasks

Fetch results

cur.execute("SELECT * FROM my_table")
table = cur.fetch_arrow_table()  # pyarrow.Table
df = cur.fetch_df()  # pandas.DataFrame

# Larger than memory? Stream it:
cur.execute("SELECT * FROM big_table")
for batch in cur.fetch_record_batch():
    process(batch)

Results are streamed, so a result you have not finished reading still occupies the connection. Other queries and commits on that connection fail until you read it to the end or close it (details).

Load Arrow data into a table

adbc_ingest uploads a whole Arrow table in one request and can create the target table for you, nested ARRAY and STRUCT columns included:

import pyarrow as pa

table = pa.table(
    {
        "id": pa.array([1, 2], pa.int32()),
        "tags": pa.array([["a", "b"], ["c"]], pa.list_(pa.string())),
        "meta": pa.array([{"k": 1}, {"k": 2}], pa.struct([("k", pa.int32())])),
    }
)

with dbapi.connect(
    driver="firebolt", db_kwargs={"uri": "http://localhost:3473"}, autocommit=True
) as conn:
    with conn.cursor() as cur:
        # mode: create, append, create_append or replace
        cur.adbc_ingest("events", table, mode="replace")

See Arrow to Database for the supported types.

Query parameters

Use Firebolt's positional placeholders $1, $2, … (not ? or %s). Values are sent separately from the SQL, never spliced into it:

cur.execute("SELECT $1 + 1", (41,))  # → 42
cur.executemany("INSERT INTO events VALUES ($1, $2)", [(1, "a"), (2, "b")])

Numbers, booleans, strings and None keep their type. Dates, timestamps and decimals are sent as text — add a cast ($1::DATE) if Firebolt cannot infer one.

Named parameters use Firebolt's param() function and are always TEXT:

cur.execute("SELECT param('cutoff')::INT + 1", {"cutoff": 41})

More in OPTIONS.md.

Transactions

dbapi.connect() turns autocommit off by default (as PEP 249 requires), so your statements run in a transaction until you commit:

cur.execute("INSERT INTO events VALUES (1, 'a')")
conn.commit()  # or conn.rollback()

Pass autocommit=True to dbapi.connect() to run each statement on its own.

Explore metadata

conn.adbc_get_table_schema("events")  # pyarrow.Schema
conn.adbc_get_objects(depth="columns")  # catalogs → schemas → tables → columns
conn.adbc_get_table_types()
conn.adbc_get_info()

Options

Set these in db_kwargs:

Key Meaning
uri Required. The engine endpoint, e.g. http://localhost:3473, or firebolt://host[:port]/[database], which uses TLS unless you add ?ssl_mode=disable (details)
firebolt.database Database to use
firebolt.token Bearer token; omit when authentication is disabled
firebolt.timeout_sec How long to wait for the server, in seconds; 0 (default) means no limit (details)
firebolt.ssl_certificate_path PEM CA bundle for https://, if not the system one
firebolt.arrow_compression any (default) lets the server send compressed results; none turns that off; zstd or lz4 allows just that codec (details)

Connection and statement options are in OPTIONS.md. These names will change when the driver adopts Firebolt's common SDK parameter names (mapping).

Feature & Type Support

Features

Feature Firebolt
Bulk Ingestion: Create ✅
Bulk Ingestion: Append ✅
Bulk Ingestion: Create/Append ✅
Bulk Ingestion: Replace ✅
Bulk Ingestion: Temporary Table ❌ 1
Bulk Ingestion: Target Catalog ✅ 2
Bulk Ingestion: Target Schema ✅
Non-nullable fields are marked NOT NULL ✅ 3
Catalog (GetObjects): depth=catalogs ✅
Catalog (GetObjects): depth=db_schemas ✅
Catalog (GetObjects): depth=tables ✅
Catalog (GetObjects): depth=columns (all) ✅
Get Parameter Schema ✅ 4
Get Table Schema ✅
Prepared Statements ✅ 4
Transactions ✅
Also Firebolt
Streaming results as Arrow record batches ✅
Query parameters ($1, named via param('name')) ✅ 5
Session parameters (firebolt.session.*) ✅
rowcount after DML ❌ always -1 6
Firebolt Core sign-in with credentials ❌ see docs/authentication.md
Partitioned execution, Substrait ❌
ADBC 1.1.0-only functions ❌ 7

Types

Database to Arrow

Database Type Firebolt
BOOLEAN bool
INTEGER (INT) int32
BIGINT int64
REAL float
DOUBLE PRECISION (FLOAT, DOUBLE) double
TEXT (VARCHAR) string
BYTEA binary
DATE date32[day]
TIMESTAMP (TIMESTAMPNTZ) timestamp[us]
TIMESTAMPTZ timestamp[us, tz=UTC]
NUMERIC(p, s) (DECIMAL(p, s)) decimal128(p, s)
GEOGRAPHY binary 8
ARRAY(T) list<item: T>
STRUCT(…) struct<…>

ARRAY and STRUCT nest to any depth.

Arrow to Database

Ingest creates and loads tables from Arrow data; Bind sends values as query parameters.

Arrow Type Firebolt Type Ingest Bind
bool BOOLEAN ✅ ✅
int8, int16, int32, uint8, uint16 INTEGER ✅ ✅ as BIGINT
int64, uint32 BIGINT ✅ ✅
uint64 BIGINT ⚠️ 9 ⚠️ 9
float REAL ✅ ✅ as DOUBLE
double DOUBLE PRECISION ✅ ✅ 10
string, large_string TEXT ✅ ✅
string_view TEXT ❌ 11 ✅
binary, large_binary, fixed_size_binary BYTEA ✅ ❌ 5
binary_view BYTEA ❌ 11 ❌ 5
date32[day], date64[ms] DATE ✅ ✅ as text 12
timestamp[s|ms|us|ns] TIMESTAMP ✅ ✅ as text 12
timestamp (with time zone) TIMESTAMPTZ ✅ 13 ✅ as text 12
time32, time64 (no mapping) ❌ ✅ as text 12
decimal128(p, s) NUMERIC(p, s) ✅ 14 ✅ as text 12
decimal32, decimal64, decimal256 NUMERIC(p, s) ❌ 15 ✅ as text 12
list<T>, large_list<T> ARRAY(T) ✅ ❌ 5
fixed_size_list<T> ARRAY(T) ❌ 15 ❌ 5
struct<…> STRUCT(…) ✅ 3 ❌ 5
dictionary<T> (value type) ❌ 11 ✅ decoded as T
null (no mapping) ❌ ✅ as NULL
map, duration, interval (no mapping) ❌ ❌

A NULL value binds as SQL NULL whatever its Arrow type.

Footnotes

  1. Firebolt has no temporary tables.
  2. Set a target schema too; a catalog alone is read as the schema.
  3. Only top-level columns become NOT NULL; Firebolt requires STRUCT fields to be nullable.
  4. Prepare is local; adbc_prepare() asks the server for parameter types without running the query (details).
  5. Binary and nested values cannot be bound as parameters; ingest them instead. Named parameters are always TEXT (details).
  6. Firebolt does not report affected rows; use SELECT count(*).
  7. Typed option setters, Cancel, ExecuteSchema, GetStatistics, ErrorGetDetail. GetInfo still reports ADBC 1.1.0.
  8. WKB bytes, without GeoArrow metadata.
  9. Values above the signed 64-bit maximum are rejected.
  10. NaN and infinities are rejected.
  11. Not supported by the Arrow IPC writer; cast to string/binary or decode the dictionary first.
  12. Firebolt converts the text in most contexts; otherwise cast ($1::DATE).
  13. Stored as UTC; the original offset is not kept.
  14. Precision up to 38.
  15. Rejected by the server; cast to decimal128 or list.

Troubleshooting

Error Fix
Could not connect to server Is the engine running? Check curl -fsS http://localhost:3473/ping.
Cluster not yet healthy The engine is still starting; retry in a few seconds.
Database 'uri' must start with … Include the scheme: http://localhost:3473, not localhost:3473.
HTTP 401 / 403 The engine requires authentication; see docs/authentication.md.
No CA certificate bundle found / SSL peer certificate … was not OK Install your OS's ca-certificates, or set firebolt.ssl_certificate_path to your CA's PEM file.
positional parameter $1, but it was not set Pass one value per $N placeholder; numbering starts at $1.
current transaction is aborted A statement failed inside a transaction; call conn.rollback().
A query result stream is still open on this connection Read the previous result to the end or close it first, or use a second connection (details).
Unknown Firebolt database option Check the option name against OPTIONS.md.

Build from source

Only needed to work on the driver itself; otherwise use a release. Requires git, Docker and Pixi:

git submodule update --init --recursive
pixi run make   # → build/libadbc_driver_firebolt.{so,dylib,dll}

Testing and contribution guidelines are in CONTRIBUTING.md.

Documentation

OPTIONS.md Every option, error status and type mapping
docs/authentication.md Authentication: what works now and what is planned
examples/python/ Runnable examples
CONTRIBUTING.md Building, testing and submitting changes
CHANGELOG.md Release history

Other environments

FB2 only: engines (v5+) in a Firebolt 2.0 SaaS account — see docs/fb2-saas.md.

License

Apache 2.0 — see LICENSE.txt and NOTICE.txt. Release packages also include the licenses of all statically linked dependencies.

About

ADBC driver for Firebolt

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages