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-clientRust 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¶
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¶
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 withrocklake_close().rocklake_close()is safe to call onNULLor 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¶
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.