pg_pure roadmap

This is the only plan file. The design and its reasons are in DESIGN.md, the working rules in AGENTS.md. Each phase ends with a gate. A phase is done when its gate has run on the EC2 box and the output shows that every test in it actually ran.

Phase 0: libpure prerequisites (in github.com/gburd/pure-lang) – DONE

Both landed in the fork on libpure-embeddable (tip ab12de13):

  • [x] 0.1 libpure no longer exports its LLVM symbols, so it cannot clash with a host’s llvmjit of a different LLVM major (commit “Hide libpure’s LLVM symbols …”). pg_pure links it unchanged; the “PostgreSQL without -jit” workaround is retired. Verified: 0 llvm:: exports, libpure make check 95/95, both pg_pure suites pass with jit=on, jit_above_cost=0 on PG 17/18/19, 0 crashes.
  • [x] 0.3 A safe mode (commit “Add a safe mode …”): pure_is_safe, pure_safe_allow_using, pure_safe_arm. This is what the trusted pg_pure uses (phase 3).
  • [ ] 0.2 Keep a crash-matrix reproducer in pg_pure’s TAP suite (ROADMAP 1.7) so a future libpure that re-exports LLVM is caught. (Not in the fork; it belongs here.)

Phase 1: the extension (pg_pureu now, pg_pure on top)

  • [x] 1.1 Repository skeleton: PGXS Makefile (with dist and check-ascii), pg_pure.control and pg_pureu.control, their --0.1.sql scripts, sql/ with expected/, README, LICENSE, META.json (two provides), CHANGELOG, ci/ (announce + noop), and the CI and release workflows. Still to add: a t/ TAP suite.
  • [x] 1.2 Port the prototype as pg_pure.c and fix the six defects in DESIGN.md section 8. Each fix has a regression case in sql/pg_pureu.sql; all pass on PG 17, 18 and 19.
  • [x] 1.3 Type mapping: scalars, exact numeric (bigint and rational, with a verified round-trip), range checks, text-only text results, NULL, numeric via math. Still to do: arrays as lists, composites as records, other types through text I/O, a UTF-8 conversion for other encodings.
  • [x] 1.4 The sql namespace: query, exec, notice, warning, null, error carrying SQLSTATE. (Parameters to query/exec are designed but not yet implemented; the body still builds its own SQL string.)
  • [x] The two trusted/untrusted handler pairs (pg_pure/pg_pureu), the DO inline handler, the validator, and using lines pulled to the top of a body.
  • [x] 1.9 Cross-platform: Linux (Debian 13) PG 17/18/19 and FreeBSD 14.5 PG 17 both build against the fork’s libpure and pass the suite with 0 crashes. Windows ruled out with reasons (DESIGN.md section 10).
  • [ ] 1.4a Parameterized sql::query (q, p1, ...) / sql::exec (send parameters, never splice).
  • [ ] 1.5 Set-returning functions (lists and lazy streams into a tuplestore), triggers (new, old, tg), procedures.
  • [ ] 1.6 Preloading: the _PG_init warm-up code exists but is not yet tested end to end; confirm backends inherit it and measure.
  • [ ] 1.7 TAP tests: crash safety (JIT plus Pure in both orders, with and without preload, checked in the server log – the manual matrix is 0-crash, 3 runs each, on PG 18); cancel and pg_terminate_backend; 8 concurrent backends; RSS over 1M calls stays flat; a LATIN1 database.
  • [ ] 1.8 A cassert build of PostgreSQL from source on the box (and, once Greg’s LLVM-21 work lands, a server whose llvmjit matches libpure’s LLVM major – the matched-major no-clash case, DESIGN.md 5a).

Gate: ci/gate.sh passes installcheck and TAP on PG 17 and PG 18, plus the cassert leg; the server log has 0 “terminated by signal” lines and 0 TRAP lines; make check-ascii passes.

Phase 2: depth

  • [ ] 2.1 Prepared plans, either cached per query string or as an explicit sql::prepare.
  • [ ] 2.2 sql::stream q: a lazy stream backed by a cursor. Forcing it after its call has returned must throw, never crash.
  • [ ] 2.3 bytea (choose between a blob and a byte matrix), domains, and an explicit subtransaction block.
  • [ ] 2.4 Vet modules and promote them to the tested list, each with a regression test inside PostgreSQL: gsl, mpfr, csv, xml, stldict, stllib, rational. Fix pure-glpk’s error hook in the fork.
  • [ ] 2.5 hegel property tests for the conversions: for generated values of each type, identity(v) = v, and every value out of range is an ERROR, never a wrong answer.
  • [ ] 2.6 Benchmarks against PL/pgSQL, PL/Python and PL/Perl: interleaved runs and medians, method and box recorded under bench/ with a date.

Gate: phase 1 gate, plus the module tests and the property suite.

Phase 3: the trusted language and the remaining PL features

  • [x] 3.1/3.2 libpure safe mode designed and landed in the fork (pure_is_safe/pure_safe_allow_using/pure_safe_arm); see phase 0.
  • [x] 3.3a pg_pure (trusted) runs each function in a --safe, armed interpreter: a body attempting extern, inline code, eval/evalcmd, a native or off-allowlist using, or a dangerous prelude function is refused as an SQL ERROR and the backend survives. sql/pg_pure.sql covers each route; passes on PG 17/18/19.
  • [ ] 3.3b One interpreter per SQL user (DESIGN.md 9.4): today a single armed interpreter serves all pg_pure functions in a backend. Key it by GetUserId() so SECURITY DEFINER functions cannot share state.
  • [ ] 3.3c A curated --safe prelude (DESIGN.md 9.5) instead of the denylist, designed with the Pure maintainer; independent security review before relying on the trusted language for untrusted multi-tenant use.
  • [ ] 3.4 Event triggers; transaction control in procedures (sql::commit, sql::rollback).

Gate: phase 2 gate plus the escape suite (have it in sql/pg_pure.sql), and an independent security review of the safe mode before relying on pg_pure for untrusted multi-tenant workloads.

Phase 4: release

  • [ ] 4.1 Docs (SGML and HTML), the PGXN package, Debian packaging, and RELEASING.md in the style of pg_fts’s.

Decided

  • 2026-10-27: development and every build and test run on an EC2 Debian 13 box in the kiwi account, never on floki (Greg).
  • 2026-10-27: the languages are pg_pure (trusted, the ship target) and pg_pureu (untrusted, superuser only), following the PL/Perl plperl/plperlu model with pg_ names. We keep both; we ultimately ship pg_pure (Greg).
  • 2026-10-28: reuse pg_fts’s PGXN/CI/release/announce machinery (META.json two-provides, ci/announce.sh, GitHub Actions). Repo home is GitHub (github.com/gburd/pg_pure), not Codeberg.
  • 2026-10-28: support PG 17, 18 and 19 (19 via the PGDG snapshot repo until release). FreeBSD is a supported platform; Windows is not (DESIGN.md 10).
  • 2026-10-27: a PostgreSQL built without LLVM (no postgresql-NN-jit) is a supported deployment and needs no libpure symbol fix; it gives up the server’s own JIT. DESIGN.md section 5a. (Greg is also moving PostgreSQL to LLVM 21 in a separate effort, which removes the clash a different way.)
  • 2026-10-29: libpure landed both fixes in the fork (ab12de13): LLVM symbols hidden (no coexistence workaround needed) and a safe mode. pg_pure 0.2.0 wires the trusted pg_pure to the safe mode; both languages now run and pass on PG 17/18/19 with jit=on.