Skip to main content
DuckDB is an in-process OLAP SQL engine. better-duck embeds it (compiled straight into your binary — see Architecture) and talks to its C API. This page is a short orientation to the engine behaviors that matter when you drive DuckDB from Rust, with links to the focused pages that cover each in depth.

SQL dialect & statements

The PostgreSQL-like dialect and analytics extras, batch vs single statements, parameters, and transactions.

Type system

Every DuckDB type as a DuckValue, NULL and validity, the lossless TypeInfo, and feature-dependent read types.

Extensions

Bundled at build time (json / parquet / icu) vs loaded at runtime (spatial and more).

Error handling

How failures surface, DuckDB’s typed EngineError, and the panic = "abort" caveat.

The one-page tour

  • Dialect. DuckDB’s SQL is PostgreSQL-like with analytics extras — QUALIFY, GROUP BY ALL, SELECT * EXCLUDE (...), COLUMNS(...), list/struct/map literals, UNNEST, PIVOT, and friendly casting (x::t, TRY_CAST). Full tour on SQL dialect.
  • Statements. execute_batch runs many ;-separated statements (DuckDB does the parsing); a single execute prepares and runs one. SELECT / RETURNING yield rows, DML reports a changes() count, DDL changes nothing.
  • Parameters. Positional ($1, ?) via execute_with, named ($name) via execute_with_named. See parameters.
  • Types. Values arrive as DuckValue, covering every integer width, DECIMAL, UUID, BIT, BIGNUM, temporals, and the composite LIST / ARRAY / STRUCT / MAP / UNION / ENUM. The read type for temporals/decimals/UUID depends on feature flags.
  • NULL. First-class — DuckValue::Null, a per-column validity bitmask in columnar access, and Option<T> round-tripping.
  • Extensions. Either bundled at build time (no runtime install) or loaded at runtime via the extension API.
  • Transactions. Driven as SQL (BEGIN / COMMIT / ROLLBACK) — no savepoints. See transactions.

Two engine behaviors worth memorizing

Row mode vs chunk mode — do not mix. A DuckResult is consumed either row-by-row (next / exists / count / materialize) or chunk-by-chunk (fetch_chunk, feature columnar) — never both. Mixing them yields Error::MixedIterationMode. See columnar access.
A failed appender flush is unrecoverable. DuckDB invalidates the Appender on a failed flush and the buffered data is lost; the appender poisons and refuses further calls. See error handling.

DuckDB version

better-duck pins a specific vendored DuckDB in better-duck-sys; better_duck_core::library_version() returns the linked version string at runtime (e.g. "v1.5.5"). See Versioning & compatibility.

Queries, Results & Values

The DuckValue type, parameter binding, and result metadata in depth.

Appender

Bulk ingest and the data-chunk path.