| From: | Tender Wang <tndrwang(at)gmail(dot)com> |
|---|---|
| To: | PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Subject: | MERGE loses UPDATE transition rows when moving rows between partitions |
| Date: | 2026-11-05 06:47:29 |
| Message-ID: | CAHewXNk8MgaFMD87s=xHeguzmErEjsqeroxrMyQbKyXwG5eocw@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
While working on the fix for MERGE on a partitioned table with a
subplan in the UPDATE action, I noticed that the bug dated back to
the original MERGE implementation. That prompted me to use an LLM
to look for similar omissions in the MERGE executor code. It
identified the following issue, which I reproduced.
CREATE TABLE mx_t (i int, v int) PARTITION BY LIST (i);
CREATE TABLE mx_t1 PARTITION OF mx_t FOR VALUES IN (1);
CREATE TABLE mx_t2 PARTITION OF mx_t FOR VALUES IN (2);
INSERT INTO mx_t VALUES (2, 20);
CREATE FUNCTION mx_dump_update() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
RAISE NOTICE 'old: %, new: %',
(SELECT string_agg(ot::text, ', ') FROM ot),
(SELECT string_agg(nt::text, ', ') FROM nt);
RETURN NULL;
END;
$$;
CREATE TRIGGER mx_upd AFTER UPDATE ON mx_t
REFERENCING OLD TABLE AS ot NEW TABLE AS nt
FOR EACH STATEMENT EXECUTE FUNCTION mx_dump_update();
MERGE INTO mx_t USING (VALUES (2)) s(i) ON mx_t.i = s.i
WHEN MATCHED THEN UPDATE SET i = 1, v = 999;
The MERGE updates one row, but the UPDATE trigger reports both
transition tables as empty. A plain UPDATE mx_t SET i = 1, v = 999
WHERE i = 2, run separately on the same initial data, reports
(2,20) in the old table and (1,999) in the new table.
A cross-partition UPDATE moves the row via a DELETE and an INSERT.
The transition capture code in ExecDeleteEpilogue() and ExecInsert()
checks for CMD_UPDATE, but the statement operation is CMD_MERGE
when a MERGE action performs the move. As a result, the row versions
are omitted from the UPDATE transition tables. If the MERGE also has
DELETE and INSERT actions with transition tables, the moved row
versions can be captured in those tables instead.
The attached patch recognizes both halves of the move as part of
the UPDATE action. It also keeps moved rows out of the DELETE and
INSERT transition tables when no UPDATE transition table is requested.
The patch includes regression tests for both cases.
--
Thanks,
Tender Wang
| Attachment | Content-Type | Size |
|---|---|---|
| 0001-Fix-MERGE-cross-partition-transition-tables.patch | text/plain | 6.4 KB |
| From | Date | Subject | |
|---|---|---|---|
| Previous Message | Chao Li | 2026-11-05 06:43:54 | Fix stale column context after COPY FROM conversion errors |