@crvouga/postgres-mem 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/AGENTS.md +159 -0
  2. package/COMPATIBILITY-AUDIT.md +155 -0
  3. package/COMPATIBILITY.md +87 -0
  4. package/LICENSE +21 -0
  5. package/README.md +325 -0
  6. package/compat/coverage.json +1081 -0
  7. package/compat/divergences.json +191 -0
  8. package/compat/gate-report.json +80 -0
  9. package/compat/requirements.json +1105 -0
  10. package/compat/requirements.raw.html +484 -0
  11. package/compat/scenario-types.ts +98 -0
  12. package/compat/scenarios.ts +98 -0
  13. package/compat/sections/agg.ts +45 -0
  14. package/compat/sections/api.ts +28 -0
  15. package/compat/sections/arr.ts +45 -0
  16. package/compat/sections/cat.ts +47 -0
  17. package/compat/sections/con.ts +32 -0
  18. package/compat/sections/cpy.ts +24 -0
  19. package/compat/sections/cte.ts +29 -0
  20. package/compat/sections/dat.ts +60 -0
  21. package/compat/sections/ddl.ts +55 -0
  22. package/compat/sections/det.ts +20 -0
  23. package/compat/sections/dml.ts +37 -0
  24. package/compat/sections/eco.ts +16 -0
  25. package/compat/sections/err.ts +16 -0
  26. package/compat/sections/exp.ts +53 -0
  27. package/compat/sections/fun.ts +58 -0
  28. package/compat/sections/fzz.ts +36 -0
  29. package/compat/sections/guc.ts +27 -0
  30. package/compat/sections/joi.ts +33 -0
  31. package/compat/sections/jsn.ts +46 -0
  32. package/compat/sections/lim.ts +13 -0
  33. package/compat/sections/par.ts +61 -0
  34. package/compat/sections/pre.ts +26 -0
  35. package/compat/sections/sch.ts +31 -0
  36. package/compat/sections/sel.ts +43 -0
  37. package/compat/sections/seq.ts +31 -0
  38. package/compat/sections/snp.ts +21 -0
  39. package/compat/sections/tok.ts +53 -0
  40. package/compat/sections/trg.ts +57 -0
  41. package/compat/sections/tsr.ts +37 -0
  42. package/compat/sections/txn.ts +39 -0
  43. package/compat/sections/typ.ts +55 -0
  44. package/compat/sections/uni.ts +13 -0
  45. package/compat/sections/win.ts +43 -0
  46. package/compat/smoke-baseline.json +3 -0
  47. package/compat/unsupported-register.json +2526 -0
  48. package/dist/api/bind.d.ts +10 -0
  49. package/dist/api/database.d.ts +69 -0
  50. package/dist/api/statement.d.ts +51 -0
  51. package/dist/ast/nodes.d.ts +810 -0
  52. package/dist/constraints/enforce.d.ts +39 -0
  53. package/dist/errors/error.d.ts +24 -0
  54. package/dist/executor/ddl.d.ts +23 -0
  55. package/dist/executor/dml.d.ts +10 -0
  56. package/dist/executor/execute.d.ts +11 -0
  57. package/dist/executor/relation.d.ts +60 -0
  58. package/dist/executor/select.d.ts +41 -0
  59. package/dist/executor/session.d.ts +21 -0
  60. package/dist/executor/triggers-exec.d.ts +1 -0
  61. package/dist/executor/triggers.d.ts +16 -0
  62. package/dist/executor/window.d.ts +13 -0
  63. package/dist/expressions/context.d.ts +23 -0
  64. package/dist/expressions/eval.d.ts +38 -0
  65. package/dist/expressions/operators.d.ts +8 -0
  66. package/dist/expressions/pattern.d.ts +20 -0
  67. package/dist/functions/aggregates.d.ts +17 -0
  68. package/dist/functions/array-fns.d.ts +2 -0
  69. package/dist/functions/datetime-fns.d.ts +26 -0
  70. package/dist/functions/datetime-registry.d.ts +2 -0
  71. package/dist/functions/json-fns.d.ts +7 -0
  72. package/dist/functions/math-fns.d.ts +2 -0
  73. package/dist/functions/misc-fns.d.ts +8 -0
  74. package/dist/functions/scalar.d.ts +10 -0
  75. package/dist/functions/srf.d.ts +12 -0
  76. package/dist/functions/string-fns.d.ts +4 -0
  77. package/dist/functions/tsearch-fns.d.ts +2 -0
  78. package/dist/functions/util.d.ts +14 -0
  79. package/dist/functions/window.d.ts +7 -0
  80. package/dist/index.d.ts +28 -0
  81. package/dist/index.js +19591 -0
  82. package/dist/index.js.map +7 -0
  83. package/dist/lexer/tokenize.d.ts +8 -0
  84. package/dist/parser/index.d.ts +1 -0
  85. package/dist/parser/parser.d.ts +96 -0
  86. package/dist/runtime/clock.d.ts +14 -0
  87. package/dist/runtime/index.d.ts +3 -0
  88. package/dist/runtime/options.d.ts +25 -0
  89. package/dist/runtime/prng.d.ts +48 -0
  90. package/dist/schema/catalog-tables.d.ts +1 -0
  91. package/dist/schema/catalog.d.ts +12 -0
  92. package/dist/serialization/codec.d.ts +29 -0
  93. package/dist/serialization/index.d.ts +1 -0
  94. package/dist/storage/database-state.d.ts +216 -0
  95. package/dist/transactions/manager.d.ts +25 -0
  96. package/dist/tsearch/stem.d.ts +5 -0
  97. package/dist/tsearch/tsearch.d.ts +59 -0
  98. package/dist/types/cast.d.ts +26 -0
  99. package/dist/types/compare.d.ts +18 -0
  100. package/dist/types/datetime.d.ts +68 -0
  101. package/dist/types/jsonb.d.ts +45 -0
  102. package/dist/types/numeric.d.ts +69 -0
  103. package/dist/types/resolve.d.ts +15 -0
  104. package/dist/types/timezone.d.ts +9 -0
  105. package/dist/types/value.d.ts +99 -0
  106. package/dist/unstable.d.ts +15 -0
  107. package/dist/unstable.js +19153 -0
  108. package/dist/unstable.js.map +7 -0
  109. package/package.json +120 -0
