Skip to main content

Crate quack_rs

Crate quack_rs 

Source
Expand description

§quack-rs

A production-grade Rust SDK for building DuckDB loadable extensions.

§Overview

quack-rs encapsulates the hard-won FFI knowledge required to build DuckDB community extensions in Rust. It provides:

  • A correct, panic-free entry point helper via the entry_point module
  • Type-safe builders for registering aggregate functions (aggregate)
  • Safe vector reading and writing helpers (vector)
  • A generic FfiState<T> that eliminates raw pointer management
  • Documented solutions to every known DuckDB Rust FFI pitfall

§Quick Start

// In your extension's src/lib.rs, write the entry point manually:
use quack_rs::entry_point::init_extension;

#[no_mangle]
pub unsafe extern "C" fn my_extension_init_c_api(
    info: libduckdb_sys::duckdb_extension_info,
    access: *const libduckdb_sys::duckdb_extension_access,
) -> bool {
    unsafe {
        init_extension(info, access, quack_rs::DUCKDB_API_VERSION, |con| {
            // register_my_function(con)?;
            Ok(())
        })
    }
}

§Architecture

The SDK is organized into focused modules:

ModulePurpose
callbackSafe extern "C" callback wrapper macros (scalar_callback!, table_scan_callback!)
chunk_writerAuto-sizing chunk writer for table scan callbacks (auto set_size on drop)
data_chunkErgonomic wrapper for DuckDB data chunks
entry_pointHelper for the correct {name}_init_c_api C entry point
connectionConnection facade + Registrar trait for version-agnostic registration
aggregateBuilders for aggregate function registration
scalarBuilder for scalar function registration
castBuilder for custom type cast functions
tableBuilders for table function registration (raw TableFunctionBuilder + closure-based TypedTableFunctionBuilder<S>)
replacement_scanSELECT * FROM 'file.xyz' replacement scan registration
sql_macroSQL macro registration (CREATE MACRO) — no FFI callbacks
vectorSafe helpers for reading/writing DuckDB data vectors
vector::complexSTRUCT / LIST / MAP / ARRAY vector access (child vectors, offsets)
vector::struct_readerBatched StructReader for STRUCT input vectors
vector::struct_writerBatched StructWriter for STRUCT output vectors
typesDuckDB type system wrappers (TypeId, LogicalType)
intervalINTERVAL → microseconds conversion with overflow checking
errorExtensionError for FFI error propagation
configRAII wrapper for DuckDB database configuration
valueRAII wrapper for DuckDB values with typed extraction
tlsType-erased TLS configuration provider for HTTP-capable extensions
warningStructured security warning API (ExtensionWarning, WarningCollector)
secretsSecrets manager bridge trait (SecretsManager, SecretEntry)
validateCommunity extension compliance validators
validate::description_ymlParse and validate description.yml metadata
scaffoldProject generator for new extensions (no C++ glue needed)
testingTest harness for aggregate state logic
preludeConvenience re-exports of the most commonly used items
catalogCatalog entry lookup (duckdb-1-5 feature)
client_contextClient context access (duckdb-1-5 feature)
config_optionExtension-defined configuration options (duckdb-1-5 feature)
copy_functionCustom COPY TO handlers (duckdb-1-5 feature)
table_descriptionTable metadata queries (duckdb-1-5 feature)

§Safety

All unsafe code within this SDK is sound and documented. Extension authors must write unsafe extern "C" callback functions (required by DuckDB’s C API), but the SDK’s helpers minimize the surface area of unsafe code within those callbacks. Every unsafe block inside this crate has a // SAFETY: comment explaining the invariants being upheld.

§Design Principles

  1. Thin wrapper: every abstraction must pay for itself in reduced boilerplate or improved safety. When in doubt, prefer simplicity.
  2. No panics across FFI: unwrap() is forbidden in FFI callbacks and entry points.
  3. Bounded version range: libduckdb-sys uses >=1.4.4, <2 to support DuckDB 1.4.x and 1.5.x (including v1.5.1) while preventing silent adoption of breaking changes in future major releases.
  4. Testable business logic: state structs have zero FFI dependencies.

§Pitfalls

See LESSONS.md for all 16 known DuckDB Rust FFI pitfalls, including symptoms, root causes, and fixes.

§Pitfall L1: COMBINE must propagate config fields

DuckDB’s segment tree creates fresh zero-initialized target states via state_init, then calls combine to merge source into them. This means your combine callback MUST copy ALL configuration fields from source to target — not just accumulated data. Any field that defaults to zero will be wrong at finalize time, producing silently incorrect results.

See aggregate::callbacks::CombineFn for details.

Modules§

aggregate
Builders for registering DuckDB aggregate functions.
callback
Safe callback wrapper macros for DuckDB extension callbacks.
cast
Builder for registering DuckDB custom cast functions.
chunk_writer
Auto-sizing chunk writer for table function scan callbacks.
config
RAII wrapper for DuckDB database configuration.
connection
Connection — version-agnostic extension registration facade.
data_chunk
Ergonomic wrapper around DuckDB data chunks.
entry_point
Extension entry point helper.
error
Error types for DuckDB extension FFI error propagation.
interval
DuckDB INTERVAL type conversion utilities.
prelude
Convenience re-exports for the most commonly used quack-rs items.
replacement_scan
Builder for registering DuckDB replacement scans.
scaffold
Project scaffolding for DuckDB Rust extensions.
scalar
Builder for registering DuckDB scalar functions.
secrets
Secrets manager bridge for extensions.
sql_macro
SQL macro registration for DuckDB extensions.
table
Builder for registering DuckDB table functions.
testing
Test utilities for DuckDB extension development.
tls
Type-erased TLS configuration provider for HTTP-capable extensions.
types
DuckDB type system wrappers.
validate
Validation utilities for DuckDB community extension compliance.
value
RAII wrapper around DuckDB values (duckdb_value).
vector
Safe helpers for reading from and writing to DuckDB data vectors.
warning
Structured security warning API for extensions.

Macros§

entry_point
Generates the #[no_mangle] unsafe extern "C" entry point for a DuckDB extension.
entry_point_v2
Generates the #[no_mangle] unsafe extern "C" entry point using the version-agnostic Connection facade.
scalar_callback
Generates a panic-safe unsafe extern "C" scalar function callback.
table_scan_callback
Generates a panic-safe unsafe extern "C" table function scan callback.

Constants§

DUCKDB_API_VERSION
The DuckDB C API version string required by duckdb_rs_extension_api_init.