FOR PORTION OF silently ignored on views with DO INSTEAD rules

From: Ewan Young <kdbase(dot)hack(at)gmail(dot)com>
To: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Cc: Peter Eisentraut <peter(at)eisentraut(dot)org>, pj(at)illuminatedcomputing(dot)com
Subject: FOR PORTION OF silently ignored on views with DO INSTEAD rules
Date: 2026-09-03 04:19:49
Message-ID: CAON2xHO5FJ1jC87cQhGg+KMG5QR7ZaifJwN24rPjMqCGYn-hzA@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

An UPDATE/DELETE ... FOR PORTION OF against a view that has an
unqualified DO INSTEAD rule silently ignores the FOR PORTION OF clause
and modifies (or deletes) the whole temporal row instead of just the
requested portion -- no error, no warning:

CREATE TABLE t (id int, valid_at daterange, name text);
INSERT INTO t VALUES (1, '[2020-01-01,2021-01-01)', 'a');
CREATE VIEW v AS SELECT * FROM t;
CREATE RULE v_upd AS ON UPDATE TO v DO INSTEAD
UPDATE t SET name = NEW.name WHERE id = OLD.id;

UPDATE v FOR PORTION OF valid_at FROM '2020-06-01' TO '2020-07-01'
SET name = 'b';
SELECT * FROM t;
id | valid_at | name
----+-------------------------+------
1 | [2020-01-01,2021-01-01) | b -- whole row changed

The same statement on the base table (or a plain auto-updatable view)
correctly splits the row three ways. DELETE is worse: DELETE ... FOR
PORTION OF through such a view removes the entire row.

The cause is that an unqualified INSTEAD rule replaces the original
query with the rule's action during rewriting, so rewriteTargetView()
-- the path that carries the query's forPortionOf through a view -- is
never reached, and the rule action has forPortionOf = NULL. This is
the exact analog of the INSTEAD OF trigger case that dfce19c2300
("Forbid FOR PORTION OF on views with INSTEAD OF triggers") already
rejects with a feature-not-supported error (5b5e99047ab on
REL_19_STABLE); the DO INSTEAD rule sibling was left unguarded.

The attached patch rejects FOR PORTION OF when an unqualified INSTEAD
rule fires on a view, using the same error as the trigger case. A
DO ALSO rule does not replace the query, so FOR PORTION OF keeps working
on the automatically-updatable path; the tests cover that as well as the
UPDATE and DELETE INSTEAD-rule cases. make check passes. The patch
is against master; the same code (and the same behavior) is present on
REL_19_STABLE.

--
Regards,
Ewan Young

Attachment Content-Type Size
v1-0001-Reject-FOR-PORTION-OF-on-views-with-instead-rules.patch application/octet-stream 7.7 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Antonin Houska 2026-09-03 04:42:06 Re: REPACK (ANALYZE) within transaction block segfaults
Previous Message Fujii Masao 2026-09-03 04:19:30 Re: Stabilize recovery conflict stats checks in 031_recovery_conflict.pl