2026-06-01 · claude-opus-4-6
Monthly Summary: Rebuild CHECK Constraints After Generated Column SET EXPRESSION (May 2026)
Overview
This thread addressed a data integrity bug where ALTER TABLE ... ALTER COLUMN ... SET EXPRESSION on generated columns failed to revalidate CHECK constraints and indexes containing whole-row Var references (varattno = 0). The root cause is architectural: PostgreSQL's pg_depend system records whole-row dependencies at the relation level (attnum=0), not per-column, so RememberAllDependentForRebuilding() misses them when scanning for the target column's attnum.
Key Resolution: Policy Handling Dropped
The most significant design decision this month was removing RLS policy blocking logic from the patch. Ayush Tiwari convincingly argued that:
- Changing a generation expression doesn't change the row type — policies evaluate at query time with the new column value and remain valid
- The v4 patch would over-block by rejecting
SET EXPRESSION on table r2 if an unrelated table r1's policy happened to reference r2's row type
Jian He agreed, and v5 explicitly ignores whole-row policy references with an explanatory comment.
Patch Evolution (v1 → v5)
| Version |
Approach |
| v1 |
Rebuild all CHECK constraints on the relation (simple but over-broad) |
| v2 |
Introduced RememberWholeRowDependentForRebuilding() — inspects expression trees via pull_varattnos() to rebuild only objects with actual whole-row Vars; handled CHECK, indexes, and policies |
| v3-v4 |
Cosmetic/refactoring: improved error messages, typo fixes, commit message cleanup |
| v5 |
Removed policy error path; focused scope on CHECK constraints and indexes only |
Final Patch Scope (v5)
The current patch introduces RememberWholeRowDependentForRebuilding() which:
- Queries
pg_depend for objects dependent on the relation at attnum=0
- Inspects expression trees to confirm whole-row Var presence
- CHECK constraints → added to rebuild/revalidation list
- Indexes (expression indexes and partial index predicates) → added to rebuild list
- RLS policies → explicitly skipped (safe; documented with comment)
Function signature retains attnum/colName parameters for forward compatibility with future DDL operations (DROP COLUMN, SET DATA TYPE) that will need the policy rejection path.
Broader Context
This is part of a series addressing whole-row Var gaps across DDL:
ALTER TABLE DROP COLUMN (commitfest patch 5988)
ALTER COLUMN SET DATA TYPE (commitfest patch 6055)
ALTER COLUMN SET EXPRESSION (this patch)
All share the same fundamental pattern: scan for relation-level dependencies, inspect expressions for whole-row Vars, then rebuild or reject.
Current Status
v5 has a soft sign-off from Ayush (no further comments) and independent testing confirmation from Solai validating the fix against current master. The patch is on the PostgreSQL 19 Open Items wiki.
2026-06-01 · claude-opus-4-6
Incremental Update: Minor Code Review Nitpick on Error Handling
Summary
A single new review comment from Zsolt Parragi (returning reviewer) raises a minor but valid code quality question about error severity in the v5 patch.
Technical Point
Zsolt questions why the patch uses elog(WARNING) when encountering a NULL conbin (constraint expression binary representation) during the whole-row dependency scan:
if (isnull)
elog(WARNING, "null conbin for relation \"%s\"",
RelationGetRelationName(rel));
His argument: a NULL conbin in pg_constraint for a CHECK constraint should never occur in a healthy catalog. Most existing code paths in PostgreSQL that encounter this condition treat it as an ERROR (or even elog(ERROR)), not a WARNING. Using WARNING allows execution to continue with potentially undefined behavior (the constraint expression pointer would be invalid), while ERROR would abort the operation cleanly.
This is a valid observation — in PostgreSQL's codebase, conbin being NULL for a CHECK constraint indicates catalog corruption, and the standard pattern is to error out rather than warn and continue. Examples include RelationGetCheckConstraints() and pg_get_constraintdef_worker() which both treat NULL conbin as an error condition.
Significance
This is a one-line fix (changing WARNING to ERROR) with no architectural implications. No new patch version has been posted in response yet.