datafusion

package module
v0.530100.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 26, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

README

datafusion-go

Go Reference CI Go Report Card License

What is datafusion-go?

datafusion-go is in-process analytic SQL for Go, powered by Apache DataFusion — an extensible query engine written in Rust that uses Apache Arrow as its in-memory format. It ships as a standard database/sql driver with an Arrow-native escape hatch: no server, no network connection, nothing else to run.

Out of the box, datafusion-go offers the familiar database/sql interface, analytic SQL over CSV and Parquet files, Arrow record batches in and out, and prebuilt native runtimes for macOS, Linux, and Windows that install themselves on first use. DataFusion's columnar, multi-threaded, vectorized execution engine does the heavy lifting; the driver's job is to make it feel like Go.

That makes datafusion-go great for building data-heavy tools and CLIs, tests for analytic pipelines, services that want embedded query features, and more. It is not a network database client, and it does not turn DataFusion into a persistent file database: catalog and session state live in memory and last only as long as the process.

Here are links to some important information:

datafusion-go is a community-maintained binding in the datafusion-contrib organization, alongside other bindings and extensions built around Apache DataFusion.

How do I install and use it?

Install
go get github.com/datafusion-contrib/datafusion-go

Requires Go 1.24+ with cgo enabled (the default) and a C toolchain. On supported platforms — darwin-arm64, darwin-amd64, linux-amd64, linux-arm64, and windows-amd64 — there is no other setup: the driver downloads the matching libdatafusion_go native library from the module's GitHub release and checksum-verifies it on first use. See Native Runtime to override resolution or disable downloads.

Install from a tagged release for normal consumer use. Pseudo-versions from @main are development snapshots and may not have matching GitHub Release assets for the native runtime downloader; source checkouts build the library locally with make bundle instead.

Quick Start

Give it a CSV file:

printf 'city,trips\nnyc,3\nnyc,5\nsf,2\n' > trips.csv

Register the file as a table and run analytic SQL against it:

package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"

	_ "github.com/datafusion-contrib/datafusion-go"
)

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

	db, err := sql.Open("datafusion", "")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	_, err = db.ExecContext(ctx, `create external table trips
		stored as csv location 'trips.csv'
		options ('format.has_header' 'true')`)
	if err != nil {
		log.Fatal(err)
	}

	rows, err := db.QueryContext(ctx, `select city, sum(trips) as total
		from trips group by city order by total desc`)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		var city string
		var total int64
		if err := rows.Scan(&city, &total); err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%s\t%d\n", city, total)
	}
	if err := rows.Err(); err != nil {
		log.Fatal(err)
	}
}
nyc	8
sf	2

The same pattern works for Parquet (stored as parquet).

Examples

More runnable examples live in examples/: simple, parameters, and arrow. Try one without cloning anything:

go run github.com/datafusion-contrib/datafusion-go/examples/simple@latest

From a source checkout, run make bundle once, then go run ./examples/simple.

Finding your way: Loading Data covers most use beyond the quick start. Arrow interop is under Arrow-Native Usage, exact scanning behavior under Type Conversion and Semantics and Limits, and building from source under Native Runtime and CONTRIBUTING.md.

Philosophy

  • In-process by design. The driver embeds a query engine in your process rather than connecting to one somewhere else. It suits local analytic execution, tests, tools, embedded query features, and services that want DataFusion inside the Go process — and it deliberately refuses DSNs that look like hosts or file paths rather than pretending to be a client.
  • Standard interfaces first. Everything that database/sql can express goes through database/sql: pooling, prepared statements, parameters, cancellation. Arrow-native APIs exist as an escape hatch for what it cannot express — exact schemas, complex types, record-batch streaming — not as a parallel API surface.
  • Zero setup, no surprises. Prebuilt native libraries download and checksum-verify themselves on first use, and every step of that is overridable: point at your own library, disable downloads, or build from source.
  • A query engine, not a database. There is no persistence, no transactions, and no insert IDs. Where DataFusion doesn't provide a behavior, the driver returns an explicit unsupported error instead of emulating it. Files are the durable layer: CREATE EXTERNAL TABLE reads them, COPY ... TO writes them.
  • Track upstream faithfully. Each release bundles a specific DataFusion version, encoded in the module version itself — see Versioning.

Features

  • Standard database/sql driver — registered as datafusion, with connection pooling, prepared statements, SQL parameters, and context cancellation.
  • Files as tablesCREATE EXTERNAL TABLE over CSV and Parquet files, COPY ... TO to write results back out.
  • Arrow-native APIs — stream results as arrow.RecordBatch values and register Go Arrow readers as DataFusion tables, with a zero-copy option.
  • Foreign table providers — register a datafusion-ffi FFI_TableProvider produced by another library and query it with projection/filter pushdown reaching the provider.
  • Typed SQL parameters?, $1, and $name styles, plus typed wrappers for dates, times, timestamps, durations, decimals, and typed nulls.
  • Context cancellation end to end — Go contexts bridge to native cancellation during planning, stream creation, and record-batch reads.
  • Structured errors — machine-readable native error kinds, matchable with errors.Is.
  • Zero-setup native runtime — prebuilt libraries for macOS, Linux, and Windows are downloaded and checksum-verified automatically on first use.

