C API Reference
The public C API is declared in src/dl.h. All value arrays are
u32 (raw integers or interned symbol ids). The handle type is the opaque
dl_db. This page documents the complete surface, grouped by
area. See also Order Statistics and
Time Travel for the larger feature groups.
Lifecycle
dl_db *dl_open(const char *dir) | Open or create a database directory. Returns NULL on error. |
void dl_close(dl_db *db) | Close the database, flushing and saving state. |
dl_db *dl_open2(const char *dir, int *err_out) | Open with explicit error reporting. On failure sets *err_out (see DL_E_LOCKED) and returns NULL. |
Schema
int dl_declare_relation(dl_db *db, const char *name, uint8_t arity) | Declare a fixed-arity relation (1–8). Idempotent; arity 0 declares a variadic relation. |
int dl_declare_relation_variadic(dl_db *db, const char *name) | Declare a variadic relation: facts of any arity 1–8 are accepted, stored per-arity. |
Facts
int dl_load_facts(dl_db *db, const char *rel, const char *csv_path) | Load ground facts from a headerless CSV (quoted strings interned; bare integers raw u32). Returns facts loaded, or -1. |
int dl_add_fact(dl_db *db, const char *rel, const uint32_t *cols, uint8_t arity) | Add a single fact (durable WAL + fsync). Returns 1 added / 0 duplicate / -1 error. |
int dl_delete_fact(dl_db *db, const char *rel, const uint32_t *cols, uint8_t arity) | Delete a single fact. Returns 1 deleted / 0 absent / -1 error. |
Queries
int dl_lookup(dl_db *db, const char *rel, const uint32_t *cols, uint8_t arity) | Exact lookup. Returns 1 if present, else 0. |
typedef int (*dl_tuple_cb)(const uint32_t *cols, uint8_t arity, void *user) | Tuple enumeration callback; return non-zero to stop early. |
long dl_prefix(dl_db *db, const char *rel, const uint32_t *leading, uint8_t k, dl_tuple_cb cb, void *user) | Bind the first k columns and enumerate matching tuples. Returns count, or -1. |
long dl_query(dl_db *db, const char *goal_rel, dl_tuple_cb cb, void *user) | Stream the goal relation’s tuples. Reads mmap snapshot if published, else runs the VM. Returns tuple count, or -1. |
long dl_query_bound(dl_db *db, const char *goal_rel, const uint32_t *leading, uint8_t k, dl_tuple_cb cb, void *user) | Prefix-bind k columns of the goal and enumerate. |
long dl_pattern(dl_db *db, const char *rel, const struct regex_dfa *dfa, dl_tuple_cb cb, void *user) | Enumerate tuples whose full key matches a compiled regex DFA. |
Iterator + merge-join
A resumable pull-based cursor over the tuples of a relation in ascending key order (u32BE key encoding ⇒ numeric order == lex order). Reads from the mmap snapshot view when a snapshot is current, else the in-memory relation.
dl_iter *dl_iter_open(dl_db *db, const char *rel, const uint32_t *leading, uint8_t k) | Open a cursor bound to the first k leading columns (k==0: all). Returns NULL on error; an absent prefix yields a valid empty iterator. |
int dl_iter_seek(dl_iter *it, const uint32_t *leading, uint8_t k) | Re-bind the cursor to a new leading prefix. Returns 0 / -1. |
int dl_iter_next(dl_iter *it, uint32_t *cols_out) | Fetch the next tuple ascending. Returns 1 / 0 at end / -1 error. |
uint8_t dl_iter_arity(const dl_iter *it) | The relation’s arity (0 for a NULL/error cursor). |
void dl_iter_close(dl_iter *it) | Close the cursor (NULL-safe). |
typedef int (*dl_join_cb)(const uint32_t *l, uint8_t la, const uint32_t *r, uint8_t ra, void *user) | Merge-join pair callback. |
long dl_merge_join(dl_iter *l, dl_iter *r, uint8_t jcols, dl_join_cb cb, void *user) | Equi-join two sorted iterators on their first jcols columns, streaming pairs in sorted order (cross-product semantics, duplicates preserved). Both iterators left exhausted. Returns pairs emitted, or -1. |
Order statistics
uint64_t dl_rank(dl_db *db, const char *rel, const uint32_t *cols, uint8_t arity) | Number of distinct tuples strictly lexicographically smaller than cols. UINT64_MAX on error. |
int dl_select(dl_db *db, const char *rel, uint64_t k, uint32_t *cols_out, uint8_t arity) | The k-th tuple (0-indexed, lex order). Returns 0 / -1. |
uint64_t dl_range_count(dl_db *db, const char *rel, const uint32_t *lo, const uint32_t *hi, uint8_t arity) | Number of distinct tuples in the half-open range [lo, hi) = rank(hi) − rank(lo). |
uint64_t dl_count(dl_db *db, const char *rel) | O(1) distinct-tuple count (memoized subtree array). |
uint64_t dl_rank_bound(db, rel, leading, k, cols, arity) | Rank restricted to tuples whose first k columns equal leading. |
int dl_select_bound(db, rel, leading, k, idx, cols_out, arity) | Select within a leading-prefix bound. |
uint64_t dl_range_count_bound(db, rel, leading, k, lo, hi, arity) | Range count within a leading-prefix bound. |
uint64_t dl_rank_perm(db, rel, perm_id, cols, arity) | Rank over a permuted view (order-by on a non-leading column). |
int dl_select_perm(db, rel, perm_id, k, cols_out, arity) | Select over a permuted view (inverse-maps the result back to original column order). |
uint64_t dl_range_count_perm(db, rel, perm_id, lo, hi, arity) | Range count over a permuted view. |
int dl_db_perm_count(const dl_db *db) | Number of permutation indices currently declared. |
Details and examples are on the Order Statistics page.
Rules
int dl_load_rules(dl_db *db, const char *dl_source) | Parse and compile Datalog rules from a source string. Returns 0 / -1. Rules may reference existing relations or declare new derived relations. |
int dl_compile(dl_db *db) | Compile all loaded rules into bytecode and run them (semi-naive fixpoint), materializing derived relations. Returns 0 / -1. |
long dl_query_magic(db, goal_rel, leading, k, cb, user) | Magic-sets bound query (leading/k). Re-evaluates a scoped fixpoint; result is byte-identical to dl_query_bound. Returns count, or -1. |
long dl_query_magic_adorn(db, goal_rel, adorn, vals, nvals, cb, user) | Magic-sets with an arbitrary adornment string of b/f chars. |
long dl_query_topdown(db, goal_rel, leading, k, cb, user) | Top-down / QSQ: the same adorned magic program, scheduled demand-driven (SLG worklist) instead of forward semi-naive. C-API only — no CLI command. |
long dl_query_topdown_adorn(db, goal_rel, adorn, vals, nvals, cb, user) | Top-down / QSQ with an arbitrary adornment. |
Snapshot
int dl_publish_snapshot(dl_db *db) | Atomically save the interner + all relations to a versioned snapshot directory and flip the CURRENT pointer. After publish, dl_query reads from mmap. |
Time-travel / as-of
long dl_snapshot_versions(const dl_db *db, uint32_t *out, size_t cap) | Enumerate every published snapshot version ascending. Returns the total (two-call idiom). |
long dl_query_version(dl_db *db, uint32_t version, const char *goal_rel, dl_tuple_cb cb, void *user) | As-of query: stream tuples as of snapshot version, bypassing live routing. Nonexistent version / absent relation is a loud -1, never a silent empty result. |
long dl_query_bound_version(dl_db *db, uint32_t version, const char *goal_rel, const uint32_t *leading, uint8_t k, dl_tuple_cb cb, void *user) | As-of prefix query. |
int dl_set_snapshot_retain(dl_db *db, unsigned n) | Opt-in retention: keep at most n most-recent versions, pruning older ones after each publish. n==0 (default) keeps every version. |
Details and examples are on the Time Travel page.
Fault-injection hooks (test-only)
void dl_set_fault_hook(dl_db *db, int (*hook)(dl_fpoint fp, void *user), void *user) | Install a fault-injection hook called at each fpoint during publish (DL_FPOINT_AFTER_REL_SAVE, DL_FPOINT_AFTER_RENAME) and during a transaction commit (DL_FPOINT_TXN_BEFORE_MARKER); non-zero aborts the publish/commit. |
Interner
uint32_t dl_intern_str(dl_db *db, const char *str) | Intern a string, return its sym_id (1-based). Returns 0 on OOM. |
const char *dl_intern_str_of(dl_db *db, uint32_t sym_id) | Look up a sym_id → string. Returns NULL if out of range. |