Skip to content

C API Reference

The RockLake C ABI (rocklake.h) is the stable interface for embedding the catalog in any language ecosystem. It is consumed by:

  • The rocklake-client Rust crate (via the Rust API — no raw C required)
  • Python bindings via PyO3
  • Go bindings via cgo
  • Node.js bindings via napi-rs
  • The native DuckDB extension (v0.36.0)

The header is maintained at crates/rocklake-ffi/include/rocklake.h and generated by cbindgen in CI.


ABI Version

#define ROCKLAKE_ABI_VERSION 5000U
uint32_t rocklake_abi_version(void);

Callers MUST check the version at load time and refuse to proceed when the runtime value does not match the compile-time constant:

if (rocklake_abi_version() != ROCKLAKE_ABI_VERSION) {
    fprintf(stderr, "ABI mismatch\n");
    return -1;
}

Error Handling

rocklake_error_t

typedef struct {
    int32_t  code;
    char    *message;
} rocklake_error_t;

Every function that can fail takes a rocklake_error_t *err output parameter (may be NULL). Always call rocklake_error_free(err) after each call, even on success, to release the message string.

Error Codes

Constant Value Meaning
ROCKLAKE_OK 0 Success
ROCKLAKE_ERR_INTERNAL 1 Unexpected internal error
ROCKLAKE_ERR_NOT_FOUND 2 Requested resource not found
ROCKLAKE_ERR_WRITER_FENCED / ROCKLAKE_ERR_FENCED 3 Writer fenced by a higher-epoch writer
ROCKLAKE_ERR_FORMAT_MISMATCH 4 Catalog format version mismatch
ROCKLAKE_ERR_VALUE_TOO_LARGE 5 Value exceeds maximum encoded size
ROCKLAKE_ERR_TRANSACTION_CONFLICT / ROCKLAKE_ERR_CONFLICT 6 Serializable conflict — retry
ROCKLAKE_ERR_NOT_INITIALIZED 7 Catalog not initialized
ROCKLAKE_ERR_INVALID_HANDLE 8 Null or already-closed handle

The short aliases (ROCKLAKE_ERR_FENCED, ROCKLAKE_ERR_CONFLICT) are provided for POSIX-style code that prefers concise names.

Error Functions

int32_t     rocklake_error_code(const rocklake_error_t *err);
const char *rocklake_error_message(const rocklake_error_t *err);
void        rocklake_error_free(rocklake_error_t *err);

rocklake_error_message() returns a borrowed pointer — do not free it directly. Call rocklake_error_free() to release the whole struct.


Catalog Handle

typedef struct RockLakeCatalog rocklake_catalog_t;

rocklake_catalog_t *rocklake_open(const char *uri, rocklake_error_t *err);
void                rocklake_close(rocklake_catalog_t *catalog);

Ownership

  • rocklake_open() returns a heap-allocated handle. The caller must close it with rocklake_close().
  • rocklake_close() is safe to call on NULL or an already-closed pointer.
  • A handle must not be shared across threads without external mutual exclusion.

Supported URIs

URI Backend
/absolute/path Local filesystem
file:///absolute/path Local filesystem

S3 / GCS / Azure support is available via the rocklake-client Rust API and higher-level language bindings.


Read Operations

All read functions take a snapshot_id parameter. Pass 0 to read the latest committed snapshot.

Get Current Snapshot

rocklake_snapshot_t rocklake_get_current_snapshot(
    rocklake_catalog_t *catalog, rocklake_error_t *err);

Returns snapshot_id = 0 when no snapshots exist (fresh catalog).

List Schemas

rocklake_schema_list_t rocklake_list_schemas(
    rocklake_catalog_t *catalog, uint64_t snapshot_id, rocklake_error_t *err);

void rocklake_schema_list_free(rocklake_schema_list_t *list);

List Tables

rocklake_table_list_t rocklake_list_tables(
    rocklake_catalog_t *catalog,
    uint64_t schema_id,
    uint64_t snapshot_id,
    rocklake_error_t *err);

void rocklake_table_list_free(rocklake_table_list_t *list);

Describe Table (Columns)

rocklake_column_list_t rocklake_describe_table(
    rocklake_catalog_t *catalog,
    uint64_t table_id,
    uint64_t snapshot_id,
    rocklake_error_t *err);

void rocklake_column_list_free(rocklake_column_list_t *list);