User Guide

Loading Data

Data reaches a session two ways: SQL DDL over files, or Arrow registration from Go memory. Both are session-scoped — see Driver and Sessions for how catalog state is shared across pooled connections.

Files

CREATE EXTERNAL TABLE registers a file as a queryable table. CSV and Parquet work out of the box:

_, err := db.ExecContext(ctx, `create external table events
	stored as parquet location '/data/events.parquet'`)

COPY writes query results back to files:

_, err := db.ExecContext(ctx, `copy (select * from events where kind = 'click')
	to '/data/clicks.parquet' stored as parquet`)

File paths appear only in SQL; the DSN never carries them — see DSNs.

Go Memory

Register any Go Arrow record reader as an in-memory table with RegisterArrowReader, or skip the defensive copy with RegisterArrowReaderZeroCopy when buffer lifetimes allow it. See Register Arrow Tables.

Driver and Sessions

The package registers itself with database/sql as datafusion.

db, err := sql.Open("datafusion", "")

A sql.DB opened by one connector shares a DataFusion SessionContext by default. This matches typical database/sql expectations: catalog changes such as CREATE VIEW or CREATE EXTERNAL TABLE are visible across pooled connections from the same sql.DB.

Use isolated sessions when you want each physical connection to have its own DataFusion session state:

db, err := sql.Open("datafusion", "?datafusion.go.shared_session=false")

Or configure it directly on a connector:

connector, err := datafusion.NewConnectorWithInitContext(
	"",
	nil,
	datafusion.WithSharedSession(false),
)
DSNs

Supported DSNs are:

  • ""
  • ?<options>
  • datafusion://
  • datafusion://?<options>

The DSN opens an in-process DataFusion session, not a remote host or file-backed embedded database. Query parameters are passed to DataFusion as session configuration options:

?datafusion.execution.batch_size=8192

Driver-owned options use the datafusion.go. prefix and are stripped before the remaining options are passed to DataFusion:

?datafusion.go.shared_session=false

File paths, hosts, and other URL forms are rejected. The URL form exists only to carry session options; files are queried through SQL instead — see Loading Data.

Query Paths

Use ordinary database/sql calls when rows contain scalar Arrow values that can be represented as database/sql/driver.Value values:

rows, err := db.QueryContext(ctx, "select 1 as value")

Use QueryArrowContext when you need exact Arrow schemas, record-batch streaming, or complex Arrow values that database/sql cannot scan:

conn, err := db.Conn(ctx)
if err != nil {
	return err
}
defer conn.Close()

reader, err := datafusion.QueryArrowContext(ctx, conn, "select 1 as value")
if err != nil {
	return err
}
defer reader.Close()

Records returned by Read must be released by the caller.

Initialization

Use NewConnector or NewConnectorWithInitContext when a pooled database needs setup SQL before use.

connector, err := datafusion.NewConnectorWithInitContext(
	"",
	func(ctx context.Context, exec driver.ExecerContext) error {
		_, err := exec.ExecContext(ctx, "create view nums as select 1 as n", nil)
		return err
	},
)
if err != nil {
	return err
}
defer connector.Close()

db := sql.OpenDB(connector)
defer db.Close()

In shared-session mode, the initialization callback runs once per connector. In isolated-session mode, it runs for each connection and reset.

Multiple Setup Statements

DataFusion prepares one SQL statement at a time. Split migration or setup scripts before calling the driver, then execute the statements in order:

err := datafusion.ExecStatements(ctx, db, []string{
	"create view one as select 1 as n",
	"create view two as select 2 as n",
})

The helper skips blank statements and wraps errors with the statement index.

Context Cancellation

Query contexts are bridged to native cancellation. Cancellation is checked during planning, stream creation, and record-batch reads.

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

rows, err := db.QueryContext(ctx, "select * from some_large_table")

Native cancellation errors can be matched with errors.Is(err, datafusion.ErrNativeCancelled).

SQL Parameters

The driver supports DataFusion SQL parameters through database/sql:

row := db.QueryRowContext(ctx, "select ? + 1, ?", int64(41), "x")

Supported ordinary parameter values are:

  • nil
  • bool
  • signed integer types that fit int64
  • unsigned integer types as DataFusion UInt64
  • floating-point values as float64
  • string
  • []byte
  • time.Time as Timestamp[ns]
  • time.Duration as Duration[ns]

time.Time preserves loadable IANA locations such as America/New_York. Fixed-offset, local, or otherwise non-loadable locations bind as UTC unless TimestampWithTimeZone is used. float32 values are promoted to DataFusion Float64 through database/sql conversion.

Other values are rejected by CheckNamedValue before native execution.

Use typed wrappers when inference would be ambiguous or when exact Arrow/DataFusion types matter:

row := db.QueryRowContext(
	ctx,
	"select $1, $2, $3, $4, $5",
	datafusion.DateFromTime(day),
	datafusion.TimeFromTime(clock),
	datafusion.DurationFromTime(2*time.Second),
	datafusion.DecimalString("123.45", 10, 2),
	datafusion.NullOf(datafusion.ParameterInt64),
)

Available wrappers cover UInt64, Date, Time, Timestamp, Duration, Decimal, and typed nulls through NullOf, NullDecimal, and NullTimestamp.

