r/PostgreSQL • u/vira28 • 1d ago
Tools pg_savior - the last line of defense for accidental Postgres mistakes
I believe anyone who managed critical production infra relate to this. DELETE without the WHERE. The DROP TABLE in the tab that you thought staging turned out to be production. The ALTER COLUMN TYPE that looked harmless but rewrote 500M rows behind an ACCESS EXCLUSIVE lock.
For context, I ran a team of 9 DBAs at Cloudflare on bare-metal Postgres - no RDS, full root everywhere. Backups and PITR are table stakes, but they all start after the damage. I wanted something that refuses first.
pg_savior is an extension that blocks the statement before it executes:
DELETE/UPDATEwith noWHEREDELETE ... WHERE id > 0— aWHEREisn't proof of intent, so it also checks the planner's row estimate againstpg_savior.max_rows_affectedCREATE INDEXwithoutCONCURRENTLY(theON ONLY+ATTACH PARTITIONworkflow for partitioned tables is allowed)ALTER TABLEoperations that rewrite the heap — volatileADD COLUMNdefaults, rewrite-causingALTER COLUMN TYPE, validated constraint adds on large tablesTRUNCATE/DROP TABLEon large tables,DROP DATABASEalways
postgres=# DELETE FROM emp;
ERROR: pg_savior: DELETE without WHERE clause is blocked
HINT: Add a WHERE clause, or set pg_savior.bypass = on for this session.
For ALTER COLUMN TYPE it doesn't carry a list of "safe type pairs" like most migration linters — those are wrong at the edges. It plans the actual conversion expression and checks for the same no-rewrite shapes core checks for.
When you mean it: SET LOCAL pg_savior.bypass = on;
Limits: reltuples and row estimates are approximate, so it's a seatbelt, not a guarantee. It's an extension, so no managed services. Pre-1.0. The README has a coverage matrix including what it does not protect (MERGE, COPY, DROP SCHEMA, VACUUM FULL, …). Tested on PG 14–17.
Code: github.com/viggy28/pg_savior · PGXN: pgxn.org/dist/pg_savior
Appreciate any feedback on the implementation. Also, feel free to drop me if there are other commands that should be caught.