List Data Files

rocklake_file_list_t rocklake_list_data_files(
    rocklake_catalog_t *catalog,
    uint64_t table_id,
    uint64_t snapshot_id,
    rocklake_error_t *err);

void rocklake_file_list_free(rocklake_file_list_t *list);

Result Types

rocklake_snapshot_t

typedef struct {
    uint64_t snapshot_id;
    uint64_t schema_version;
} rocklake_snapshot_t;

Returned by value — no heap allocation, no free needed.

rocklake_schema_list_t / rocklake_schema_entry_t

typedef struct {
    uint64_t  schema_id;
    char     *schema_name;  /* owned by the list */
} rocklake_schema_entry_t;

typedef struct {
    rocklake_schema_entry_t *schemas;
    uint64_t                 count;
} rocklake_schema_list_t;

Free with rocklake_schema_list_free().

rocklake_table_list_t / rocklake_table_entry_t

typedef struct {
    uint64_t  table_id;
    uint64_t  schema_id;
    char     *table_name;  /* owned by the list */
} rocklake_table_entry_t;

typedef struct {
    rocklake_table_entry_t *tables;
    uint64_t                count;
} rocklake_table_list_t;

rocklake_column_list_t / rocklake_column_entry_t

typedef struct {
    uint64_t  column_id;
    uint64_t  table_id;
    char     *column_name;
    char     *data_type;
    uint64_t  column_index;
    bool      is_nullable;
} rocklake_column_entry_t;

typedef struct {
    rocklake_column_entry_t *columns;
    uint64_t                 count;
} rocklake_column_list_t;

rocklake_file_list_t / rocklake_data_file_t

typedef struct {
    uint64_t  data_file_id;
    uint64_t  table_id;
    char     *path;
    char     *file_format;
    uint64_t  row_count;
    uint64_t  file_size_bytes;
    uint64_t  snapshot_id;
} rocklake_data_file_t;

typedef struct {
    rocklake_data_file_t *files;
    uint64_t              count;
} rocklake_file_list_t;

Complete Example (C)

#include <stdio.h>
#include <string.h>
#include "rocklake.h"

int main(void) {
    /* Verify ABI version */
    if (rocklake_abi_version() != ROCKLAKE_ABI_VERSION) {
        fprintf(stderr, "ABI version mismatch\n");
        return 1;
    }

    /* Open catalog */
    rocklake_error_t err;
    memset(&err, 0, sizeof(err));
    rocklake_catalog_t *cat = rocklake_open("/path/to/catalog", &err);
    if (!cat) {
        fprintf(stderr, "open failed: %s\n", rocklake_error_message(&err));
        rocklake_error_free(&err);
        return 1;
    }
    rocklake_error_free(&err);

    /* Get current snapshot */
    rocklake_snapshot_t snap = rocklake_get_current_snapshot(cat, &err);
    rocklake_error_free(&err);
    printf("snapshot_id = %llu\n", (unsigned long long)snap.snapshot_id);

    /* List schemas */
    rocklake_schema_list_t schemas = rocklake_list_schemas(cat, snap.snapshot_id, &err);
    rocklake_error_free(&err);
    for (uint64_t i = 0; i < schemas.count; i++) {
        printf("schema: %s\n", schemas.schemas[i].schema_name);
    }
    rocklake_schema_list_free(&schemas);

    rocklake_close(cat);
    return 0;
}

Thread Safety

  • Different handles (separate rocklake_open() calls) may be used concurrently from different threads.
  • A single handle must not be used from multiple threads simultaneously without external mutual exclusion.
  • rocklake_abi_version() is safe to call from any thread at any time.

Building Against the C ABI

Include crates/rocklake-ffi/include/rocklake.h and link against librocklake_ffi.a (static) or librocklake_ffi.so / librocklake_ffi.dylib (dynamic).

# Static link
cc -I crates/rocklake-ffi/include \
   -o my_app my_app.c \
   target/release/librocklake_ffi.a \
   -lpthread -ldl -lm

# Dynamic link
cc -I crates/rocklake-ffi/include \
   -o my_app my_app.c \
   -L target/release -lrocklake_ffi \
   -Wl,-rpath,target/release

Pre-built binaries for Linux x86-64/arm64 and macOS arm64 are distributed as GitHub release assets.

See docs/integration/client-library.md for language-specific quickstarts.