Bare nil binds as DataFusion's untyped null. Use NullOf, NullDecimal, or NullTimestamp when DataFusion needs a concrete type, for example select $1 + 1 with NullOf(ParameterInt64).

Prepared statements report Stmt.NumInput for ? placeholders, $1/$2 positional parameters, and distinct $name parameters. Repeated named parameters count once; each ? occurrence counts as a separate positional parameter. Mixed question-mark, dollar-numbered, and named parameter styles are rejected during prepare.

Named statements must be executed with matching sql.Named arguments. Positional arguments for named statements, named arguments for positional statements, missing names, extra names, and duplicate supplied names are rejected before query execution is handed to DataFusion.

Arrow-Native Usage
Query Arrow Batches

QueryArrowContext executes SQL on a *sql.Conn and returns a closeable Arrow reader:

reader, err := datafusion.QueryArrowContext(ctx, conn, "select $1", int64(42))
if err != nil {
	return err
}
defer reader.Close()

for {
	record, err := reader.Read()
	if err == io.EOF {
		break
	}
	if err != nil {
		return err
	}
	// Use record.
	record.Release()
}

The Arrow reader owns native stream resources and must be closed. A finalizer is installed as a leak safety net, but finalizers are not prompt cleanup and should not be relied on for normal resource management.

Register Arrow Tables

Arrow record readers can be registered as in-memory DataFusion tables:

rdr, err := array.NewRecordReader(schema, []arrow.RecordBatch{batch})
if err != nil {
	return err
}
defer rdr.Release()

if err := datafusion.RegisterArrowReader(ctx, conn, "events", rdr); err != nil {
	return err
}

RegisterArrowReader consumes the remaining batches from the reader, serializes them as an Arrow IPC stream, and registers decoded Rust-owned batches. The copy is intentional: a registered table can outlive the cgo call, while ordinary Go Arrow arrays can contain Go-owned buffers that native code must not retain.

RegisterArrowReaderZeroCopy skips the IPC copy by exporting the reader through the Arrow C Stream Interface. Use it only when every exported Arrow buffer is valid for native code to retain until the table is dropped or the owning session/connector closes, for example data built with Arrow Go's memory/mallocator package or another C/foreign allocator.

Do not use the zero-copy API with ordinary Go-allocated Arrow buffers unless you fully own that lifetime and cgo pointer-safety tradeoff.

Register Foreign FFI Table Providers

If another library produces a datafusion-ffi FFI_TableProvider — a language binding, or a client that talks to a remote catalog and streams Arrow — register it directly so SQL can plan against it, with projection and filter predicates pushed down into the provider:

// providerPtr is an *FFI_TableProvider handed to you by the producing library,
// and providerVersion is the datafusion version that library was built against.
table, err := datafusion.RegisterFFITableProvider(ctx, conn, "t", providerPtr, providerVersion)
if err != nil {
	return err
}
defer table.Deregister(ctx)

rows, err := db.QueryContext(ctx, `SELECT ... FROM t WHERE ...`)

A few contract points, all enforced or documented on RegisterFFITableProvider:

  • Version handshake. providerVersion must equal this package's DataFusionVersion; obtain it from the producing library, not from DataFusionVersion. The check runs before the provider pointer is dereferenced, so a mismatch is a clean error rather than a crash. The match is required to be exact — deliberately stricter than datafusion-ffi's major-version ABI contract, because datafusion is pre-1.0 and has broken layouts across minor releases.
  • Ownership. The provider pointer must be memory owned by the producing foreign library (C/Rust), not Go heap memory, since native code retains callback pointers cloned out of it past the call. Registration clones the provider (bumping its refcount), so you retain ownership of the original pointer and may free it through its producing library once the call returns.
  • Library lifetime. The producing library must stay loaded for as long as the table is registered — the registered table calls back into its function pointers on every scan.
  • Deregistration is explicit. RegisterFFITableProvider returns a *RegisteredTable handle; call Deregister to remove the table before the producing library tears down. The table's lifetime follows the session it was registered on: with an isolated session (WithSharedSession(false)) closing the *sql.Conn also releases it, but with a shared session (the default) it lives on the shared SessionContext and persists until Deregister or the owning Connector is closed. Dropping the handle never deregisters it.
API Overview

The most important exported APIs:

  • NewConnector / NewConnectorWithInitContext: pooled databases with setup SQL and connector options such as WithSharedSession.
  • QueryArrowContext: streams Arrow record batches from a *sql.Conn.
  • RegisterArrowReader / RegisterArrowReaderZeroCopy: register Go Arrow readers as DataFusion tables.
  • RegisterFFITableProvider: register a foreign datafusion-ffi FFI_TableProvider and query it with pushdown; returns a *RegisteredTable handle for explicit Deregister.
  • ExecStatements: executes an already-split slice of SQL statements.
  • Error and the ErrNative* sentinels: structured driver errors with operation type and native error kind.

See the Go package documentation for the complete API reference.

Type Conversion

database/sql row conversion currently supports:

