On September 7, PostgreSQL’s release team reverted SQL/PGQ, the built-in property-graph query feature, out of the PostgreSQL 19 branch. Forty-seven commits gone: the feature itself and every post-commit fix layered on top of it since March. It had been in development since February 2024. It shipped in beta. It is not shipping in 19.
The proximate cause wasn’t a single catastrophic bug report. It was a pgsql-hackers thread from August 25 titled “scary patch contest,” in which Robert Haas, one of PostgreSQL’s longest-serving committers, wrote that he’d asked Claude to rank the release’s patches by how many bugs had been fixed in them since feature freeze. SQL/PGQ was one of six patches the exercise flagged. Nine days after Andres Freund replied to that thread with his own independent findings, SQL/PGQ was gone.
What SQL/PGQ actually did
SQL/PGQ doesn’t store graphs. It’s a semantic layer over relational tables you already have. You declare a property graph on top of existing tables and foreign keys, then query it with pattern-matching syntax instead of joins:
create property graph "emp_dept_graph"
vertex tables ("department" label "department", "employee" label "employee")
edge tables (
"employee" as "reports"
source key ("empno") references "employee" ("empno")
destination key ("mgr") references "employee" ("empno")
label "reports_to"
);
select * from graph_table (
"emp_dept_graph"
match (e is "employee" where e."name" = 'JONES')
-[is "reports_to"]-> (m is "employee")
columns (m."name" as "manager_name")
);
Run EXPLAIN on that and the plan is identical to the equivalent JOIN, down to the join type and cost estimate, except for the alias names. That’s not a criticism of the implementation, it’s the design: SQL/PGQ is meant to make relationship-heavy queries readable without inventing a new storage engine. The tables, indexes, and planner are untouched.
What PostgreSQL 19 didn’t ship, even before the revert, was the part that would have made the feature more than a syntax convenience: variable-length traversal, the * quantifier that lets a pattern match a path of unknown depth (-[:knows*1..5]->). Without it, every multi-hop pattern in the shipped feature was a fixed number of explicit hops, exactly as limited as writing out the joins by hand. The pgsql-hackers thread on how to implement variable-length edges runs back to January, and it never converged. One camp wanted to rewrite * patterns into WITH RECURSIVE, simple to implement but with a memory profile that gets ugly fast: a design document posted to the list modeled a graph with a branching factor of 100 and a traversal depth of 4, and the CTE’s worktable holds roughly 101 million partial paths in memory before the query returns a single row, because a recursive CTE materializes every intermediate path rather than discarding the ones that don’t pan out. The other camp wanted a custom executor node doing true depth-first search with backtracking, which keeps memory at O(depth) instead of O(branching^depth), but requires a new plan node with its own PlanState stack, real surgery on the planner and executor. Two years in, neither had landed. So the shipped feature quietly dropped the hard part and kept the syntax sugar.
The tally that ended it
Haas’s post didn’t argue SQL/PGQ was broken. It listed six post-freeze patches by bug-fix count and asked which ones the project should still trust going into release: RI fast-path FK checks (about 16 fixes, including an out-of-bounds write and five distinct classes of incorrect enforcement), REPACK CONCURRENTLY (28 fixes, including data loss bugs also affecting VACUUM FULL), online data checksums (about 25 fixes, mostly state-machine holes), UPDATE/DELETE FOR PORTION OF (17 fixes, three of them security), SQL/PGQ (17 fixes, lower severity individually), and postgres_fdw statistics import (7 fixes in one file of contrib code). Haas himself was ambivalent about SQL/PGQ specifically, calling it “a bigger feature so I’m more concerned” rather than making a hard call.
Two things moved it from ambivalent to reverted. First, speed: within an hour, Daniel Gustafsson replied “I’ll prepare a revert,” fast enough that Bruce Momjian posted “Uh, I am confused. We are now considering reverting these?” a few messages later. Second, and more specific to SQL/PGQ, Andres Freund weighed in the next day with an independent finding from unrelated work nearby in the codebase: ALTER PROPERTY GRAPH didn’t verify it was actually operating on a property graph. Freund’s argument for treating SQL/PGQ as higher risk than the FK and checksum patches wasn’t the bug count, it was exposure: checksums and REPACK are superuser-only operations, so a bug there needs a privileged attacker. SQL/PGQ is reachable by any user who can query a graph, with no separate permission to disable it, so a security bug in it is exploitable at ordinary privilege. That asymmetry, not the raw fix count, is why PGQ and FOR PORTION OF ended up the two riskiest items on Haas’s own reading, and PGQ was the one with the bigger unfinished surface behind it.
By September 16, the same triage thread had produced five more reverts on the 19 branch beyond SQL/PGQ, 74 commits total in that window alone, including FOR PORTION OF (23 commits, September 15) and online data checksums (30 commits, September 16, pulled from the stable branch but left active on master for a future release).
What this changes
If a 2027 plan assumes SQL/PGQ in production PostgreSQL 19, it isn’t there, and won’t be until whatever ships as 20. That’s the easy part. The less obvious part is that even fully shipped, fixed-depth SQL/PGQ buys you nothing at execution time over hand-written joins, since the planner produces the same plan either way, so treat it as a readability layer, not a performance feature, once it does land. For anything variable-depth today, you’re writing WITH RECURSIVE yourself, and the number that matters is branching factor raised to depth, materialized entirely in the CTE’s worktable before the first row streams out. Size that before you ship a hierarchy query against a table with real fan-out, not after a customer’s org chart takes down the connection pool.
The triage method is worth stealing independent of the outcome. Counting bug fixes per patch since freeze, rather than lines changed or subjective feature importance, is a concrete, cheap signal for “how much hidden complexity is still in here,” and it doesn’t require an LLM to compute, Haas’s prompt just made it fast. What it doesn’t replace is judgment about exposure: Freund’s point that a bug’s blast radius depends on who can trigger it, not how many commits fixed it, is what actually separated SQL/PGQ from the three patches that got a calmer, more contested discussion. A raw defect count flags where to look. It doesn’t tell you what to do once you’re looking, and the “I’ll prepare a revert” reply landing before that distinction got made is exactly what Momjian pushed back on.
Sources
[1] https://www.postgresql.org/message-id/flat/CA%2BTgmob9NY6m0YNFTQ4nFH2d0iC9SQRruDYxfndGKKzh8OC80w%40mail.gmail.com: Robert Haas et al., “scary patch contest,” pgsql-hackers, August 25-26, 2026
[2] https://commitfest.postgresql.org/patch/4904/: SQL Property Graph Queries (SQL/PGQ) commitfest entry, Peter Eisentraut and Ashutosh Bapat
[3] https://www.postgresql.org/message-id/CAEG8a3+fdtHSEUGCd7o74ChO+wq4yV07NyjTh_dOmuBBye_1Wg@mail.gmail.com: Variable Length Edge implementation design discussion, pgsql-hackers, January 2026
[4] https://www.commandprompt.com/blog/two-features-just-left-postgresql-19/: Joshua D. Drake, “Two features just left PostgreSQL 19,” CommandPrompt, September 8, 2026
[5] https://www.commandprompt.com/blog/postgresql-19-sept-08-sept-16-2026/: Joshua D. Drake, “PostgreSQL 19: Sept 08 - Sept 16, 2026,” CommandPrompt, September 16, 2026
[6] https://dev.to/franckpachot/from-joins-to-graph-edges-sqlpgq-in-postgresql-19-2doo: Franck Pachot, “From Joins to Graph Edges: SQL/PGQ in PostgreSQL 19,” DEV Community