bug: UPDATE FOR PORTION OF interact with updatable view

First seen: 2026-04-12 15:11:19+00:00 · Messages: 2 · Participants: 2

Latest Update

2026-05-11 · opus 4.7

UPDATE/DELETE FOR PORTION OF on Updatable Views: Rewriter Assertion Failure and Server Crash

Core Problem

This thread reports a bug in PostgreSQL 19's temporal table feature — specifically the FOR PORTION OF clause of UPDATE/DELETE — when combined with the automatically-updatable views subsystem. The issue exposes a gap in the view rewriter's validation logic: it fails to reject FOR PORTION OF operations targeting view columns that are not simple references to a base table column (e.g., they involve expressions like ('[' || abs(b) || ',20]')::int4range).

Reproducer

CREATE TABLE base_tbl (a int, b int, c int);
CREATE VIEW rw_view15 AS
  SELECT a, ('[' || abs(b) || ',20]')::int4range AS b
  FROM base_tbl;

UPDATE rw_view15 FOR PORTION OF b FROM 1 TO 10 SET a = 2;
-- ERROR: attribute number 2 not found in view targetlist
-- (from rewriteTargetView, rewriteHandler.c:3779)

DELETE FROM rw_view15 FOR PORTION OF b FROM 1 TO 10;
-- Server crash

Architectural Significance

The failure location — rewriteTargetView() in rewriteHandler.c — is the heart of the automatically-updatable views machinery. When a DML statement targets a view, the rewriter translates references to view columns into references on the underlying base relation. This translation requires each affected view column to be a plain Var pointing at a base-table column; expressions cannot be "reverse-engineered" into assignments on the base table.

The existing updatability logic correctly rejects UPDATE rw_view15 SET b = ... with:

cannot update column "b" of view "rw_view15" / View columns that are not columns of their base relation are not updatable.

However, FOR PORTION OF is a new way in which an UPDATE/DELETE statement can implicitly modify a column: the temporal range column is split by the server into pre- and post-portion rows, which requires writing back adjusted range values into that column. The updatability analysis added for FOR PORTION OF did not account for this case, so:

  1. For UPDATE, the rewriter proceeds past the initial check and later trips an internal sanity assertion (attribute number N not found in view targetlist), which is an XX000 internal error — user-visible evidence of a missed check.
  2. For DELETE, the path is even less defended and dereferences something invalid, crashing the backend.

Both should be caught early in rewriteTargetView and surfaced as clean user errors consistent with the existing "not updatable" family.

Proposed Fix

Paul Jungwirth — the original author of the SQL:2011 temporal features in PostgreSQL — attached a patch about four weeks after the report. Based on his description, the fix:

Implications

Key Technical Insights

  1. XX000 in a user-reachable path is always a bug. The attribute number 2 not found in view targetlist message originates from an internal consistency check; encountering it from pure SQL means an earlier semantic gate was missing. This is the classic signature of a feature (FOR PORTION OF) that was not cross-wired with an orthogonal subsystem (auto-updatable views).

  2. FOR PORTION OF is an implicit write to the range column. Unlike a regular UPDATE, the user does not name the range column in SET, yet the executor must still write to it. Any code that enumerates "columns being modified" for authorization or updatability purposes must treat the FOR PORTION OF target column as written, even for DELETE — which is unusual, since DELETE normally writes no columns.

  3. The DELETE crash vs. UPDATE error asymmetry suggests the UPDATE path at least reaches a defensive check in the rewriter, while the DELETE path skips it entirely. This is a hint that the FOR PORTION OF integration added validation on the UPDATE rewrite branch but forgot the symmetric DELETE branch — a common oversight given that DELETE historically has no targetlist manipulation.

  4. Trust in the fix: Paul Jungwirth is the implementer of the temporal/FOR PORTION OF feature itself, so he is the domain authority here. A fix from him on his own feature, during the v19 open-items window, is essentially the expected and authoritative resolution.

Participant Roles

Timeline

The issue was reported in mid-April 2026, during the v19 development / open-items phase. About four weeks later, in early May 2026, the feature's original author posted a patch. No disagreement emerged on the mailing list; the proposed direction — reject these statements in rewriteTargetView with a message consistent with existing view-updatability errors — is the only architecturally sound option.