Arrow type family Go value
Null nil
Bool bool
Signed integers int64
Unsigned integers int64 when in range
Float16/Float32/Float64 float64
Utf8/LargeUtf8/StringView string
Binary/LargeBinary/FixedSizeBinary/BinaryView []byte
Date/Time/Timestamp time.Time
Duration int64 nanoseconds
Decimal string
Intervals string

Column metadata is exposed through database/sql where Arrow schema information is precise: nullable columns use typed sql.Null* scan types where practical, fixed-size binary columns report length, decimal columns report precision and scale, and temporal/interval database type names include their Arrow unit or interval subtype.

Variable-width string and binary columns do not report declared lengths because DataFusion's Arrow result schema does not preserve SQL declarations such as VARCHAR(32).

Time-only values are returned as UTC time.Time values on the Unix epoch date. Duration values are returned as int64 nanoseconds because time.Duration is not a legal database/sql/driver.Value. Interval values are returned as strings that preserve their month, day, millisecond, and nanosecond components.

Nested and complex Arrow values such as lists, structs, maps, unions, dictionaries, extensions, and run-end encoded values are rejected from database/sql row conversion when schema information is available. Use the Arrow-native reader for exact batch data.

Semantics and Limits
  • PrepareContext validates SQL syntax with DataFusion's parser.
  • A prepared query must contain exactly one SQL statement. Multiple result sets are not supported; Rows.NextResultSet reports no additional result sets.
  • Stmt.NumInput reports parser-derived parameter counts for question-mark, dollar-numbered, or named parameters.
  • Connections from one connector share a DataFusion SessionContext by default.
  • Shared sessions intentionally share session-scoped catalog/config mutations, including CREATE VIEW, DROP VIEW, and SET, across all connections from the same connector.
  • Non-query statements are serialized at the connector level across ExecContext, QueryContext, and QueryArrowContext; queries can still observe normal ordering effects if they run concurrently with DDL.
  • Pooled reuse implements driver.SessionResetter. Shared sessions validate the connection and preserve shared session state; isolated sessions recreate the underlying SessionContext and rerun the connector initialization callback when one was provided.
  • Connections implement driver.Validator; closed connections are reported invalid before they return to the pool.
  • Native errors carry machine-readable error kinds across the C ABI and are exposed on *datafusion.Error.NativeKind.
  • errors.Is can match native sentinel errors: ErrNativeCancelled, ErrNativeInvalidArgument, ErrNativeFailure, and ErrNativePanic.
  • RowsAffected returns 0 by default and reports the sum of a single integer count, rows_affected, or rowsaffected output column when DataFusion emits one.
  • LastInsertId returns 0, nil; DataFusion does not expose insert IDs through this driver.
  • Prepared statement handles are reused when callers use db.Prepare or conn.PrepareContext, but DataFusion still plans and executes each run; the driver does not cache DataFusion physical plans.
  • Close is idempotent for connectors, connections, statements, rows, and Arrow readers.
  • Transactions are unsupported and return explicit unsupported errors. BeginTx still honors an already-canceled context before returning the unsupported transaction error.
Native Runtime

Default builds use cgo but do not link DataFusion at Go link time. At runtime, the driver loads a shared libdatafusion_go library, resolved in this order:

  1. DATAFUSION_GO_LIBRARY, if set.
  2. internal/native/lib/<goos>-<goarch>/ in a source checkout.
  3. A checksum-verified library downloaded from the matching GitHub Release into the user cache.

Environment variables:

  • DATAFUSION_GO_LIBRARY — explicit path to the shared library.
  • DATAFUSION_GO_NO_DOWNLOAD=1 — disable automatic release-asset downloads.
  • DATAFUSION_GO_DOWNLOAD_BASE — override the release download base URL.

Prebuilt native libraries are published for darwin-arm64, darwin-amd64, linux-amd64, linux-arm64, and windows-amd64. Windows arm64 is not currently bundled.

CGO_ENABLED=0 is not supported for normal use; the package returns a clear datafusion-go requires cgo error in that mode.

Source checkouts should run make bundle or make test before invoking Go tests or examples that open the driver directly; both build the Rust shim and copy the native archive and shared library into internal/native/lib/<goos>-<goarch>/. Alternative link modes (bundled static archive, source, static-lib, and system shared-library linking) are documented in CONTRIBUTING.md.

Troubleshooting

datafusion-go requires cgo

Enable cgo for normal execution:

CGO_ENABLED=1 go test ./...
Native library not found

If automatic download is disabled or the release does not publish an asset for your platform, either set DATAFUSION_GO_LIBRARY or build a local library:

make bundle
DATAFUSION_GO_LIBRARY="$PWD/internal/native/lib/$(go env GOOS)-$(go env GOARCH)/libdatafusion_go.so" go test ./...

On macOS, use libdatafusion_go.dylib. On Windows, use datafusion_go.dll.

Local checkout tests fail before opening the driver

Run the project build/test target so internal/native/lib/<goos>-<goarch>/ is populated:

make test
DSN rejected

Use an empty DSN or a session-options DSN. Paths, hosts, and file URLs are intentionally unsupported; register files through SQL instead — see Loading Data.

sql.Open("datafusion", "")
sql.Open("datafusion", "?datafusion.execution.batch_size=8192")
sql.Open("datafusion", "datafusion://?datafusion.go.shared_session=false")
database/sql cannot scan a result column

