# m2SQLITE summary — v0.3.0 (2026-09-24) SQLite bindings for GNU Modula-2 (`gm2` 16.0.1, SQLite 3.46.1 system `libsqlite3.so.0`, Linux; API reference `sqlite-master/` 3.54.0). All builds verified with `make`; tests 6/6 green, showcase exits 0. ## v0.1.0 — core binding + showcase - `src/SQLite.def` — thin `FOR "C"` core API (~60 procedures): version/sourceid/threadsafe, `open`/`open_v2`/`close`/`close_v2`, `exec`, errcode/errmsg/errstr/error-offset/free, complete, busy-timeout, autocommit, changes/rowid, extended codes, limit, `prepare_v2`/`prepare_v3`, step/finalize/reset/clear-bindings, data/column-count, sql/expanded-sql, stmt-readonly/busy, all `bind_*`, all `column_*`, parameter count/name/index; result-code, open-flag, column-type, prepare-flag and limit-id constants - `lib/SQLiteUtils.def/.mod` — `CStrToM2`, `ErrMsg`/`ErrStr`/ `LibVersionStr`, `StaticDestr`/`TransientDestr` (STATIC/TRANSIENT sentinels), `BindTextCopy`/`BindBlobCopy`, `ExecSimple`/`ExecWithErr` - `tests/` — version, open (+open_v2), exec (incl. change counters and error capture), prepare/bind/column round trip + `run_tests.sh` - `examples/` — `version`, `hello_db` (bind-insert, select-print) - `showcases/showcase_all` — calls every `SQLite` procedure and every `SQLiteUtils` helper in 7 sections; verifies values, prints results - `Makefile` — gm2 build (`-c` helper to `.o`, then link) for tests, examples and showcases; `pkg-config` with runtime-lib fallback; optional `local-sqlite` amalgamation target - `.gitignore` — ignores `sqlite-master/`, `build/`, artefacts, `*.db` - `README.md` — status table, layout, build/test, usage, FFI notes ## v0.2.0 — custom SQL functions - `src/SQLite.def` — function API (+30 procedures): `XFunc`/`XStep`/ `XFinal`/`XDestroy` callback types (`ContextHandle`, `ValueHandle`), `create_function`/`create_function_v2`, all `value_*` readers (blob/double/int/int64/text/bytes/type/numeric-type), all `result_*` writers (blob/blob64/double/error(+code/toobig/nomem)/int/int64/null/ text/text64/value/zeroblob/zeroblob64), context helpers (`aggregate_context`, `user_data`, `context_db_handle`, `get/set_auxdata`); UTF-encoding and function-flag constants - `lib/SQLiteUtils` — `ValueText`, `ResultTextCopy` - `tests/test_func` — 17 registered functions: scalars, sized results, error paths (exact codes 1/18/7), `msum` aggregate with shared state, `user_data` counting, `context_db_handle` check, auxdata round trip - `showcases/showcase_all` — section [8]: `m2tax` scalar, `m2total` aggregate ## v0.3.0 — BLOB I/O and online backup - `src/SQLite.def` — handle APIs (+11 procedures): `BlobHandle` and `BackupHandle` opaque types, `blob_open`/`reopen`/`close`/`bytes`/ `read`/`write`, `backup_init` (returns the handle or NIL), `backup_step`/`finish`/`remaining`/`pagecount` - `lib/SQLiteUtils` — `BackupToFile` one-call copy of a live database to a file path (open, init, page loop with Busy/Locked retry bound, finish, close; step/finish errors propagate) - `tests/test_blob` — 256-byte write/read round trip with offset, `reopen` across rows, read-only write refusal (code 8), close relaying the pending handle error (documented behavior, asserted), direct backup (`step(-1)` to Done, remaining/pagecount) verified by row count, `BackupToFile` to `/tmp` verified and unlinked - `showcases/showcase_all` — section [10]: 64-byte blob write/read, file backup, reopen-and-count, temp-file removal (close moves to [11]) ## GM2 FFI rules learned (encoded in code) 1. `DEFINITION MODULE FOR "C"` needs `EXPORT UNQUALIFIED`, otherwise the linker looks for `Module_proc` instead of the C symbol. 2. No `*)` and no `(*` inside `(* *)` comments (nested-comment open and early close) — C pointer spellings need spaces (`char *` never `char *)`, `destructor` never `void (*)`). 3. `INTEGER` <-> int, `LONGINT` <-> `sqlite3_int64`, `REAL` <-> double (`libc.atof`/`strtod` return `REAL`); opaque handles = `ADDRESS`. 4. `ARRAY OF CHAR` params = `char *` (pass literals, `-1` for lengths); mandatory `**` OUT params = `VAR`, optional ones (`errmsg`, `pzTail`) = plain `ADDRESS` taking `ADR(var)` or `NIL`. 5. `SQLITE_TRANSIENT`/`STATIC` are macros, pass `VAL(ADDRESS, -1/0)` (wrapped by `TransientDestr`/`StaticDestr`). 6. `INTEGER` constants garble through C varargs (`printf("%d")`) — route them via variables first. 7. No dev package needed: link `/usr/lib/x86_64-linux-gnu/libsqlite3.so.0` directly when `pkg-config sqlite3` is absent. 8. Callback types (`PROCEDURE (ADDRESS, ...)`) cross into C as plain function pointers; `NIL` fills unused slots. Index C pointer arrays with a `VAL` overlay onto `POINTER TO ARRAY OF ADDRESS`. 9. This SQLite build rejects the `AS t(v)` column-alias form in `FROM (VALUES ...)`; use bare `column1` names in tests. 10. `ORD` returns `CARDINAL`: mix with `INTEGER` only via `VAL`, and compare `HIGH()` (also `CARDINAL`) the same way. `blob_close` relays a handle's pending operation error while still releasing it — expect codes, not just `Ok`. 11. `libc.unlink` takes `ADDRESS` (`ADR` of a NUL buffer) and its `[INTEGER]` result may be assigned or dropped as a statement. ## Next Window functions (`create_window_function`) + collations, extended result-code constants + `get_table` wrapper, sessions/changesets.