快速开始
本页从零构建一个名为 my_ext 的最小扩展。本仓库自带的示例扩展是 duckfn,覆盖了全部功能,
见示例扩展。
如果想直接从带 CI 的可用骨架起步,见创建项目。
整条流程就是下面四步:
1. 创建 crate
Cargo.toml
[package]
name = "my_ext"
version = "0.1.0"
edition = "2024"
rust-version = "1.86"
[lib]
crate-type = ["cdylib"]
[dependencies]
duckfn = "0.0.18"
quack-rs = "0.16.0"
libduckdb-sys = { version = ">=1.4.4, <2", features = ["loadable-extension"] }
2. 编写扩展
src/lib.rs
use duckfn::{duck_error, duck_scalar_function, duckfn_entrypoint, DuckOptionResult};
#[duck_scalar_function]
pub fn double_it(v: Option<i64>) -> DuckOptionResult<i64> {
if v == Some(13) {
return Err(duck_error("unlucky input"));
}
Ok(v.map(|x| x * 2))
}
duckfn_entrypoint!("my_ext");
有三个方面值得留意:
- 属性同时完成了注册与 FFI 包装的生成,没有单独的手动注册步骤。
- 入参
Option<i64>、出参DuckOptionResult<i64>是表达NULL的方式。完整的返回形态见 错误与 panic。 duckfn_entrypoint!("my_ext")必须与扩展名一致,见下文。
3. 构建
DuckDB 官方流程会构建 cdylib、追加扩展元数据,并把产物放到 DuckDB 期望的位置:
make configure # 只做一次:创建测试运行器所需的 Python venv
make debug # -> build/debug/extension/my_ext/my_ext.duckdb_extension
make release 是带优化的同一套流程。两者都来自本仓库引入的 DuckDB extension-ci-tools makefile。
这就是推荐的构建路径。本仓库用 Justfile 把它封装好了:just build 会跑
make configure && make debug,just sql "SELECT ..." / just repl 加载它产出的
build/debug/my_ext.duckdb_extension,所以日常命令与官方工具链就是同一条流程。
4. 加载并调用
duckdb -unsigned -c "
LOAD './build/debug/extension/my_ext/my_ext.duckdb_extension';
SELECT double_it(21);
"
42
| SQL | 结果 |
|---|---|
SELECT double_it(21); | 42 |
SELECT double_it(NULL); | NULL |
SELECT double_it(13); | 报错:unlucky input |
扩展基于 DuckDB 的 unstable C API 构建,因此必须加 -unsigned。
入口符号名称
duckfn_entrypoint!("my_ext") 生成符号 my_ext_init_c_api,这正是 DuckDB 加载扩展时查找的符号。
名称不能为空,且只能包含小写 ASCII 字母、数字和下划线;不满足会在编译期报错,而符号名写错会导致扩展无法加载。