The database/sql path rejects complex Arrow values. Use QueryArrowContext to read exact Arrow record batches.

Windows build or test failures

Use a MinGW/GNU C toolchain. The bundled Windows build targets Rust's x86_64-pc-windows-gnu ABI.

Developing

Run make lint and make test before sending changes. Setup, the full test matrix, native link modes, version bumps, and the release process are documented in CONTRIBUTING.md. Questions, bug reports, and pull requests are welcome on GitHub.

Versioning

Release tags encode the bundled DataFusion version as v<major>.<encoded-datafusion-version>.<patch>: DataFusion 53.1.0 encodes as 530100, so v0.530100.1 bundles DataFusion 53.1.0. Release metadata is maintained in versions.toml; the version-bump and release workflow is documented in CONTRIBUTING.md.

License

Licensed under the Apache License, Version 2.0.

Documentation

Overview

Package datafusion provides a database/sql driver backed by Apache DataFusion.

The driver registers as "datafusion". It is intended for in-process analytic SQL over DataFusion's memory/session catalog and Arrow execution engine. Standard database/sql row scanning is supported for scalar Arrow types, and QueryArrowContext exposes native Arrow record batches for callers that need exact Arrow schemas or complex values. RegisterArrowReader registers Go Arrow record readers as DataFusion in-memory tables.

Index

Constants

View Source
const (
	// DataFusionVersion is the exact Rust datafusion crate version pinned by this release.
	DataFusionVersion = "53.1.0"

	// DataFusionVersionEncoded is used in Go module tags: v<major>.<encoded-datafusion-version>.<patch>.
	DataFusionVersionEncoded = "530100"

	// DataFusionGoMajor is the major component of datafusion-go release tags.
	DataFusionGoMajor = 0

	// DataFusionGoPatch is the patch component of datafusion-go release tags.
	DataFusionGoPatch = 2

	// DataFusionGoVersion is the full datafusion-go module version without the leading v.
	DataFusionGoVersion = "0.530100.2"
)

Variables

View Source
var (
	// ErrNativeCancelled matches errors caused by native query cancellation.
	ErrNativeCancelled = errors.New("datafusion native query canceled")
	// ErrNativeInvalidArgument matches native invalid-argument errors.
	ErrNativeInvalidArgument = errors.New("datafusion native invalid argument")
	// ErrNativeFailure matches uncategorized native DataFusion failures.
	ErrNativeFailure = errors.New("datafusion native failure")
	// ErrNativePanic matches panics caught on the Rust side of the FFI boundary.
	ErrNativePanic = errors.New("datafusion native panic")
)

Functions

func ExecStatements

func ExecStatements(ctx context.Context, execer SQLExecerContext, statements []string) error

ExecStatements executes already-split SQL statements in order.

DataFusion prepares exactly one SQL statement at a time, so callers handling migration files should split the script before calling this helper.

func RegisterArrowReader

func RegisterArrowReader(ctx context.Context, sqlConn *sql.Conn, tableName string, reader array.RecordReader) error

RegisterArrowReader registers the remaining batches in reader as a DataFusion in-memory table visible to SQL executed on sqlConn.

This safe path serializes the reader to an Arrow IPC stream and lets the native side decode that stream into Rust-owned Arrow batches. That copy is intentional: the registered table can outlive this call, while ordinary Go Arrow arrays may use Go-owned buffers that must not be retained by native code after a cgo call returns.

func RegisterArrowReaderZeroCopy

func RegisterArrowReaderZeroCopy(ctx context.Context, sqlConn *sql.Conn, tableName string, reader array.RecordReader) error

RegisterArrowReaderZeroCopy registers the remaining batches in reader as a DataFusion in-memory table by exporting reader through the Arrow C Stream Interface.

Unlike RegisterArrowReader, this path does not copy buffers into Rust-owned memory. Use it only when every exported Arrow buffer is safe for native code to retain until the registered table is dropped or the owning DataFusion session/connector is closed, for example buffers allocated with Arrow Go's mallocator or another C/foreign allocator. Passing ordinary Go-allocated Arrow buffers can violate cgo pointer lifetime rules because DataFusion keeps table batches after this call returns.

Types

type ArrowReader

type ArrowReader interface {
	arrio.Reader
	Schema() *arrow.Schema
	Close() error
}

ArrowReader streams Arrow record batches returned by DataFusion.

Callers must close the reader when they are done with it. Close cancels any in-flight native execution and releases native Arrow stream resources.

func QueryArrowContext

func QueryArrowContext(ctx context.Context, sqlConn *sql.Conn, query string, args ...any) (ArrowReader, error)

QueryArrowContext runs query on a DataFusion *sql.Conn and returns Arrow record batches without converting them through database/sql values.

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn is a single database/sql driver connection to a DataFusion SessionContext.

func (*Conn) Begin

func (conn *Conn) Begin() (driver.Tx, error)

Begin returns an unsupported error because DataFusion transactions are not supported.

func (*Conn) BeginTx

func (conn *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error)

BeginTx returns an unsupported error after honoring an already-canceled context.

func (*Conn) CheckNamedValue

func (conn *Conn) CheckNamedValue(nv *driver.NamedValue) error

