Skip to content

§12 Database Access

Status: finalized (v0.8, 2026-09-22) — written back on the landing of the server roadmap's P5 wave (the std/db data-access layer) (2026-09-22; for the execution rulings, see the execution record in internal design documents in the repository). The original draft (v0.8-d1, 2026-09-20) descends from server roadmap design v3. Capability/purity semantics belong to §8; cancellation semantics to §7.2 and §11.4. This chapter defines the driver contract, the connection pool, row mapping (the as-built runtime surface), transactions, and cancellation. Normative conventions follow the spec README. Implemented surface: std/db/{db,pg,redis,pool,rowmap}.ct + tests/db/ (replay with zero real databases; real targets nightly; the performance gate tests/db/perf, with a registered skip policy as measured).

12.1 The db.connect Capability Key (Normative)

  • All database access goes through capability objects; [caps] declares the db.connect upper bound, and exceeding it = E4010. Connections are passed in as a DSN via capability-object parameters; programs must not establish connections from arbitrary strings on their own.
  • A #[pure] function touching the database = E4020 (rejected at compile time).
  • Derived surface: transactions/prepared statements derived from an already-authorized connection inherit the authorization and do not consume the key again.

12.2 Driver Contract (Normative: Pure-Ctron Wire Protocol)

  • Drivers MUST be pure-Ctron wire-protocol implementations — this is the basis for the auditability of the capability surface (C-binding drivers bypass language-level auditing and trigger W-level lints):
  • PostgreSQL wire protocol v3: startup, simple query, extended query (Prepared Statement), SCRAM-SHA-256 authentication (cryptographic primitives from std/crypto: SHA-256/HMAC/PBKDF2, pure Ctron, anchored on the RFC 6234/4231/6070 vectors; omitting SASLprep password normalization = a registered v0 policy, passwords taken as raw bytes, which follows RFC 5802 §5.1's recommendation; rejecting plus-only channel binding = a clean Err);
  • Redis RESP2: the GET/SET/DEL/EXPIRE/INCR fundamentals; pub/sub subscriptions are listed in the ecosystem tier.
  • MySQL/Mongo and the like are outside the v1 contract; SQLite (the C-binding exception path) is listed as an aspiration tier and requires an explicit #[trusted] audit surface when it lands.

12.3 Connection Pool and Backpressure (Normative)

  • The pool is bounded (capacity required, same discipline as Channel); pool waits express backpressure through a bounded channel, and waits are cancellable (§12.4).
  • Reset before returning to the pool (MUST): active transactions rolled back, session variables reset, prepared statements cleaned up per policy — reusing dirty connections across cancellations or across errors is forbidden.

12.4 Transactions and Cancellation Propagation (Normative)

  • begin / commit / rollback as the explicit surface; queries respond to scope cancellation at suspension points (§7.2/§11.4): cancellation → the connection is rolled back, reset, and returned to the pool, never leaking cancellation semantics into a half-way commit.
  • Nested transactions are not supported (savepoints listed as an aspiration tier); errors propagate explicitly along Result, without panicking.

12.5 Row Mapping (Normative; as-built = runtime binding, D-P5-1 deviation written back)

  • Query-result row → struct binding: expanded at runtime (P5-wave as-built; std/db/rowmap.ct OID table / column-name matching / type-family gates; missing column / type mismatch / NULL misfit / row out of bounds / value out of domain = reported as a runtime Result Err, kinds noent/type/null/row-oob/val-domain). The original draft's "comptime expansion, reported at compile time" is unreachable under §8.4's reflection ban (type-producing functions reserved for v2) — this clause is the finalized write-back of design deviation D-P5-1; the deviation registration and exit ruling are in the P5 plan execution record. Negative anchor r7d_db_rowmap (the anchor's semantics accordingly changed from "reported at compile time" to "runtime Err").
  • @derive(DbRow) (an extension of the compiler-known derive set, generating binding code at compile time) = an aspiration tier, listed in the compilation swimlane; the OID/column-name matching surface of this clause is its runtime fallback position, and once it lands the runtime surface is demoted to a hand-written fallback path.
  • SQL text is not statically validated (no live-DB dependency; static SQL checking is listed as an aspiration tier).
  • NULL → Option[T] explicit mapping, no implicit zero values (the rowmap NULL Err surface + the caller-side wrapper mapping Option in a two-stage form).

12.6 Interface with std/json (Declared Prerequisite)

  • The request body → struct → row-binding chain takes std/json numeric/boolean type fidelity as a declared prerequisite work item (as determined in the 2026-09-20 v3 review: the current json value model is a flattened string table and does not satisfy numeric fidelity); streaming/NDJSON parsing is listed in the ecosystem tier.

12.7 Correspondence with the Test Suite

  • Protocol fixture replay (as-built: byte scripts constructed by hand against the public protocols, with each README registering its own recording policy; zero real-database dependency in CI); real databases (Postgres/Redis) are nightly targets only (tests/db/nightly/, env-driven, with a registered SKIP policy when no target exists).
  • tests/db/ dual arms (interpreter + emit; 40 fixture-script surfaces + corpus + the x_ fd-true-source emit-only arm); decoder fuzzing and differential testing (underpinned by libpq/official resp implementations, referenced by the test line only) are listed for later; performance gate: the simple-query round trip vs libpq, isomorphic, ≤1.5× (tests/db/perf/, min-of-3; no libpq development surface on this machine = the registered SKIP policy, measured 2026-09-22).