gizmosql-adbc

July 29, 2026 · View on GitHub

gizmosql-adbc-ci Go Reference Go Version Supported Python Versions PyPI version PyPI Downloads License

Native ADBC driver for GizmoSQL, written in Go, with Python bindings — the successor to adbc-driver-gizmosql 1.x.

Status: released. adbc-driver-gizmosql 2.0 ships from this repo — pip install adbc-driver-gizmosql gets the Go-backed driver with the same API as 1.x (migration guide).

Why a Go driver?

The GizmoSQL-specific behavior that previously lived in the 1.x Python package — DDL/DML auto-detection and immediate execution (GizmoSQL's lazy-execution model), RETURNING handling, geometry-preserving bulk ingest, and the OAuth/SSO browser flow — lives in a native Go ADBC driver built on apache/arrow-adbc's Flight SQL driver. Compiled to a C shared library, one implementation serves every ADBC language: Python, Go, R, C/C++, C#, Rust, and JavaScript.

Layout

go/       Go driver (wraps arrow-adbc's flightsql driver) + cgo C exports
python/   Python bindings — ships libadbc_driver_gizmosql in its wheels,
          keeps the 1.x dbapi.connect() API byte-compatible (PyPI:
          adbc-driver-gizmosql 2.x)
docs/     Design docs, migration guide, conformance results

Features

  • gizmosql:// URI scheme — TLS by default, ?transport=tcp for plaintext
  • DDL/DML auto-detection → immediate server-side execution (DoPut) under GizmoSQL's lazy-execution model, with INSERT/UPDATE/DELETE ... RETURNING eagerly materialized on the query path
  • OAuth/SSO code-exchange flow (/oauth/initiate → browser → /oauth/token/{uuid}), including a headless mode — from any language via adbc.gizmosql.* options
  • Everything the upstream Flight SQL driver provides: TLS, cookies, timeouts, connection profiles, OpenTelemetry tracing and logging
  • Python bindings keeping the 1.x adbc-driver-gizmosql API byte-compatible — the verbatim 1.x test suite is this repo's release gate (migration guide)

See docs/plan.md for the design, docs/migrating-1x-to-2.md for the 1.x → 2.x migration guide, and docs/quickstarts-conformance.md plus docs/downstream-compat.md for how the driver is validated.

Usage (Go)

Start a GizmoSQL server

Start a GizmoSQL server in Docker, serving the small TPC-H sample database bundled in the image:

docker run --name gizmosql \
           --detach \
           --rm \
           --tty \
           --init \
           --publish 31337:31337 \
           --env TLS_ENABLED="1" \
           --env GIZMOSQL_USERNAME="gizmosql_user" \
           --env GIZMOSQL_PASSWORD="gizmosql_password" \
           --env DATABASE_FILENAME="data/TPC-H-small.duckdb" \
           --env PRINT_QUERIES="1" \
           --pull missing \
           gizmodata/gizmosql:latest

Install

go get github.com/gizmodata/gizmosql-adbc/go@latest

(The Go module is versioned by go/vX.Y.Z tags — its own line, independent of this repo's Python/release v* tags.)

Password authentication

package main

import (
	"context"
	"fmt"

	"github.com/apache/arrow-go/v18/arrow/memory"
	"github.com/gizmodata/gizmosql-adbc/go/gizmosql"
)

func main() {
	ctx := context.Background()

	drv := gizmosql.NewDriver(memory.DefaultAllocator)
	db, err := drv.NewDatabase(map[string]string{
		"uri":      "gizmosql://localhost:31337", // TLS by default
		"username": "gizmosql_user",
		"password": "gizmosql_password",
		// Development only — trust the demo server's self-signed cert:
		"adbc.flight.sql.client_option.tls_skip_verify": "true",
	})
	if err != nil {
		panic(err)
	}
	defer db.Close()

	cnxn, err := db.Open(ctx)
	if err != nil {
		panic(err)
	}
	defer cnxn.Close()

	stmt, err := cnxn.NewStatement()
	if err != nil {
		panic(err)
	}
	defer stmt.Close()

	if err := stmt.SetSqlQuery(
		"SELECT n_nationkey, n_name FROM nation ORDER BY n_nationkey LIMIT 5",
	); err != nil {
		panic(err)
	}
	reader, _, err := stmt.ExecuteQuery(ctx)
	if err != nil {
		panic(err)
	}
	defer reader.Release()

	for reader.Next() {
		fmt.Println(reader.Record())
	}
}

URI schemes

The preferred way to connect is the gizmosql:// URI scheme, which is secure by default (gRPC with TLS):

URIMeaning
gizmosql://host:31337gRPC with TLS (default)
gizmosql://host:31337?transport=tlsgRPC with TLS (explicit)
gizmosql://host:31337?transport=tcpgRPC plaintext (no TLS)
grpc+tls://host:31337Legacy TLS spelling (still supported)
grpc+tcp://host:31337 / grpc://host:31337Legacy plaintext spellings (still supported)
flightsql://host:31337Upstream Flight SQL spelling (still supported)

Observability: OpenTelemetry tracing & logging

Inherited from the upstream Flight SQL driver — trace spans are emitted for Database.Open, Prepare, ExecuteQuery, and ExecuteUpdate:

Option key (database options)Description
adbc.telemetry.traces_exporterExporter: none, otlp, console, or adbcfile
adbc.telemetry.traces_folder_pathOutput directory for the adbcfile exporter
adbc.telemetry.trace_parentW3C Trace Context traceparent — join an existing distributed trace

With the otlp exporter, the standard OTEL_EXPORTER_OTLP_* environment variables configure the collector endpoint. Structured driver logging is enabled via ADBC_DRIVER_FLIGHTSQL_LOG_LEVEL (debug/info/warn/error).

DDL/DML — auto-detected and executed immediately

GizmoSQL plans queries lazily: the Flight SQL GetFlightInfo RPC only plans, so DDL/DML submitted through the normal query path never executes unless the result is fetched. This driver detects DDL/DML statements (first keyword, comments stripped) and routes them through ExecuteUpdate (DoPut) for immediate server-side execution — no fetch required. INSERT/UPDATE/DELETE ... RETURNING takes the query path with the result eagerly materialized, so the DML fires even if you never read the returned reader — matching the 1.x Python driver and the GizmoSQL JDBC/ODBC drivers:

stmt.SetSqlQuery("CREATE TABLE t (id INT)")
_, _, _ = stmt.ExecuteQuery(ctx) // executes immediately via DoPut

stmt.SetSqlQuery("INSERT INTO t VALUES (1), (2)")
_, affected, _ := stmt.ExecuteQuery(ctx) // affected == 2, already executed

Routing applies to plain SQL only — statements with bound parameters (Bind/BindStream) or Substrait plans use standard prepared-statement semantics.

OAuth/SSO authentication

When your GizmoSQL server is configured with OAuth, set adbc.gizmosql.auth_type to external — the driver initiates the flow, opens your browser to the identity provider, polls for completion, and connects with the identity token via Basic Auth (username token):

db, err := drv.NewDatabase(map[string]string{
	"uri":                     "gizmosql://gizmosql.example.com:31337",
	"adbc.gizmosql.auth_type": "external",
})
Option keyDefaultDescription
adbc.gizmosql.auth_typepasswordpassword or external (OAuth/SSO)
adbc.gizmosql.oauth.url(discovered)Explicit OAuth base URL; otherwise probed from the connection host (HTTPS, then HTTP)
adbc.gizmosql.oauth.port31339OAuth HTTP port used for discovery
adbc.gizmosql.oauth.timeout_seconds300Max seconds to wait for the user to complete auth
adbc.gizmosql.oauth.poll_interval_seconds1Delay between token polls
adbc.gizmosql.oauth.open_browsertruefalse prints the auth URL to stderr instead (headless)
adbc.gizmosql.oauth.tls_skip_verify(follows Flight SQL setting)Skip TLS verification for the OAuth HTTP server

Go-native callers can also run the flow directly — including fully headless with a custom URL handler — via gizmosql.GetOAuthToken:

result, err := gizmosql.GetOAuthToken(ctx, gizmosql.OAuthConfig{
	Host:           "gizmosql.example.com",
	AuthURLHandler: func(u string) { fmt.Println("authenticate at:", u) },
})
// result.Token → use as password with username "token"

Usage (any language, via driver manifest)

Build (or download from a release) the shared library, then install a driver manifest so every ADBC driver manager can load the driver by name:

make -C go lib   # produces go/build/libadbc_driver_gizmosql.{so,dylib,dll}

Copy packaging/gizmosql.toml.in to a driver search path as gizmosql.toml (e.g. ~/.config/adbc/drivers/ on Linux, ~/Library/Application Support/ADBC/Drivers/ on macOS, or any directory in ADBC_DRIVER_PATH), filling in the library path. Then:

# Python — no GizmoSQL-specific package needed:
import adbc_driver_manager.dbapi as dbapi

with dbapi.connect(driver="gizmosql", db_kwargs={
    "uri": "gizmosql://localhost:31337",
    "username": "gizmosql_user",
    "password": "gizmosql_password",
}) as conn:
    ...

The same driver = "gizmosql" reference works everywhere the ADBC driver manager does — with DDL/DML immediacy, RETURNING handling, gizmosql:// URIs, and OAuth all provided by the shared library. Verified against the Columnar ADBC QuickStarts gizmosql examples (see docs/quickstarts-conformance.md):

// Go via the C driver manager (github.com/apache/arrow-adbc/go/adbc/drivermgr)
var drv drivermgr.Driver
db, err := drv.NewDatabase(map[string]string{
    "driver":   "gizmosql",
    "uri":      "gizmosql://localhost:31337",
    "username": "gizmosql_user",
    "password": "gizmosql_password",
})
# R
library(adbcdrivermanager)
db <- adbc_database_init(
  adbc_driver("gizmosql"),
  uri = "gizmosql://localhost:31337",
  username = "gizmosql_user",
  password = "gizmosql_password"
)
// C/C++ (adbc_driver_manager.h)
AdbcDatabaseSetOption(&database, "driver", "gizmosql", &error);
AdbcDatabaseSetOption(&database, "uri", "gizmosql://localhost:31337", &error);

Or reference it from a connection profile usable in every language:

profile_version = 1

[Options]
driver = "gizmosql"
uri = "gizmosql://gizmosql.example.com:31337"
username = "gizmosql_user"
password = "{{ env_var(GIZMOSQL_PASSWORD) }}"

Usage (Python)

The Python bindings ship from this repo as adbc-driver-gizmosql (2.x) — the platform wheels bundle the Go driver, and the API is byte-compatible with the 1.x driver (migration guide):

pip install adbc-driver-gizmosql
from adbc_driver_gizmosql import dbapi as gizmosql

with gizmosql.connect("gizmosql://localhost:31337",  # TLS by default
                      username="gizmosql_user",
                      password="gizmosql_password",
                      tls_skip_verify=True,
                      ) as conn:
    with conn.cursor() as cur:
        # DDL/DML executes immediately (no fetch needed), RETURNING works,
        # and adbc_ingest preserves geometry columns — all driver-side.
        cur.execute("SELECT n_nationkey, n_name FROM nation LIMIT 5")
        print(cur.fetch_arrow_table())

OAuth/SSO (auth_type="external"), connection profiles (profile=), bulk ingest (cursor.adbc_ingest), and Pandas integration all work exactly as in 1.x.

License

Apache License 2.0 — see LICENSE.