package/AGENTS.md ADDED
@@ -0,0 +1,159 @@
1
+ # AGENTS.md — contributing to postgres-mem
2
+
3
+ Guidance for humans and coding agents editing this repository. For install and consumer API, see [README.md](README.md). For the feature matrix, see [COMPATIBILITY.md](COMPATIBILITY.md).
4
+
5
+ ## Mission and non-goals
6
+
7
+ **Mission:** PostgreSQL 18 **SQL dialect** behavioral parity vs **PostgreSQL 18.3** (PGlite, `@electric-sql/pglite`). Same statements → same observable results (rows, errors, SQLSTATEs, row counts), proven by differential contracts and a fail-closed gate.
8
+
9
+ **Allowed intentional differences:**
10
+
11
+ 1. Custom snapshot codec (`PGMM`), not `pg_dump` / on-disk clusters
12
+ 2. Deterministic `random()` / `gen_random_uuid()` and fixed `now()` by default (injectable)
13
+ 3. Single-session engine: no MVCC across connections, no wire protocol, no aborted-transaction (`25P02`) state
14
+ 4. `NOT APPLICABLE` items: roles/auth enforcement, replication, VACUUM internals, storage params, PL/pgSQL
15
+
16
+ **Non-goals:** speaking the wire protocol, matching `pg`/`postgres.js` client APIs, PL/pgSQL, or multi-session concurrency.
17
+
18
+ ## SQL pipeline
19
+
20
+ ```
21
+ SQL string
22
+ → tokenize() src/lexer/tokenize.ts
23
+ → parse() src/parser/index.ts → parser.ts
24
+ → Statement[] AST src/ast/nodes.ts
25
+ → Statement.execute() src/api/statement.ts
26
+ → executeStatement() src/executor/execute.ts
27
+ → per-stmt executor select / dml / ddl / session / triggers
28
+ ```
29
+
30
+ Public entry points: `Database.exec` / `query` / `prepare` / `copyFrom` in [`src/api/database.ts`](src/api/database.ts).
31
+
32
+ Everything is **typed values** (`TypedValue = { t: TypeId, v: Datum }` in [`src/types/value.ts`](src/types/value.ts)) — there is no SQLite-style affinity. Type resolution/casting lives in [`src/types/resolve.ts`](src/types/resolve.ts) and [`src/types/cast.ts`](src/types/cast.ts); `numeric` is an in-repo arbitrary-precision implementation ([`src/types/numeric.ts`](src/types/numeric.ts)).
33
+
34
+ ## `src/` map
35
+
36
+ | Directory | Role |
37
+ | --- | --- |
38
+ | `api/` | Public `Database` / `Statement` facade, bind-value conversion |
39
+ | `ast/` | Discriminated-union AST (`nodes.ts`) |
40
+ | `lexer/` | Tokenizer (dollar quoting, E-strings, `::`, operators) |
41
+ | `parser/` | Recursive-descent parser |
42
+ | `executor/` | Statement dispatch, SELECT, DML, DDL, session (SET/SHOW/COPY/PREPARE), triggers, window functions |
43
+ | `expressions/` | `evalExpr`, operators, pattern matching, `EngineCtx` |
44
+ | `functions/` | Scalar / aggregate / window / datetime / JSON / array / SRF / tsearch registries |
45
+ | `types/` | `TypedValue`, casts, comparison, numeric, datetime, jsonb, timezone |
46
+ | `storage/` | In-memory schemas, tables, sequences, `DatabaseState` |
47
+ | `schema/` | `pg_catalog` + `information_schema` virtual catalogs, `search_path` |
48
+ | `constraints/` | NOT NULL / PK / UNIQUE / CHECK / FK with referential actions |
49
+ | `transactions/` | BEGIN / COMMIT / SAVEPOINT (clones state + PRNG) |
50
+ | `runtime/` | Clock, PRNG, `DatabaseOptions` |
51
+ | `serialization/` | `PGMM` snapshot codec |
52
+ | `tsearch/` | `tsvector` / `tsquery` text search |
53
+ | `errors/` | `PostgresError` with SQLSTATE, `unsupported()` |
54
+
55
+ Hot / large files: `parser/parser.ts`, `executor/select.ts`, `executor/dml.ts`, `types/numeric.ts`.
56
+
57
+ ## Critical conventions
58
+
59
+ - **AST `type` tags** are snake_case (`"create_table"`, `"drop_index"`). TypeScript interfaces are PascalCase (`CreateTableStmt`).
60
+ - **Identifiers** fold to **lowercase** unless double-quoted (PostgreSQL rule); quoted identifiers are case-sensitive.
61
+ - **Engine values** are `TypedValue` with PG internal type names (`int4`, `float8`, `numeric`, `timestamptz`, `_int4` for arrays). **Harness `SqlValue`** ([`tests/harness/types.ts`](tests/harness/types.ts)) is the normalized compare type — do not confuse them.
62
+ - **API `Statement`** vs **AST `Statement`**: the API class aliases the AST union as `AstStatement`.
63
+ - **`Database`** (API) vs **`DatabaseState`** (engine storage).
64
+ - Throw **`PostgresError`** with an `ErrorCategory` and a five-character **SQLSTATE**. Missing SQL must fail loud via `unsupported()` (`0A000`) — the inventory gate fails if the oracle exposes an unimplemented builtin/operator that isn't in `compat/unsupported-register.json`.
65
+ - The public API is **sync**; the oracle (PGlite) is **async** — contract helpers `await` both sides through the `ContractDb` adapter interface.
66
+ - TypeScript: `strict` + `noUncheckedIndexedAccess`. Imports use `.ts` extensions. Biome: 2-space, double quotes, 120 columns.
67
+ - Determinism invariants (seeded PRNG, fixed clock, PRNG rollback with transactions, byte-identical snapshots) must hold — see README.
68
+
69
+ ## Change checklists
70
+
71
+ ### New SQL statement
72
+
73
+ 1. Add union member + interface in [`src/ast/nodes.ts`](src/ast/nodes.ts)
74
+ 2. Parse in [`src/parser/parser.ts`](src/parser/parser.ts) (`parseStatement` dispatch)
75
+ 3. Handle in [`src/executor/execute.ts`](src/executor/execute.ts) (+ `ddl.ts` / `dml.ts` / `session.ts` as needed)
76
+ 4. Mutate `DatabaseState` if schema changes; keep `pg_catalog` / `information_schema` views consistent
77
+ 5. Add differential contract under `tests/contract/<area>/`
78
+ 6. Add/extend a scenario row in `compat/sections/*.ts` and its catalog test in `tests/contract/catalog/`
79
+
80
+ ### New SQL function or operator
81
+
82
+ 1. Implement and register in the right map under `src/functions/*` (or `src/expressions/operators.ts`) so [`scripts/postgres-inventory.ts`](scripts/postgres-inventory.ts) sees it; remove any matching entry from `compat/unsupported-register.json`
83
+ 2. Contract tests under `tests/contract/functions/` (and related areas)
84
+ 3. Run `bun run inventory` / `bun run test:postgres-compat` — oracle builtins must not be silently missing
85
+
86
+ ### New contract test
87
+
88
+ 1. Prefer helpers in [`tests/contract/helpers.ts`](tests/contract/helpers.ts):
89
+ - `parity` — query both engines, compare rows
90
+ - `parityTyped` — also compare column type names
91
+ - `execParity` — writes (row counts + final state)
92
+ - `sequenceParity` — multi-step (optional final-state compare)
93
+ - `errorParity` / `queryErrorParity` — both must fail with the same SQLSTATE class
94
+ - `rankParity` — REAL epsilon compare (ts_rank etc.)
95
+ - `divergence` — engine-only assertion pinned to a `compat/divergences.json` entry
96
+ 2. Or `matrixBoth` + `expectParity` from `tests/harness/`
97
+ 3. **Do not** treat isolated internal unit tests as PostgreSQL proof. The differential suite is authoritative.
98
+ 4. Gate: `bun run test:postgres-compat`
99
+
100
+ ## Test layout
101
+
102
+ | Path | Role |
103
+ | --- | --- |
104
+ | `tests/contract/` | Differential SQL vs PGlite (**authoritative**) |
105
+ | `tests/fuzz/` | fast-check property tests (seeded); differential, NoREC/TLP metamorphic, stateful DST |
106
+ | `tests/harness/` | Compare/normalize/classify helpers + harness unit tests |
107
+ | `tests/adapters/` | Wrappers for postgres-mem and PGlite (`ContractDb`) |
108
+ | `tests/corpus/` | Fuzz regression corpus |
109
+ | `tests/meta/` | Canary definitions, skip register |
110
+
111
+ Examples of public API usage: `tests/contract/api/`, `tests/contract/parameters/`, `tests/contract/determinism/`, `examples/react-vite`.
112
+
113
+ ### Fuzz replay
114
+
115
+ Default seed `0x5a17e0e1`. On failure the seed is printed:
116
+
117
+ ```bash
118
+ bun test tests/fuzz
119
+ POSTGRES_MEM_FUZZ_SEED=12345 bun test tests/fuzz
120
+ POSTGRES_MEM_FUZZ_SEED=12345 POSTGRES_MEM_FUZZ_PATH='0:1' bun test tests/fuzz
121
+ ```
122
+
123
+ ## Compat system
124
+
125
+ | Command | Role |
126
+ | --- | --- |
127
+ | `bun run test:postgres-compat` | Requirements + fail-closed gate + construct catalog + smoke ratchet + contract/fuzz/harness |
128
+ | `bun run inventory` | Oracle `pg_proc` / `pg_operator` vs engine registries (+ `--write-register`) |
129
+ | `bun run scenarios` | Construct-level scenario catalog (`compat/scenarios.ts`) + smoke gate |
130
+ | `bun run requirements` | Refresh PostgreSQL 18 SQL-commands docs → `compat/requirements.json` + `compat/coverage.json` |
131
+ | `bun run canaries` | Apply deliberate sabotages, assert the suite catches them |
132
+
133
+ Statuses: **VERIFIED** / **PARTIALLY VERIFIED** / **UNSUPPORTED** / **NOT APPLICABLE**. Do not market PARTIAL as complete. Coverage evidence is directory paths (e.g. `tests/contract/joins/`), not automatic from test filenames.
134
+
135
+ **Catalog vs proof:** `tests/contract/catalog/` IDs must execute; trivial probes are tracked in `compat/smoke-baseline.json` (ratchet — no new smoke stubs). Documented divergences bind to `compat/divergences.json` (regenerate `DIVERGENCES.md` with `bun run divergences`). Generated operator/CAST matrices: `tests/contract/matrices/`. Stateful dump-after-each fuzz: `tests/fuzz/stateful.test.ts`. Oracle `server_version` must be on the allow-list in `tests/harness/oracle-versions.ts` (18.3).
136
+
137
+ **PGlite quirk:** PGlite's WASM boot leaks `process.exitCode = 99` under Bun ([pglite#975](https://github.com/electric-sql/pglite/issues/975)); the adapter and scripts reset it — keep that workaround when touching `tests/adapters/pglite.ts`.
138
+
139
+ Details: [COMPATIBILITY.md](COMPATIBILITY.md), audit: [COMPATIBILITY-AUDIT.md](COMPATIBILITY-AUDIT.md).
140
+
141
+ ## Local gates
142
+
143
+ Requires [Bun](https://bun.sh).
144
+
145
+ ```bash
146
+ bun install
147
+ bun run ci:local # same gates as GitHub Actions CI (except publish)
148
+ bun run check # format + lint + typecheck + postgres-compat suite
149
+ bun run format
150
+ bun run lint
151
+ bun run typecheck
152
+ bun run test:postgres-compat
153
+ bun test # contract + fuzz + harness
154
+ bun run build
155
+ ```
156
+
157
+ ## PR and commits
158
+
159
+ Use [Conventional Commits](https://www.conventionalcommits.org/) for commits and PR titles (enforced in CI). Prefer squash merges with a conventional title. Releasing is automated via semantic-release — see [README.md](README.md#releasing).
@@ -0,0 +1,155 @@
1
+ # PostgreSQL 18 Compatibility Audit
2
+
3
+ ```text
4
+ PostgreSQL 18 Compatibility Audit
5
+ =================================
6
+
7
+ Reference PostgreSQL version:
8
+ PGlite (@electric-sql/pglite) — real PostgreSQL 18.3 compiled to WASM,
9
+ in-process, no Docker. server_version pinned in
10
+ tests/harness/oracle-versions.ts and asserted by the gate.
11
+
12
+ postgres-mem version:
13
+ 0.0.0-development (package.json; publish via semantic-release)
14
+
15
+ Scope:
16
+ Every oracle-exposed SQL construct is in-scope except NOT APPLICABLE
17
+ (roles/auth enforcement, replication, wire protocol, storage internals,
18
+ PL/pgSQL, extensions). The gate fails closed on silence.
19
+
20
+ PostgreSQL requirements reviewed:
21
+ 183 SQL commands (from the PostgreSQL 18 SQL-commands documentation
22
+ index → compat/requirements.json)
23
+
24
+ Requirements classification:
25
+ NOT APPLICABLE: 56
26
+ SQL_BEHAVIOR: 127
27
+ unknown: 0 (gate fails if non-zero)
28
+
29
+ Coverage statuses (SQL_BEHAVIOR):
30
+ VERIFIED: 43 / PARTIALLY_VERIFIED: 26 / UNSUPPORTED: 58 (fail-loud,
31
+ registered) — see `bun run requirements` / compat/coverage.json
32
+
33
+ Oracle builtin inventory:
34
+ pg_catalog functions exposed by oracle: 2787
35
+ implemented in engine registries: 301
36
+ registered unsupported (with reasons): 2486
37
+ silently missing: 0 (gate fails otherwise)
38
+ pg_catalog operators exposed by oracle: 74
39
+ implemented: 41
40
+ registered unsupported: 33
41
+
42
+ Construct catalog:
43
+ 945 scenarios across 33 sections (compat/scenarios.ts), all promoted
44
+ to executing catalog tests; smoke baseline EMPTY (0 trivial stubs).
45
+
46
+ SQL grammar / operators / expressions:
47
+ VERIFIED — contracts + generated operator matrices from pg_operator
48
+
49
+ Types / casts / NULL:
50
+ VERIFIED — bool/int2/4/8, float4/8, numeric (in-repo arbitrary
51
+ precision), text/varchar/char, bytea, uuid, date/time/timestamp[tz],
52
+ interval, json/jsonb, arrays; cast matrices generated from pg_cast;
53
+ 3VL through operators/aggregates/DISTINCT
54
+
55
+ Functions (oracle surface):
56
+ VERIFIED for the implemented 301; every other oracle builtin is an
57
+ explicit register entry (never silent)
58
+
59
+ JSON / JSONB:
60
+ VERIFIED — operator + function surface, jsonpath subset
61
+
62
+ Aggregates / windows:
63
+ VERIFIED — FILTER, ORDER BY in aggregates, string_agg/array_agg/
64
+ jsonb_agg, full frame specs incl. GROUPS/RANGE + EXCLUDE
65
+
66
+ CTEs / transactions / savepoints / constraints / FK:
67
+ VERIFIED — recursive + data-modifying CTEs; FK actions (CASCADE/SET
68
+ NULL/SET DEFAULT/RESTRICT/NO ACTION); DEFERRABLE parsed, checked at
69
+ statement end (commit-time deferral is a documented gap)
70
+
71
+ Schemas / search_path / catalogs:
72
+ VERIFIED — pg_catalog + information_schema commonly-queried subset
73
+
74
+ Sequences / serial / identity / enums / domains / generated columns:
75
+ VERIFIED
76
+
77
+ Triggers / LANGUAGE sql functions:
78
+ PARTIALLY VERIFIED — row-level triggers fire in creation order
79
+ (PostgreSQL: name order), UPDATE OF ignored, INSTEAD OF unsupported —
80
+ all pinned divergences
81
+
82
+ Text search:
83
+ PARTIALLY VERIFIED — tsvector/tsquery/@@/ts_rank with simple-style
84
+ config; no ispell/synonym dictionaries
85
+
86
+ COPY / PREPARE / EXECUTE / SET / SHOW:
87
+ VERIFIED — text + csv COPY via copyFrom API hook; GUC subset
88
+
89
+ Collation:
90
+ Pinned C semantics; locale/ICU out of scope (documented)
91
+
92
+ Snapshots / determinism:
93
+ VERIFIED — PGMM logical round-trip, byte-identical snapshots, PRNG
94
+ rollback with transactions, fixed clock, post-restore lockstep
95
+
96
+ Differential tests (2026-08-21 initial audit):
97
+ Total: 3400 under `bun test` / `bun run test:postgres-compat`
98
+ (contract + fuzz + harness; Bun 1.4.0, PGlite/PostgreSQL 18.3)
99
+ Passed: 3400
100
+ Failed: 0
101
+ expect() calls: 8968
102
+ Files: 273 (246 contract)
103
+
104
+ Stateful / fuzz:
105
+ Seeds: 0x5a17e0e1 (+ POSTGRES_MEM_FUZZ_SEED override, PATH replay)
106
+ Differential grammar fuzz, per-area fuzz (17 areas), TLP + NoREC
107
+ metamorphic, stateful DST with minimizer/repro, mixed-stateful,
108
+ robustness (PostgresError-only), corpus regressions
109
+ Mismatches: 0
110
+
111
+ Harness integrity:
112
+ PGlite adapter compares rows (canonical text), column names/types,
113
+ SQLSTATE class + normalized messages, rowCount/command tags, and
114
+ logical state dumps after write sequences. Comparator meta-tests:
115
+ tests/harness/*.test.ts. Canaries: 6 deliberate sabotages, each
116
+ caught by the suite (bun run canaries). Skip register: empty.
117
+
118
+ Engine bugs found & fixed by the differential/fuzz process (this build):
119
+ 1. sum() crashed on certain inputs surfaced by grammar fuzz
120
+ 2. min()/max() returned unnormalized numeric cells
121
+ 3. NULL IN (empty subquery) returned NULL instead of false
122
+ 4. FULL JOIN did not enforce the join condition on one side
123
+ (regression tests added under tests/contract/*; area corpus scripts
124
+ replayed by tests/fuzz/corpus.test.ts)
125
+
126
+ Remaining known differences / intentional:
127
+ Custom PGMM snapshots; deterministic random()/now() by default
128
+ ({ random: "os" } / { now: "system" } match PostgreSQL entropy and
129
+ wall clock); sync single-session API; COPY payloads via copyFrom;
130
+ no 25P02 aborted-transaction state; trigger creation-order firing;
131
+ UPDATE OF ignored; no INSTEAD OF triggers; round(float8) ties away
132
+ from zero; '1e400'::float8 saturates; DROP CASCADE retains dependent
133
+ views; COMMENT ON not stored; version() banner; pg_get_viewdef
134
+ missing; EXPLAIN stubs. Machine-readable: compat/divergences.json
135
+ (18 entries, each pinned).
136
+
137
+ Final assessment:
138
+ Verified against PostgreSQL 18.3 (PGlite on Bun 1.4.0). Oracle
139
+ function/operator inventory is closed (0 silently missing).
140
+ Requirements matrix ingested with zero unknown statuses. Gate:
141
+ `bun run test:postgres-compat`. Triggers, text search, collation,
142
+ numeric extremes, and catalog long tail remain PARTIALLY VERIFIED
143
+ honestly — not “fully compatible because green.”
144
+ ```
145
+
146
+ Verification commands:
147
+
148
+ ```bash
149
+ bun run test:postgres-compat
150
+ bun run inventory
151
+ bun run requirements
152
+ bun run scenarios
153
+ bun run canaries
154
+ bun run typecheck
155
+ ```
@@ -0,0 +1,87 @@
1
+ # Compatibility
2
+
3
+ Goal: **PostgreSQL 18 SQL dialect behavioral parity** as a drop-in for the same statements against the reference oracle. Compatibility is proven by the differential contract suite and the fail-closed gate:
4
+
5
+ ```bash
6
+ bun run test:postgres-compat
7
+ ```
8
+
9
+ See [COMPATIBILITY-AUDIT.md](COMPATIBILITY-AUDIT.md) for the latest evidence-based audit report.
10
+
11
+ Reference oracle: **PostgreSQL 18.3** via PGlite (`@electric-sql/pglite`, real Postgres compiled to WASM, in-process). Inventory: `bun run inventory`. Construct catalog: `bun run scenarios` → [`compat/scenarios.ts`](compat/scenarios.ts). Divergences: [`compat/divergences.json`](compat/divergences.json). Requirements matrix: `bun run requirements` → `compat/requirements.json` + `compat/coverage.json`.
12
+
13
+ ## Proof surface
14
+
15
+ Differential tests compare a **tuple** per statement: rows (normalized to canonical PostgreSQL text where typed), column names and type names where requested, error SQLSTATE class + normalized message, command tag / `rowCount`, and transaction status, plus a **logical state dump** (catalog names, column definitions, row payloads, sequence values) after write sequences.
16
+
17
+ A catalog ID appearing in a test file is **not** proof by itself. Trivial probes are tracked in [`compat/smoke-baseline.json`](compat/smoke-baseline.json) and ratcheted downward (currently **0 smoke stubs** across 945 catalog scenarios). Generated operator/cast matrices live under [`tests/contract/matrices/`](tests/contract/matrices/). Observed mem≠oracle diffs must bind to a `compat/divergences.json` entry or be a **FAILURE** — unexplained diffs are not allowed.
18
+
19
+ Intentional differences are finite and machine-readable in `compat/divergences.json` (PGMM snapshots, seeded `random()`/`now()`, sync single-session API, no aborted-transaction state, EXPLAIN stubs, trigger-order/`UPDATE OF` edges, float8 rounding/overflow edges, …). Human-readable: [DIVERGENCES.md](DIVERGENCES.md).
20
+
21
+ ## Status vocabulary
22
+
23
+ | Status | Meaning |
24
+ | --- | --- |
25
+ | **VERIFIED** | Differential contracts (+ fuzz where applicable) cover happy path **and** meaningful edges vs oracle |
26
+ | **PARTIALLY VERIFIED** | Implemented; coverage thin or known edges remain |
27
+ | **UNSUPPORTED** | Missing from SQL surface (must fail loud; gate fails if oracle-exposed and unregistered) |
28
+ | **NOT APPLICABLE** | Outside the in-memory single-session dialect surface (roles/auth, replication, storage, wire protocol) |
29
+
30
+ ## Scope bound
31
+
32
+ Anything a PostgreSQL application can invoke through SQL against the PGlite **18.3** oracle must match observable behavior, except:
33
+
34
+ 1. **Snapshot format** — custom binary codec (`PGMM`), not `pg_dump` / on-disk clusters (logical state still round-trips).
35
+ 2. **Deterministic `random()` / `now()`** — seeded PRNG and fixed clock by default (injectable).
36
+ 3. **Single session** — no MVCC across connections, no isolation levels beyond one session, no `25P02` aborted-transaction state (documented divergence).
37
+ 4. **NOT APPLICABLE** rows in `compat/coverage.json` (roles, replication, VACUUM internals, LISTEN/NOTIFY, cursors, PL/pgSQL, extensions).
38
+
39
+ The oracle exposes **2787 builtin functions** and **74 operators** in `pg_catalog`; postgres-mem implements **301 functions** and **41 operators**, and every remaining item is an explicit entry in [`compat/unsupported-register.json`](compat/unsupported-register.json) with a reason (trigger/internal plumbing, admin/monitoring, unsupported type families, …). The gate fails closed on silence.
40
+
41
+ ## Requirements coverage (PostgreSQL 18 SQL commands)
42
+
43
+ `bun run requirements` ingests the PostgreSQL 18 SQL-commands documentation index: **183 commands** → 56 NOT APPLICABLE, 127 SQL-behavior. Of the SQL-behavior commands: **43 VERIFIED**, **26 PARTIALLY VERIFIED**, **58 UNSUPPORTED** (fail-loud, registered). Full detail: `compat/coverage.json`.
44
+
45
+ ## Feature matrix (summary)
46
+
47
+ | Area | Status | Notes |
48
+ | --- | --- | --- |
49
+ | Core DML / SELECT / joins / CTE / ON CONFLICT / RETURNING | VERIFIED | Contract + fuzz |
50
+ | Types: bool/int2/4/8, float4/8, numeric, text/varchar/char, bytea, uuid | VERIFIED | numeric is in-repo arbitrary precision |
51
+ | Date/time: date, time, timestamp[tz], interval + arithmetic | VERIFIED | Timezone conversions for named zones; some interval corners partial |
52
+ | Casts (implicit/assignment/explicit) | VERIFIED | Generated cast matrices from oracle |
53
+ | Arrays + unnest + subscripts/slices | VERIFIED | |
54
+ | JSON / JSONB operators + functions | VERIFIED | |
55
+ | Window functions (frames, EXCLUDE) | VERIFIED | |
56
+ | GROUPING SETS / ROLLUP / CUBE, DISTINCT ON, LATERAL, set ops | VERIFIED | |
57
+ | Recursive + data-modifying CTEs | VERIFIED | |
58
+ | Constraints: PK / UNIQUE / NOT NULL / CHECK / FK actions | VERIFIED | DEFERRABLE parsed, checked at statement end |
59
+ | Sequences / serial / identity | VERIFIED | |
60
+ | Schemas + search_path + pg_catalog / information_schema | VERIFIED | Catalog columns are the commonly-queried subset |
61
+ | Enums, domains, generated columns | VERIFIED | |
62
+ | Triggers (row-level, LANGUAGE sql-expressible) | PARTIALLY VERIFIED | Creation-order firing, `UPDATE OF` ignored, no INSTEAD OF (documented) |
63
+ | CREATE FUNCTION LANGUAGE sql | PARTIALLY VERIFIED | Scalar + set-returning; no polymorphic/variadic edges |
64
+ | Text search (tsvector / tsquery / @@ / ts_rank) | PARTIALLY VERIFIED | `simple`-style config; no ispell/synonym dictionaries |
65
+ | COPY FROM/TO (text, csv) | VERIFIED | Via `copyFrom` API hook / rows out |
66
+ | PREPARE / EXECUTE / DEALLOCATE, SET / SHOW / RESET | VERIFIED | GUC subset |
67
+ | Transactions / savepoints | VERIFIED | No `25P02` aborted state (documented divergence) |
68
+ | Collation / ordering | PARTIALLY VERIFIED | `C` semantics pinned; locale/ICU out of scope |
69
+ | Regex (`~`, `~*`, POSIX functions) | PARTIALLY VERIFIED | JS regex flavor mapped to POSIX ERE; documented edges |
70
+ | EXPLAIN | PARTIALLY VERIFIED | Stub plan shapes |
71
+ | MERGE / CALL / cursors / LISTEN / PL/pgSQL | UNSUPPORTED | Fail loud `0A000`, registered |
72
+ | Roles / GRANT / VACUUM / ANALYZE / LOCK | NOT APPLICABLE | Parsed no-ops where harmless |
73
+ | Wire protocol / multi-session MVCC / on-disk format | NOT APPLICABLE | |
74
+
75
+ ## How to verify
76
+
77
+ ```bash
78
+ bun run test:postgres-compat # requirements + gate + contract/fuzz/harness
79
+ bun run inventory # oracle pg_proc/pg_operator inventory
80
+ bun run requirements # refresh PostgreSQL 18 requirements + coverage
81
+ bun run scenarios # catalog + smoke ratchet
82
+ bun run build # ESM browser build
83
+ ```
84
+
85
+ Do not treat isolated unit tests of internal modules as proof of PostgreSQL compatibility. The differential suite is authoritative for SQL behavior; `test:postgres-compat` is the release gate.
86
+
87
+ **Parity claim:** Verified against **PostgreSQL 18.3** (PGlite). Features marked **VERIFIED** are oracle-proven. **PARTIALLY VERIFIED** rows must not be marketed as complete. **NOT APPLICABLE** is the only allowed permanent omission from the SQL drop-in claim.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chris Vouga
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.