| From: | Zsolt Parragi <zsolt(dot)parragi(at)percona(dot)com> |
|---|---|
| To: | PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>, "Paul A(dot) Jungwirth" <pj(at)illuminatedcomputing(dot)com> |
| Subject: | FOR PORTION OF: BEFORE INSERT triggers can silently drop leftover rows? |
| Date: | 2026-09-03 14:10:45 |
| Message-ID: | CAN4CZFNSOA_LXWKC6sAOduWVsaxjzmFBNEHUQii89KUnMhBtcw@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hello!
Currently a before insert trigger returning NULL can drop FOR PORTION
OF leftovers. This seems unintuitive to me, and the original thread
only discussed trigger firing order, not whether it should allow
dropping the leftovers.
Let's say we have a table that silently discards backdated records:
CREATE TABLE emp (
id int,
valid_at daterange,
salary int,
PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
);
INSERT INTO emp VALUES (1, '[2015-01-01,infinity)', 1000);
CREATE FUNCTION no_backdated() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
IF upper(NEW.valid_at) <= current_date THEN
RETURN NULL;
END IF;
RETURN NEW;
END $$;
CREATE TRIGGER no_backdated
BEFORE INSERT ON emp FOR EACH ROW EXECUTE FUNCTION no_backdated();
Then we perform an UPDATE on it:
UPDATE emp FOR PORTION OF valid_at FROM current_date TO 'infinity'
SET salary = 1100 WHERE id = 1 RETURNING *;
Which causes the past portion to be silently discarded.
I think this can be very confusing, as the user didn't execute any
insert statements directly.
Shouldn't this scenario either result in an error, or be at least very
clearly documented, or print some diagnostics? I first considered
proposing a patch that errors out for this scenario, but I am not sure
if that's the proper way to handle this.
While looking into this I also found out that there's already a
precedent for this in the code, a cross partition UPDATE similarly
fires a before insert trigger, but with an important difference: in
that case, if the insert drops the row the UPDATE reports 0 rows,
while FOR PORTION OF always reports 1 rows, regardless if the
leftovers gets inserted or not. (UPDATE is also questionable, as it
deletes 1 row in that case, I am not saying that it's better, it's
just different)
Perhaps a better question for 20 and later is: shouldn't the trigger
be able to check if this is a leftover row, or if it's a
partition-moving update?
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Japin Li | 2026-09-03 14:17:07 | Re: [PATCH] Allow bare library names for non-superuser LOAD |
| Previous Message | shveta malik | 2026-09-03 13:57:06 | Re: Follow-up review items for update_deleted |