DuckDB C extension for in-process JIT compiled C UDFs via TinyCC — self-contained, no external runtime required
Maintainer(s):
sounkou-bioinfo
Installing and Loading
INSTALL ducktinycc FROM community;
LOAD ducktinycc;
Example
-- Load the extension
LOAD ducktinycc;
-- Compile and register a simple C function as a SQL UDF
SELECT ok, mode, code
FROM tcc_module(
mode := 'quick_compile',
source := 'const char *hello_from_c(void){ return "hello from C"; }',
symbol := 'hello_from_c',
sql_name := 'hello_from_c',
return_type := 'varchar',
arg_types := []
);
-- Call the registered C UDF
SELECT hello_from_c() AS msg;
About ducktinycc
DuckTinyCC compiles and registers C scalar UDFs from SQL using TinyCC (libtcc), in-process.
Main SQL entrypoints:
| Function | Purpose |
|---|---|
| tcc_module(…) | Session config, build staging, codegen, compile, registration |
| tcc_system_paths(…) | Show effective TinyCC include/library search paths |
| tcc_library_probe(…) | Probe candidate library files and normalized link names |
Compile/codegen and C-type helper modes (via tcc_module):
| Mode | Purpose |
|---|---|
| quick_compile | One-shot source + codegen + compile + register |
| compile | Compile/register from staged session sources/bindings |
| codegen_preview | Emit generated wrapper C source without compile/load |
| c_struct | Generate + register struct helper UDFs from field specs |
| c_union | Generate + register union helper UDFs from field specs |
| c_bitfield | Generate + register bitfield struct helper UDFs |
| c_enum | Generate + register enum constant helper UDFs |
Generated helper naming:
| Helper mode | Generated SQL function pattern |
|---|---|
| c_struct | struct_ |
| c_union | union_ |
| c_bitfield | struct_ |
| c_enum | enum_ |
Type signature support (return_type / arg_types):
| Token family | Examples |
|---|---|
| Scalars | void (return only), bool, i8/u8/i16/u16/i32/u32/i64/u64, f32/f64, ptr, varchar, blob, uuid, date, time, timestamp, interval, decimal |
| Composites (recursive) | list |
SQL <-> C bridge correspondences:
| SQL token family | C bridge type |
|---|---|
| varchar | const char * |
| blob | ducktinycc_blob_t |
| list<…>, type[] | ducktinycc_list_t |
| type[N] | ducktinycc_array_t |
| struct<…> | ducktinycc_struct_t |
| map<…> | ducktinycc_map_t |
| union<…> | ducktinycc_union_t |
| decimal | ducktinycc_decimal_t (DuckDB DECIMAL(18,3) at registration) |
Function result schemas:
| Function | Result columns |
|---|---|
| tcc_module(…) | ok BOOLEAN, mode VARCHAR, phase VARCHAR, code VARCHAR, message VARCHAR, detail VARCHAR, sql_name VARCHAR, symbol VARCHAR, artifact_id VARCHAR, connection_scope VARCHAR |
| tcc_system_paths(…) | kind VARCHAR, key VARCHAR, value VARCHAR, exists BOOLEAN, detail VARCHAR |
| tcc_library_probe(…) | kind VARCHAR, key VARCHAR, value VARCHAR, exists BOOLEAN, detail VARCHAR |
Codegen/runtime model:
- wrappers are generated from return_type/arg_types and registered through ducktinycc_register_signature(…)
- wrapper_mode supports row and batch execution paths
- code is compiled + relocated in-memory (no separate shared-library artifact)
- registering the same sql_name twice in a session returns false/E_INIT_FAILED (consistent across platforms); use tcc_new_state to reset before re-registering
Embedded runtime (self-contained):
- libtcc1.a and all TinyCC include headers (stdarg.h, stddef.h, tccdefs.h, etc.) are baked into the extension binary at build time
- on the first compile or quick_compile call, tcc_ensure_embedded_runtime() extracts them to a content-hash-keyed temp directory (e.g. /tmp/ducktinycc_
/) - subsequent calls in the same process reuse that directory without re-extracting
- no separate TinyCC installation or runtime path configuration is needed after deployment
- tcc_system_paths() shows the active runtime path and whether it resolved from the embedded extraction
Project details and examples: https://github.com/sounkou-bioinfo/DuckTinyCC
Community package excludes WASM targets.
Added Functions
| function_name | function_type | description | comment | examples |
|---|---|---|---|---|
| tcc_alloc | scalar | NULL | NULL | |
| tcc_dataptr | scalar | NULL | NULL | |
| tcc_free_ptr | scalar | NULL | NULL | |
| tcc_library_probe | table | NULL | NULL | |
| tcc_module | table | NULL | NULL | |
| tcc_ptr_add | scalar | NULL | NULL | |
| tcc_ptr_size | scalar | NULL | NULL | |
| tcc_read_bytes | scalar | NULL | NULL | |
| tcc_read_f32 | scalar | NULL | NULL | |
| tcc_read_f64 | scalar | NULL | NULL | |
| tcc_read_i16 | scalar | NULL | NULL | |
| tcc_read_i32 | scalar | NULL | NULL | |
| tcc_read_i64 | scalar | NULL | NULL | |
| tcc_read_i8 | scalar | NULL | NULL | |
| tcc_read_u16 | scalar | NULL | NULL | |
| tcc_read_u32 | scalar | NULL | NULL | |
| tcc_read_u64 | scalar | NULL | NULL | |
| tcc_read_u8 | scalar | NULL | NULL | |
| tcc_system_paths | table | NULL | NULL | |
| tcc_write_bytes | scalar | NULL | NULL | |
| tcc_write_f32 | scalar | NULL | NULL | |
| tcc_write_f64 | scalar | NULL | NULL | |
| tcc_write_i16 | scalar | NULL | NULL | |
| tcc_write_i32 | scalar | NULL | NULL | |
| tcc_write_i64 | scalar | NULL | NULL | |
| tcc_write_i8 | scalar | NULL | NULL | |
| tcc_write_u16 | scalar | NULL | NULL | |
| tcc_write_u32 | scalar | NULL | NULL | |
| tcc_write_u64 | scalar | NULL | NULL | |
| tcc_write_u8 | scalar | NULL | NULL |
Overloaded Functions
This extension does not add any function overloads.
Added Types
This extension does not add any types.
Added Settings
This extension does not add any settings.