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_pointmodule - 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
DuckDBRust 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:
| Module | Purpose |
|---|---|
entry_point | Helper for the correct {name}_init_c_api C entry point |
connection | Connection facade + Registrar trait for version-agnostic registration |
aggregate | Builders for aggregate function registration |
scalar | Builder for scalar function registration |
cast | Builder for custom type cast functions |
table | Builder for table function registration |
replacement_scan | SELECT * FROM 'file.xyz' replacement scan registration |
sql_macro | SQL macro registration (CREATE MACRO) — no FFI callbacks |
vector | Safe helpers for reading/writing DuckDB data vectors |
vector::complex | STRUCT / LIST / MAP / ARRAY vector access (child vectors, offsets) |
types | DuckDB type system wrappers (TypeId, LogicalType) |
interval | INTERVAL → microseconds conversion with overflow checking |
error | ExtensionError for FFI error propagation |
config | RAII wrapper for DuckDB database configuration |
validate | Community extension compliance validators |
validate::description_yml | Parse and validate description.yml metadata |
scaffold | Project generator for new extensions (no C++ glue needed) |
testing | Test harness for aggregate state logic |
prelude | Convenience re-exports of the most commonly used items |
catalog | Catalog entry lookup (duckdb-1-5 feature) |
client_context | Client context access (duckdb-1-5 feature) |
config_option | Extension-defined configuration options (duckdb-1-5 feature) |
copy_function | Custom COPY TO handlers (duckdb-1-5 feature) |
table_description | Table 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
- Thin wrapper: every abstraction must pay for itself in reduced boilerplate or improved safety. When in doubt, prefer simplicity.
- No panics across FFI:
unwrap()is forbidden in FFI callbacks and entry points. - Bounded version range:
libduckdb-sysuses>=1.4.4, <2to supportDuckDB1.4.x and 1.5.x (including v1.5.1) while preventing silent adoption of breaking changes in future major releases. - 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
DuckDBaggregate functions. - cast
- Builder for registering
DuckDBcustom cast functions. - config
- RAII wrapper for
DuckDBdatabase configuration. - connection
Connection— version-agnostic extension registration facade.- entry_
point - Extension entry point helper.
- error
- Error types for
DuckDBextension FFI error propagation. - interval
DuckDBINTERVALtype conversion utilities.- prelude
- Convenience re-exports for the most commonly used
quack-rsitems. - replacement_
scan - Builder for registering
DuckDBreplacement scans. - scaffold
- Project scaffolding for
DuckDBRust extensions. - scalar
- Builder for registering
DuckDBscalar functions. - sql_
macro - SQL macro registration for
DuckDBextensions. - table
- Builder for registering
DuckDBtable functions. - testing
- Test utilities for
DuckDBextension development. - types
DuckDBtype system wrappers.- validate
- Validation utilities for
DuckDBcommunity extension compliance. - vector
- Safe helpers for reading from and writing to
DuckDBdata vectors.
Macros§
- entry_
point - Generates the
#[no_mangle] unsafe extern "C"entry point for aDuckDBextension. - entry_
point_ v2 - Generates the
#[no_mangle] unsafe extern "C"entry point using the version-agnosticConnectionfacade.
Constants§
- DUCKDB_
API_ VERSION - The
DuckDBC API version string required byduckdb_rs_extension_api_init.