Skip to content

rupurt/duckdb-extension-template-zig

Repository files navigation

duckdb-extension-template-zig

A Zig & Nix toolkit template for building extensions against multiple versions of DuckDB using Zig, C or C++.

Usage

> nix develop -c $SHELL
> duckdb -unsigned
D LOAD 'zig-out/lib/quack.duckdb_extension';
D FROM duckdb_extensions();
┌──────────────────┬─────────┬───────────┬──────────────┬────────────────────────────────────────────────────────────────────────────────────┬───────────────────┐
│  extension_name  │ loaded  │ installed │ install_path │                                    description                                     │      aliases      │
│     varchar      │ boolean │  boolean  │   varchar    │                                      varchar                                       │     varchar[]     │
├──────────────────┼─────────┼───────────┼──────────────┼────────────────────────────────────────────────────────────────────────────────────┼───────────────────┤
│ arrow            │ falsefalse     │              │ A zero-copy data integration between Apache Arrow and DuckDB                       │ []                │
...
│ quack            │ true    │           │              │                                                                                    │ []                │
...
│ visualizer       │ true    │           │              │ Creates an HTML-based visualization of the query plan                              │ []                │
├──────────────────┴─────────┴───────────┴──────────────┴────────────────────────────────────────────────────────────────────────────────────┴───────────────────┤
│ 24 rows                                                                                                                                              6 columns │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
D FROM duckdb_extensions();
> WHERE function_name ILIKE '%quack%';
┌───────────────┬─────────────┬───────────────┬───────────────┬─────────────┬─────────────┬───┬─────────┬──────────────────┬──────────────────┬──────────┬──────────────┬─────────┐
│ database_name │ schema_name │ function_name │ function_type │ description │ return_type │ … │ varargs │ macro_definition │ has_side_effects │ internal │ function_oid │ example │
│    varchar    │   varchar   │    varchar    │    varchar    │   varchar   │   varchar   │   │ varchar │     varchar      │     boolean      │ boolean  │    int64     │ varchar │
├───────────────┼─────────────┼───────────────┼───────────────┼─────────────┼─────────────┼───┼─────────┼──────────────────┼──────────────────┼──────────┼──────────────┼─────────┤
│ system        │ main        │ quack         │ scalar        │             │ VARCHAR     │ … │         │                  │ falsetrue     │         1473 │         │
├───────────────┴─────────────┴───────────────┴───────────────┴─────────────┴─────────────┴───┴─────────┴──────────────────┴──────────────────┴──────────┴──────────────┴─────────┤
│ 1 rows                                                                                                                                                    14 columns (12 shown) │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
D SELECT quack('howdy');
┌────────────────┐
│ quack('howdy') │
│    varchar     │
├────────────────┤
│ Quack howdy 🐥 │
└────────────────┘

How it Works

DuckDB is a fast in-process analytical database written in C++ that can be extended by creating and loading a dynamically linked library using the extension API. Typically extensions are written in C++ using the officially supported extension template.

But you're one of the cool kids and want to write your extension in Zig! Fortunately the Zig build system ships with a Zig, C & C++ compiler.

1. Create a project directory initialized with the multi flake template

The Nix environment generated by the flake.nix template provides a self contained Linux & MacOS development toolchain:

  • Clang (16.0.6)
  • libcxx headers (16.0.6)
  • Zig master (0.12.0-dev.3247+26e895e3d)
  • Multiple duckdb CLI & libduckdb versions linked to the same versions of libc & libcxx as the Zig compiler (v0.10.0, v0.9.2 & main)
> mkdir myextension && cd myextension
> nix flake init -t github:rupurt/duckdb-extension-template-zig#multi
> nix develop -c $SHELL

2. Implement 2 extension loader functions

When a DuckDB extension is loaded via LOAD 'myextension.duckdb_extension'; it requires 2 symbols to be defined (myextension_version & myextension_init). The value returned from *_init must match the version of DuckDB loading the extension.

We create a simple header file to expose these 2 symbols in our built extension.

3. Create a C++ bridge that calls DuckDB::ExtensionUtil

The extension utils helper plugs into DuckDB internals such as:

  • scalar functions
  • table functions
  • custom catalogs
  • much more...

The example in this repository registers a simple scalar function called quack

4. Configure the Zig build system and compile the extension

The Zig build system is configured in build.zig.

  • We'll need to add a shared library exposing the DuckDB extension hooks defined in root.zig.
  • Add the include path for the C header file exposing these hooks.
  • Don't forget the C++ bridge
  • By convention DuckDB extensions use the file suffix .duckdb_extension. Zig writes the dynamic library using the format libmyextension.[so|dylib|dll]. Add a custom install step to use the DuckDB naming convention for the extension filename.

Limitations

Currently this template can only build extensions using versions of duckdb provided by the duckdb-nix flake. The derivation built by the flake includes header files for duckdb third_party dependencies.

I have opened a Github issue to include those libraries in the nixpkgs derivation.

Development

This repository assumes you have Nix installed

> nix develop -c $SHELL
> nix develop .#v0-10-0 -c $SHELL
> nix develop .#v0-9-2 -c $SHELL
> nix develop .#main -c $SHELL
> make

Run the Zig test suite

> make test

Delete artifacts from previous builds

> make clean

Build extension binary with Zig

> make build

Run duckdb cli allowing -unsigned extensions

> make run

License

duckdb-extension-template-zig is released under the MIT license