CheckNamedValue normalizes DataFusion-specific parameter wrapper types.

func (*Conn) Close

func (conn *Conn) Close() error

Close releases the native connection handle.

func (*Conn) ExecContext

func (conn *Conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error)

ExecContext executes a statement and returns a database/sql result.

func (*Conn) IsValid

func (conn *Conn) IsValid() bool

IsValid reports whether the connection can be reused by database/sql.

func (*Conn) Ping

func (conn *Conn) Ping(ctx context.Context) error

Ping validates that the connection is open.

func (*Conn) Prepare

func (conn *Conn) Prepare(query string) (driver.Stmt, error)

Prepare validates and prepares query using a background context.

func (*Conn) PrepareContext

func (conn *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error)

PrepareContext validates and prepares query.

func (*Conn) QueryArrowContext

func (conn *Conn) QueryArrowContext(ctx context.Context, query string, args []driver.NamedValue) (ArrowReader, error)

QueryArrowContext executes a query and returns Arrow record batches.

func (*Conn) QueryContext

func (conn *Conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error)

QueryContext executes a query and adapts Arrow record batches to database/sql rows.

func (*Conn) ResetSession

func (conn *Conn) ResetSession(ctx context.Context) error

ResetSession resets isolated sessions and validates shared sessions for pool reuse.

type Connector

type Connector struct {
	// contains filtered or unexported fields
}

Connector owns the native DataFusion database handle used to open pooled connections.

func NewConnector

func NewConnector(dsn string, initFn func(driver.ExecerContext) error) (*Connector, error)

NewConnector creates a DataFusion connector for database/sql.

func NewConnectorWithInitContext

func NewConnectorWithInitContext(dsn string, initFn func(context.Context, driver.ExecerContext) error, options ...ConnectorOption) (*Connector, error)

NewConnectorWithInitContext creates a DataFusion connector with an optional initialization callback and connector options.

func (*Connector) Close

func (c *Connector) Close() error

Close releases the connector's DataFusion database resources.

func (*Connector) Connect

func (c *Connector) Connect(ctx context.Context) (driver.Conn, error)

Connect opens a new DataFusion connection.

func (*Connector) Driver

func (c *Connector) Driver() driver.Driver

Driver returns the database/sql driver used by the connector.

type ConnectorOption

type ConnectorOption func(*connectorOptions)

ConnectorOption configures a DataFusion connector.

func WithSharedSession

func WithSharedSession(shared bool) ConnectorOption

WithSharedSession controls whether connections from one Connector share a DataFusion SessionContext.

type Date

type Date struct {
	// contains filtered or unexported fields
}

Date binds a parameter as an Arrow Date32 value.

func DateFromTime

func DateFromTime(t time.Time) Date

DateFromTime returns a Date using t's calendar date in t's location.

func (Date) Days

func (value Date) Days() int32

Days returns the Arrow Date32 day count since the Unix epoch.

func (Date) Time

func (value Date) Time() time.Time

Time returns the date as a UTC time at midnight.

type Decimal

type Decimal struct {
	// contains filtered or unexported fields
}

Decimal binds a parameter as an Arrow Decimal128 value.

func DecimalString

func DecimalString(value string, precision uint8, scale int8) Decimal

DecimalString returns a Decimal parameter from a base-10 string, precision, and scale.

func NewDecimalString

func NewDecimalString(value string, precision uint8, scale int8) (Decimal, error)

NewDecimalString validates and returns a Decimal parameter from a base-10 string, precision, and scale.

func (Decimal) Precision

func (value Decimal) Precision() uint8

Precision returns the Arrow decimal precision.

func (Decimal) Scale

func (value Decimal) Scale() int8

Scale returns the Arrow decimal scale.

func (Decimal) String

func (value Decimal) String() string

String returns the decimal value's base-10 representation.

type Driver

type Driver struct{}

Driver implements database/sql/driver.Driver for DataFusion.

func (Driver) Open

func (d Driver) Open(dsn string) (driver.Conn, error)

func (Driver) OpenConnector

func (Driver) OpenConnector(dsn string) (driver.Connector, error)

type Duration

type Duration struct {
	// contains filtered or unexported fields
}

Duration binds a parameter as an Arrow duration with nanosecond precision.

func DurationFromTime

func DurationFromTime(d time.Duration) Duration

DurationFromTime returns a Duration from a Go time.Duration.

func DurationNanos

func DurationNanos(nanoseconds int64) Duration

DurationNanos returns a Duration from nanoseconds.

func (Duration) Duration

func (value Duration) Duration() time.Duration

Duration returns the value as a Go time.Duration.

func (Duration) Nanoseconds

func (value Duration) Nanoseconds() int64

Nanoseconds returns the duration as nanoseconds.

type Error

type Error struct {
	// Type identifies the driver operation that failed.
	Type ErrorType
	// NativeKind identifies native DataFusion failures when available.
	NativeKind NativeErrorKind
	// Message is the driver-level error message.
	Message string
	// Cause is the wrapped native or lower-level error.
	Cause error
}

Error is the structured error type returned by this driver.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Is

func (e *Error) Is(target error) bool

func (*Error) Unwrap

func (e *Error) Unwrap() error

type ErrorType

type ErrorType string

ErrorType identifies the operation that failed.

