Requires
feature = "udf". See the UDF overview for shared semantics.#[duckdb_scalar] turns a Rust function into a DuckDB scalar function — one value computed per row,
usable in a SELECT list or WHERE clause.
fn f() is rejected). An Option<T> return/parameter maps to NULL; a Result<T, E>
return fails the query on Err.
NULL handling
- A non-
Optionparameter short-circuits NULL rows: DuckDB fills the output withNULLwithout calling your body (so the slot’s value may not even be valid to read). - Any
Option<T>parameter auto-enablesspecial_handling, so your body is called for NULL inputs and decides what to do.
Options
name must be a non-empty string literal without NUL bytes; specifying name or state twice is
a compile error. The function also remains callable as a plain Rust fn.Shared state with duck_state!
With state(Type, init_expr), read a Clone copy of the shared state inside the body with
duck_state!(Type):
duck_state! panics if called outside a state-carrying scalar body
— contained by the callback machinery, so it surfaces as a normal query error. See
helper macros.
The VScalar trait
The macro implements better_duck_core::udf::VScalar. Implement it by hand when you need multiple
overloads or bind-time constant folding:
VScalar by hand
VScalar by hand
ScalarSignature is exact(params, ret) or variadic(param, ret) — each becomes a DuckDB
overload. Register with conn.register_scalar_function::<T>(name) or
register_scalar_function_with_state::<T>(name, state). ScalarBindInfo exposes the call’s
argument Expressions (argument_count, argument), the bind-time
client_context() for folding a constant argument, and set_bind_data. The execution handle
reads State / per-query BindData back. Work over
DataChunkHandle / VectorMut.See also
- UDF overview — shared semantics and the panic caveat.
- Table functions · Aggregate functions.
- Vectors — the read/write views
invokeuses.