Expand description
Per-file schema migration ledger.
Every SQLite file carries a meerkat_schema(domain TEXT PRIMARY KEY, version INTEGER NOT NULL) table with exactly one row per schema domain.
Each store registers its ordered, idempotent migrations; the existing DDL
of every store is migration 0001 of its domain.
§The pinned transaction protocol
Idempotent migration functions alone do not make concurrent opens safe, so the runner pins a minimal protocol (consumed unchanged by downstream adopters):
- exactly one ledger row per domain;
BEGIN IMMEDIATE;- re-read the version inside that transaction;
- reject a future version before any mutation
(
SqliteStoreError::SchemaFromTheFuture); - execute the pending migrations and the ledger update atomically in the
same transaction — custody is verified with a runner-owned savepoint
around each body, so a body that COMMITs or ROLLBACKs underneath the
runner is refused (
SqliteStoreError::MigrationBrokeTransaction) even when it re-BEGINs a fresh transaction afterwards.
A table merely named meerkat_schema is not trusted: before any read
the pinned column shape is validated against main’s catalog, versions
must be positive, and at most one row may exist per domain
(SqliteStoreError::LedgerMalformed otherwise). All ledger SQL is
main.-qualified, so a TEMP table shadowing the name can neither satisfy
nor bypass the ledger.
Concurrent opens race safely: the loser’s in-transaction re-read sees the winner’s committed version and applies nothing.
§Migrations on files older than the ledger
Files written before the ledger existed carry tables of some historical
vintage and no meerkat_schema row (version 0). Migration 0001 is the
store’s CREATE ... IF NOT EXISTS DDL, which converges missing tables
without touching existing ones; later migrations guard internally (for
example PRAGMA table_info probes before ALTER TABLE) exactly like the
historical upgrade functions they were lifted from. Running the full
sequence therefore converges a file of any vintage and stamps it — this
is also what the offline ledger-baseline migration case does, under the
maintenance fence.
Foreign domain rows (other stores co-tenanting the same file) are never read or written; the ledger keys strictly by domain name.
Structs§
- Ledger
Report - Outcome of
apply_domain_migrations. - Migration
- One schema migration step for a domain.
- Schema
Domain - A store’s schema domain: its ledger name plus the ordered migration list.
Functions§
- apply_
domain_ migrations - Bring
domainup to date in the file behindconn, per the pinned protocol. Returns the version movement. - domain_
version - Read a domain’s ledger version without applying anything.
- refuse_
future_ schema - Refuse when the file’s ledger already records a version of
domainnewer than this binary supports, without mutating anything.