const (
	// ErrorConnect marks failures while opening a database or connection.
	ErrorConnect ErrorType = "connect"
	// ErrorPrepare marks failures while parsing or preparing SQL.
	ErrorPrepare ErrorType = "prepare"
	// ErrorBind marks failures while binding SQL parameters.
	ErrorBind ErrorType = "bind"
	// ErrorExecute marks failures while executing SQL or reading result batches.
	ErrorExecute ErrorType = "execute"
	// ErrorScan marks failures while adapting Arrow values to database/sql rows.
	ErrorScan ErrorType = "scan"
	// ErrorClosed marks use of a closed connector, connection, statement, or reader.
	ErrorClosed ErrorType = "closed"
	// ErrorUnsupported marks operations DataFusion does not support through this driver.
	ErrorUnsupported ErrorType = "unsupported"
	// ErrorNative marks uncategorized native FFI failures.
	ErrorNative ErrorType = "native"
)

type NativeErrorKind

type NativeErrorKind string

NativeErrorKind is the stable public classification for native DataFusion errors.

const (
	// NativeErrorKindCancelled indicates a query canceled through context cancellation.
	NativeErrorKindCancelled NativeErrorKind = "cancelled"
	// NativeErrorKindInvalidArgument indicates invalid SQL, parameters, or API input.
	NativeErrorKindInvalidArgument NativeErrorKind = "invalid_argument"
	// NativeErrorKindNative indicates an uncategorized native DataFusion failure.
	NativeErrorKindNative NativeErrorKind = "native"
	// NativeErrorKindPanic indicates a panic caught on the Rust side of the FFI boundary.
	NativeErrorKindPanic NativeErrorKind = "panic"
)

type Null

type Null struct {
	// contains filtered or unexported fields
}

Null binds a typed null parameter.

func NullDecimal

func NullDecimal(precision uint8, scale int8) Null

NullDecimal returns a typed decimal null.

func NullOf

func NullOf(typ ParameterType) Null

NullOf returns a typed null for non-decimal parameter types.

func NullTimestamp

func NullTimestamp(timeZone string) Null

NullTimestamp returns a typed timestamp null with an explicit Arrow time zone string.

func (Null) Precision

func (value Null) Precision() uint8

Precision returns the decimal precision for decimal typed nulls.

func (Null) Scale

func (value Null) Scale() int8

Scale returns the decimal scale for decimal typed nulls.

func (Null) TimeZone

func (value Null) TimeZone() string

TimeZone returns the Arrow timestamp timezone string for timestamp typed nulls.

func (Null) Type

func (value Null) Type() ParameterType

Type returns the typed-null parameter type.

type ParameterType

type ParameterType int

ParameterType names a DataFusion scalar type for typed null parameters.

const (
	// ParameterBool identifies a boolean parameter.
	ParameterBool ParameterType = iota + 1
	// ParameterInt64 identifies a signed 64-bit integer parameter.
	ParameterInt64
	// ParameterUInt64 identifies an unsigned 64-bit integer parameter.
	ParameterUInt64
	// ParameterFloat64 identifies a 64-bit floating point parameter.
	ParameterFloat64
	// ParameterString identifies a UTF-8 string parameter.
	ParameterString
	// ParameterBinary identifies a binary parameter.
	ParameterBinary
	// ParameterDate identifies an Arrow Date32 parameter.
	ParameterDate
	// ParameterTime identifies an Arrow Time64 nanosecond parameter.
	ParameterTime
	// ParameterTimestamp identifies an Arrow timestamp parameter.
	ParameterTimestamp
	// ParameterDuration identifies an Arrow duration nanosecond parameter.
	ParameterDuration
	// ParameterDecimal identifies an Arrow Decimal128 parameter.
	ParameterDecimal
)

type RegisteredTable added in v0.530100.2

type RegisteredTable struct {
	// contains filtered or unexported fields
}

RegisteredTable is a handle to a table registered on a connection by RegisterFFITableProvider. Call Deregister to remove the table before the producing library tears down. The handle is safe for concurrent use.

The table's lifetime follows the session it was registered on, not this handle. With an isolated session (WithSharedSession(false)) the table lives only as long as sqlConn, so closing that *sql.Conn also releases it. With a shared session (the default) it is registered on the connector's shared SessionContext and outlives sqlConn: it persists until Deregister is called or the owning Connector is closed, and closing sqlConn alone does not release it.

Dropping the handle never deregisters the table: a caller may legitimately keep querying it after dropping the handle. Deregistration is therefore always explicit.

func RegisterFFITableProvider added in v0.530100.2

func RegisterFFITableProvider(ctx context.Context, sqlConn *sql.Conn, tableName string, provider unsafe.Pointer, providerDataFusionVersion string) (*RegisteredTable, error)

RegisterFFITableProvider registers a foreign datafusion-ffi FFI_TableProvider, produced by another library, as a queryable table named tableName on the DataFusion connection backing sqlConn. Once registered, SQL executed on sqlConn can scan the table, and projection/filter predicates are pushed down into the foreign provider.

The table is registered on sqlConn's session, following the usual session semantics: with WithSharedSession it is registered on the shared session and is therefore visible to every connection sharing it, not just sqlConn.

