[PATCH] Rebuild CHECK constraints after generated column SET EXPRESSION

First seen: 2026-05-11 09:58:23+00:00 · Messages: 13 · Participants: 4

Latest Update

2026-06-04 · claude-opus-4-6

Incremental Update: v6 Patch Posted with Minor Fix

Summary

Jian He responded to Zsolt Parragi's review comment with a brief acknowledgment ("OK.") and posted what appears to be a v6 patch incorporating the suggested change (changing elog(WARNING) to elog(ERROR) for NULL conbin) along with a slightly rephrased commit message.

Technical Substance

This is a minimal update:

No architectural changes, no new technical arguments, no design shifts. This is purely a housekeeping revision addressing the prior review nitpick.

History (2 prior analyses)
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:

  1. Queries pg_depend for objects dependent on the relation at attnum=0
  2. Inspects expression trees to confirm whole-row Var presence
  3. CHECK constraints → added to rebuild/revalidation list
  4. Indexes (expression indexes and partial index predicates) → added to rebuild list
  5. 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.