Interactive Tool
Online Preview
Paste a .gedb schema, configure storage parameters, and generate C99 output instantly.
Schema Input
Generated Output
/*
* main.c — Example usage of the GreatEmbeddo generated database.
*
* All writes are automatically wrapped in a transaction if called
* outside gedb_transaction_write(). For multi-step writes, use gedb_transaction_write()
* to group them into a single atomic commit.
*
* Reads via gedb_transaction_read() are lock-free and never block writers.
*
* SPDX-License-Identifier: MIT
*/
/* MSVC: allow fopen without _s variant */
#define _CRT_SECURE_NO_WARNINGS
#include "gedb.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* ── File-based I/O (ctx = FILE* opened with "r+b" or "w+b") ── */
/* File layout: block N starts at byte N * GEDB_BLOCK_SIZE. */
/* On real flash, replace these with your driver calls. */
static gedb_status_t my_read(uint64_t block_id, uint32_t offset,
void *buf, uint32_t len, void *ctx)
{
FILE *f = (FILE *)ctx;
if (fseek(f, (long)(block_id * GEDB_BLOCK_SIZE + offset), SEEK_SET) != 0)
{
return GEDB_ERR_IO;
}
if (fread(buf, 1, len, f) != len)
{
return GEDB_ERR_IO;
}
return GEDB_OK;
}
static gedb_status_t my_erase(uint64_t block_id, void *ctx)
{
/* file-based: erases handled implicitly by write */
(void)block_id; (void)ctx;
return GEDB_OK;
}
static gedb_status_t my_write(uint64_t block_id, uint32_t offset,
const void *data, uint32_t len, void *ctx)
{
FILE *f = (FILE *)ctx;
if (fseek(f, (long)(block_id * GEDB_BLOCK_SIZE + offset), SEEK_SET) != 0)
{
return GEDB_ERR_IO;
}
if (fwrite(data, 1, len, f) != len)
{
return GEDB_ERR_IO;
}
if (fflush(f) != 0)
{
return GEDB_ERR_IO;
}
return GEDB_OK;
}
/* ── Batch insert: multiple rows in one atomic transaction ───── */
static gedb_status_t insert_three_rows(gedb_txn_t *txn, void *ctx)
{
(void)ctx;
gedb_sensors_row_t row;
gedb_status_t st;
(void)memset(&row, 0, sizeof(row));
row.node_id = 100;
row.temp_c = 10.0f;
st = gedb_sensors_insert(txn, &row);
/* rollback all three */
if (st != GEDB_OK)
{
return st;
}
row.node_id = 200;
row.temp_c = 20.0f;
st = gedb_sensors_insert(txn, &row);
/* rollback all three */
if (st != GEDB_OK)
{
return st;
}
row.node_id = 300;
row.temp_c = 30.0f;
st = gedb_sensors_insert(txn, &row);
/* rollback all three */
if (st != GEDB_OK)
{
return st;
}
/* commit all three rows atomically */
return GEDB_OK;
}
/* ── Read-only query example (lock-free) ──────────────────────── */
static gedb_status_t read_sample_data(gedb_txn_t *txn, void *ctx)
{
(void)ctx;
gedb_sensors_row_t row;
gedb_status_t st = gedb_sensors_get(txn, (uint32_t)1, &row);
if (st == GEDB_OK)
{
/* Use row.id, etc. */
}
else if (st != GEDB_ERR_NOT_FOUND)
{
/* propagate I/O or other errors */
return st;
}
return GEDB_OK;
}
/* ── Iterate every row in sensors (lock-free) ───────────── */
static gedb_status_t iterate_sensors(gedb_txn_t *txn, void *ctx)
{
(void)ctx;
gedb_sensors_iter_t iter;
gedb_status_t st = gedb_sensors_scan_open(txn, &iter);
if (st != GEDB_OK)
{
return st;
}
gedb_sensors_row_t row;
for (;;)
{
st = gedb_sensors_scan_next(txn, &iter, &row);
/* end-of-scan, not an error */
if (st == GEDB_DONE)
{
return GEDB_OK;
}
if (st != GEDB_OK)
{
return st;
}
/* row.id (and other columns) are valid here */
}
}
/* ── Entry point ────────────────────────────────────────────────── */
int main(void)
{
static gedb_db_t db;
/* Open (or create) the flat storage file. */
FILE *storage = fopen("gedb_storage.bin", "r+b");
if (!storage)
{
storage = fopen("gedb_storage.bin", "w+b");
}
if (!storage)
{
return 1;
}
/* Open the database. On a fresh device gedb_init returns GEDB_NEEDS_FORMATTING; */
/* call gedb_format with a caller-chosen unique database_id. Use a time-seeded */
/* PRNG so each new database has a distinct id, which lets a future reformat */
/* invalidate old data on the same flash without an O(BlockCount) erase pass. */
gedb_status_t st = gedb_init(&db, my_read, my_erase, my_write, storage, NULL);
if (st == GEDB_NEEDS_FORMATTING)
{
srand((unsigned)time(NULL));
uint64_t database_id = ((uint64_t)rand() << 32) ^ (uint64_t)rand();
st = gedb_format(&db, my_read, my_erase, my_write, storage, NULL, database_id);
}
if (st != GEDB_OK)
{
fclose(storage);
return 1;
}
/* Batch insert: all three rows are committed atomically. */
/* If any insert fails, the entire transaction is rolled back. */
/* Faster than inserting one-by-one: one lock, one metadata commit. */
st = gedb_transaction_write(&db, insert_three_rows, NULL);
if (st != GEDB_OK) { /* handle error — all three rows were rolled back */ }
/* Auto-commit: single insert, implicit transaction. */
/* Each call acquires the lock, inserts, and commits automatically. */
gedb_sensors_row_t new_row;
(void)memset(&new_row, 0, sizeof(new_row));
/* new_row.id = 0 — auto-assigned by the database */
/* auto-commits */
st = gedb_sensors_insert_auto(&db, &new_row);
if (st != GEDB_OK) { /* handle error */ }
/* Read-only queries are lock-free (never block writers). */
/* They use a seqlock snapshot of the committed state. */
st = gedb_transaction_read(&db, read_sample_data, NULL);
if (st != GEDB_OK) { /* handle error */ }
/* Walk every row in sensors via the generated scan API. */
st = gedb_transaction_read(&db, iterate_sensors, NULL);
if (st != GEDB_OK) { /* handle error */ }
/* ── sensors CRUD ────────────────────────────── */
/* gedb_sensors_row_t r; memset(&r, 0, sizeof(r)); */
/* r.id = 0; // auto-assigned by the database */
/* gedb_sensors_insert_auto(&db, &r); // auto-commits */
/* gedb_sensors_get_auto(&db, (uint32_t)1, &r); */
/* gedb_sensors_update_auto(&db, &r); // auto-commits */
/* gedb_sensors_delete_auto(&db, (uint32_t)1); // auto-commits */
/* gedb_sensors_upsert_auto(&db, &r); // auto-commits */
/* Inside a read txn: gedb_sensors_iter_t it; gedb_sensors_scan_open(txn, &it); */
/* while (gedb_sensors_scan_next(txn, &it, &r) == GEDB_OK) ... */
/* ── events CRUD ────────────────────────────── */
/* gedb_events_row_t r; memset(&r, 0, sizeof(r)); */
/* r.id = 0; // auto-assigned by the database */
/* gedb_events_insert_auto(&db, &r); // auto-commits */
/* gedb_events_get_auto(&db, (uint64_t)1, &r); */
/* gedb_events_update_auto(&db, &r); // auto-commits */
/* gedb_events_delete_auto(&db, (uint64_t)1); // auto-commits */
/* gedb_events_upsert_auto(&db, &r); // auto-commits */
/* Inside a read txn: gedb_events_iter_t it; gedb_events_scan_open(txn, &it); */
/* while (gedb_events_scan_next(txn, &it, &r) == GEDB_OK) ... */
fclose(storage);
return 0;
}