Liking cljdoc? Tell your friends :D

PostgreSQL regression baseline, measured

Measured 2026-09-21 against PostgreSQL 17's own src/test/regress, with bb pg-regress-with-fixtures (fixtures bootstrapped, one isolated database per run) and the diff taken against PostgreSQL's expected output with its source-excerpt presentation lines (LINE n: and the caret) removed from both sides.

The campaign inventory in campaign.edn answers how much of the schedule has been triaged. This answers the other question: how much of it we actually answer the way PostgreSQL does.

What we measure

pg_regress fails a file on any difference, so a per-file pass rate would read zero and say nothing. Two numbers are reported instead:

  • exact API match — our output is byte-identical to PostgreSQL's, modulo the parser's source excerpts. This is the real pass count.
  • agreement — the share of PostgreSQL's own expected lines that appear, in order, in ours. A file at 80% answers four fifths of what PostgreSQL prints, which is what a partially-supported area looks like from a client.

The numbers

application-facing files in the schedule153 (222 scheduled, 69 out of scope)
measured151 (2 did not complete: generated, test_setup)
exact API match5 — boolean, delete, md5, portals_p2, select_having
100% of PostgreSQL's lines (some extra lines of ours)8
≥90%19
≥75%34
median agreement58%
overall, weighted by file size50.6% (100,894 of 199,529 lines)

What accounts for the other half

Errors we raise across the corpus, by class:

classerrorsfiles
SQL parse error (JSqlParser rejects the syntax)307293
relation does not exist (mostly a cascade from an earlier failure)255572
function does not exist245292
transaction aborted (a cascade of the above)70733
unsupported statement (MERGE, and others JSqlParser parses but we refuse)56428
CREATE FUNCTION54967
type does not exist47440
partitioning (PARTITION BY, ATTACH PARTITION)44222
column does not exist42649
CREATE TRIGGER28918
DROP FUNCTION24142
CREATE RULE13415

The largest single lever is the parser: 3072 statements never reach the translator. The syntax it rejects, by frequency, is SQL/JSON (JSON_EXISTS, JSON_VALUE, JSON_TABLE), XML (xmlserialize, xmlparse), window-frame EXCLUDE, INSERT … DEFAULT VALUES, interval qualifiers (interval '1' minute to second), and the partitioning grammar.

The second is server-side routines: CREATE FUNCTION / TRIGGER / RULE account for 972 errors across 82 files, and they cascade — a file that cannot create its helper function then fails every statement that calls it.

Two smaller, self-contained ones:

  • Notices. PostgreSQL prints 1352 NOTICE / WARNING / INFO lines across 73 files that we never send, because the wire layer has no NoticeResponse. advisory_lock is at 268 of 276 lines and every remaining difference is a missing WARNING.
  • Missing functions, led by range constructors (numrange, int4range, daterange), to_timestamp / to_date (the formatting.c template engine, already Phase 6), and text search (to_tsquery, websearch_to_tsquery).

Reproducing

bb pg-regress-with-fixtures advisory_lock       # one file
bb pg-regress-wave inventory                    # the classification, not this

The measurement script and per-file table live with the session that produced them; the table below is the state on the date above.

Per-file agreement

fileagreement
bit100%
boolean100%exact
database100%
delete100%exact
md5100%exact
portals_p2100%exact
select_having100%exact
select_implicit99%
int298%
numeric97%
advisory_lock97%
oid96%
int495%
money95%
enum95%
varchar95%
comments94%
int893%
mvcc90%
transactions86%
case83%
create_aggregate82%
type_sanity82%
async81%
uuid81%
create_operator80%
char79%
errors79%
misc_sanity79%
collate78%
lseg78%
lock77%
sequence76%
time76%
drop_operator74%
copydml73%
line73%
create_type73%
float872%
truncate72%
namespace71%
temp70%
triggers69%
limit69%
prepared_xacts68%
jsonb68%
alter_generic68%
fast_default67%
alter_operator67%
alter_table67%
foreign_key67%
strings66%
text65%
drop_if_exists65%
copy65%
psql65%
tablesample64%
rowtypes64%
merge64%
select_distinct64%
expressions63%
insert_conflict63%
create_table63%
update63%
json_encoding62%
domain62%
constraints61%
copyselect60%
macaddr60%
create_cast60%
json59%
date59%
insert59%
plancache58%
select_into58%
conversion58%
psql_crosstab58%
portals57%
arrays57%
aggregates57%
identity56%
opr_sanity56%
select56%
regex56%
prepare56%
sqljson_jsontable55%
name54%
union53%
updatable_views53%
select_distinct_on52%
misc52%
float452%
window52%
tstypes51%
create_schema51%
create_procedure51%
create_index51%
path51%
copy250%
with49%
timetz49%
tsearch48%
interval48%
polymorphism47%
polygon47%
macaddr846%
tsrf46%
create_function_sql46%
inherit46%
subselect46%
random45%
matview45%
returning45%
largeobject43%
box43%
misc_functions42%
sqljson_queryfuncs42%
create_view42%
numerology41%
typed_table41%
sqljson41%
create_table_like40%
xml39%
xid39%
rules39%
join38%
create_misc38%
sysviews37%
dbsize35%
rangetypes35%
jsonpath_encoding34%
circle33%
tsdicts33%
pg_lsn31%
inet28%
txid28%
unicode28%
rangefuncs28%
regproc27%
multirangetypes27%
jsonb_jsonpath26%
timestamptz24%
point22%
jsonpath20%
explain20%
horology19%
timestamp19%
select_views8%
groupingsets8%
geometry8%
xmlmap4%

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close