better-duck-core
offers two wrappers with different lifetimes, plus incremental (“pending”) execution and
multi-statement batches.
There is no
Connection::prepare. The entry point is conn.db().prepare(sql) (which returns
a borrowing Statement) or
CachedStatement::prepare(conn.db(), sql) for a
'static one. conn.db() returns the underlying raw connection the statement is prepared on.Statement — borrows the connection
conn.db().prepare(sql) returns a Statement<'a> that borrows conn. bind auto-increments
the positional index; bind_at targets a specific 1-based index; clear_bindings resets for
reuse.
CachedStatement — owns its connection
ACachedStatement holds its own handle to the connection, so it does not borrow conn, is
'static, and is freely reusable (this is the type Diesel’s statement cache stores). Binds are
1-based; bind_named targets $name; reset_bindings clears for the next run.
Statement metadata
Both wrappers expose introspection (CachedStatement shown; Statement has the same via its raw
helpers):
statement_type() -> StatementType— see below.parameter_count() -> u64,parameter_name(index) -> Option<String>,parameter_index(name) -> Result<u64>,parameter_type/parameter_logical_type.column_count() -> u64,column_name(index),column_type/column_logical_type.
StatementType (better_duck_core::StatementType) is #[non_exhaustive] and mirrors
duckdb_statement_type — Select, Insert, Update, Delete, Create, Drop, Alter,
Explain, Prepare, Execute, Transaction, Copy, Pragma, Call, Attach, Detach,
Multi, …, and Unknown(raw) for a kind this build doesn’t recognise. Match with a _ arm.
Multi-statement batches — ExtractedStatements
conn.extract_statements(sql) parses a ;-separated batch into
better_duck_core::ExtractedStatements; DuckDB does the parsing, so a semicolon inside a string
literal is not a split. Prepare a given index at most once; an out-of-range index is rejected.
len() -> u64— statements parsed;is_empty()is effectively alwaysfalse(a zero-statement extract is an error at extraction time).prepare(index) -> Result<CachedStatement>— prepare the statement atindex.
Error::Engine carrying DuckDB’s message; an interior
NUL as Error::NulError.
Incremental (task-at-a-time) execution
CachedStatement::pending() returns a PendingResult that runs the query one task at a time —
useful for cooperative scheduling or progress reporting. into_pending() yields an OwnedPending
that is Send + 'static (it owns the statement, so it carries no borrow — this is what the
async facade steps across spawn_blocking dispatches).
PendingState (better_duck_core::PendingState) is #[non_exhaustive]:
Both
PendingResult and OwnedPending expose execute_task(), error() -> Option<String>, and
execute(self) -> Result<DuckResult>.
See also
- Positional parameters · Named parameters.
- Iterating results — consuming the
DuckResultthese return. - Async —
execute_pendingis the async form of pending execution.