Re: SQL:2011 Application Time Update & Delete
Paul A Jungwirth <pj@illuminatedcomputing.com>
From: Paul A Jungwirth <pj@illuminatedcomputing.com>
To: jian he <jian.universality@gmail.com>
Cc: SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com>,
Peter Eisentraut <peter@eisentraut.org>, Chao Li <li.evan.chao@gmail.com>, PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Date: 2026-06-18T02:29:17Z
Lists: pgsql-hackers
Attachments
- v2-0001-Forbid-BEFORE-UPDATE-triggers-changing-the-FOR-PO.patch (text/x-patch) patch v2-0001
On Tue, Apr 21, 2026 at 2:51 AM jian he <jian.universality@gmail.com> wrote:
>
> On Sun, Apr 19, 2026 at 7:18 AM Paul A Jungwirth
> <pj@illuminatedcomputing.com> wrote:
> >
> > Here is a patch that forbids changing the valid_at column in a BEFORE
> > trigger. It works by capturing the value before triggers run, then
> > checking afterwards if it is still the same (using the default btree
> > equality operator; probably a simple binary comparison is good
> > enough).
> >
> > ...
> The above works as expected, but the below is not what i expected.
>
> create type textrange as range (subtype = text, collation = "C");
> CREATE OR REPLACE FUNCTION trg_fpo()
> RETURNS TRIGGER LANGUAGE plpgsql AS
> $$
> BEGIN
> NEW.valid_at = '[A,d)';
> raise notice 'old: %, new: %', old, new;
> RETURN NEW;
> END;
> $$;
>
> create table fpo1(valid_at textrange, b int);
> CREATE TRIGGER fpo_before_update_row BEFORE UPDATE ON fpo1 FOR EACH
> ROW EXECUTE PROCEDURE trg_fpo();
> insert into fpo1 values ('[a,d]', 1);
>
> UPDATE fpo1 FOR PORTION OF valid_at FROM 'A' TO 'd' SET b = 2;
> NOTICE: old: ("[a,d]",1), new: ("[A,d)",2)
> ERROR: cannot change column "valid_at" from a BEFORE trigger because
> it is used in FOR PORTION OF
>
> Should I expect this to work without error, just like the table fpo3
> UPDATE FOR PORTION OF statement above?
That looks correct to me. In the C collation, uppercase letters come
before lowercase.
The row started as '[a,d)'. Then FOR PORTION OF valid_at FROM 'A' to
'd' leaves it as '[a,d)'
(because the intersection can only narrow). Then your BEFORE trigger
changes it to '[A,d)'.
Here is a new patch though, rebased and improved in a couple ways.
First, we are able to use ExecInitForPortionOf, added by another fix.
This reduces a lot of code duplication.
Also I moved the check out of ExecForPortionOfLeftovers. Now the time
between capturing the pre-trigger value and checking it is shorter: we
do the check right after triggers fire. This also means we don't have
to add fields to ForPortionOfState.
Yours,
--
Paul ~{:-)
pj@illuminatedcomputing.com
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Make ExecForPortionOfLeftovers() obey SRF protocol.
- 207cb2abcba0 19 (unreleased) landed
-
Add isolation tests for UPDATE/DELETE FOR PORTION OF
- b6ccd30d8ff6 19 (unreleased) landed
-
Add UPDATE/DELETE FOR PORTION OF
- 8e72d914c528 19 (unreleased) landed
-
Record range constructor functions in pg_range
- c257ba839718 19 (unreleased) landed
-
Add range_minus_multi and multirange_minus_multi functions
- 5eed8ce50ce9 19 (unreleased) landed
-
doc: Add section for temporal tables
- e4d8a2af07f5 19 (unreleased) landed
-
Add assertion check for WAL receiver state during stream-archive transition
- 65f4976189b6 19 (unreleased) cited