provider must point to a valid, initialized datafusion-ffi FFI_TableProvider that is owned by the producing foreign library — memory allocated by that library (C/Rust), not Go heap memory. Registration clones callback pointers out of the provider and native code invokes them long after this call returns, so passing a Go-allocated pointer would violate cgo's pointer-passing rules and risk corruption once Go's garbage collector moves or frees it. providerDataFusionVersion is the datafusion version the library that produced provider was built against; obtain it from that library (not from DataFusionVersion). Registration fails with an error if it does not equal this package's DataFusionVersion — the two sides must link the same datafusion version for the provider's memory layout to be compatible. This check happens before provider is dereferenced, so a version mismatch is a clean error rather than a crash; it is cooperative and cannot detect a mislabeled provider.

Lifetime: registration clones the provider (bumping its internal refcount), so the caller still owns the original FFI_TableProvider pointer and may free it through its producing library once this call returns. The producing library itself, however, must stay loaded for as long as the table remains registered (see RegisteredTable for exactly when that ends): the registered table calls back into the provider's function pointers on every scan, and unloading the library leaves them dangling. The DataFusion session backing the provider should also outlive the registration; if it does not, queries against the table fail with a clean error rather than crashing.

func (*RegisteredTable) Deregister added in v0.530100.2

func (t *RegisteredTable) Deregister(ctx context.Context) error

Deregister removes the table from the session it was registered on. Under WithSharedSession that is the shared session, so the table is removed for every connection sharing it, not just sqlConn. Calling it more than once is a no-op that returns nil, and deregistering a name that is no longer registered is not an error.

With an isolated session, closing the underlying *sql.Conn already releases the table, so an explicit Deregister is only needed to remove it sooner. With a shared session (the default) the table lives on the shared SessionContext, so closing sqlConn does not release it: Deregister (or closing the owning Connector) is required. Deregister runs on sqlConn, so it must still be open; like the other connection operations in this package, Deregister on a closed connection propagates the error database/sql reports (sql.ErrConnDone) rather than masking it.

func (*RegisteredTable) Name added in v0.530100.2

func (t *RegisteredTable) Name() string

Name returns the table name this handle refers to.

type SQLExecerContext

type SQLExecerContext interface {
	ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
}

SQLExecerContext is implemented by *sql.DB, *sql.Conn, and *sql.Tx.

type Stmt

type Stmt struct {
	// contains filtered or unexported fields
}

Stmt is a prepared DataFusion statement.

func (*Stmt) CheckNamedValue

func (s *Stmt) CheckNamedValue(nv *driver.NamedValue) error

CheckNamedValue normalizes DataFusion-specific parameter wrapper types.

func (*Stmt) Close

func (s *Stmt) Close() error

Close releases the native prepared statement handle.

func (*Stmt) Exec

func (s *Stmt) Exec(args []driver.Value) (driver.Result, error)

Exec executes the statement with positional driver values.

func (*Stmt) ExecContext

func (s *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error)

ExecContext executes the statement with normalized named values.

func (*Stmt) NumInput

func (s *Stmt) NumInput() int

NumInput returns the number of SQL parameters found while preparing the statement.

func (*Stmt) Query

func (s *Stmt) Query(args []driver.Value) (driver.Rows, error)

Query executes the statement with positional driver values.

func (*Stmt) QueryContext

func (s *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error)

QueryContext executes the statement with normalized named values.

type Time

type Time struct {
	// contains filtered or unexported fields
}

Time binds a parameter as an Arrow Time64 nanosecond value.

func NewTimeNanos

func NewTimeNanos(nanoseconds int64) (Time, error)

NewTimeNanos validates and returns a Time from nanoseconds since midnight.

func TimeFromTime

func TimeFromTime(t time.Time) Time

TimeFromTime returns a Time using only t's clock fields in t's location.

func TimeNanos

func TimeNanos(nanoseconds int64) Time

TimeNanos returns a Time from nanoseconds since midnight.

func (Time) Nanoseconds

func (value Time) Nanoseconds() int64

Nanoseconds returns the nanoseconds since midnight.

func (Time) Time

func (value Time) Time() time.Time

Time returns the clock value as a UTC time on the Unix epoch date.

type Timestamp

type Timestamp struct {
	// contains filtered or unexported fields
}

Timestamp binds a parameter as an Arrow timestamp with nanosecond precision.

func TimestampFromTime

func TimestampFromTime(t time.Time) Timestamp

TimestampFromTime returns a UTC timestamp parameter for t.

func TimestampWithTimeZone

func TimestampWithTimeZone(t time.Time, timeZone string) Timestamp

TimestampWithTimeZone returns a timestamp parameter with an explicit Arrow time zone string.

func (Timestamp) Time

func (value Timestamp) Time() time.Time

Time returns the timestamp value.

func (Timestamp) TimeZone

func (value Timestamp) TimeZone() string

TimeZone returns the Arrow timestamp timezone string.

type UInt64

type UInt64 uint64

UInt64 binds a parameter as an unsigned 64-bit integer.

func (UInt64) Uint64

func (value UInt64) Uint64() uint64

Uint64 returns the parameter value as a uint64.

Directories

Path Synopsis
examples
arrow command
parameters command
simple command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL