Re: SQL:2011 Application Time Update & Delete

jian he <jian.universality@gmail.com>

From: jian he <jian.universality@gmail.com>
To: Paul A Jungwirth <pj@illuminatedcomputing.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-04-21T09:51:18Z
Lists: pgsql-hackers
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).
>
> This copy+check only happens if the table has BEFORE UPDATE row
> triggers, so there is no cost in most cases.
>
> I'm raising ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION, which is what we
> use when (basically) a trigger & UPDATE both change a row in a way
> that leaves the user intent unclear. I think that's a very close fit
> here, but you could argue we should use the same errcode as SETing
> valid_at. That is ERRCODE_SYNTAX_ERROR. That strikes me as a
> questionable choice, actually. Personally I think using different
> errcodes is correct though.
>
HI.
After applying v1-0001-Forbid-BEFORE-UPDATE-triggers-changing-the-FOR-PO.patch

----------------------------------------------------
CREATE OR REPLACE FUNCTION trg_fponum() RETURNS TRIGGER LANGUAGE plpgsql AS
$$
BEGIN
  NEW.valid_at = '[1,12)';
  raise notice 'old: %, new: %', old, new;
  RETURN NEW;
END;
$$;
create table fpo3(valid_at int4range, b int);
CREATE TRIGGER fpo_before_update_row BEFORE UPDATE ON fpo3 FOR EACH
ROW EXECUTE PROCEDURE trg_fponum();
insert into fpo3 values('[1,100]', 1);
UPDATE fpo3 FOR PORTION OF valid_at FROM 1 TO 12 SET b = 2;
----------------------------------------------------
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?



--
jian
https://www.enterprisedb.com/



Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Make ExecForPortionOfLeftovers() obey SRF protocol.

  2. Add isolation tests for UPDATE/DELETE FOR PORTION OF

  3. Add UPDATE/DELETE FOR PORTION OF

  4. Record range constructor functions in pg_range

  5. Add range_minus_multi and multirange_minus_multi functions

  6. doc: Add section for temporal tables

  7. Add assertion check for WAL receiver state during stream-archive transition