Re: BUG #18238: Cross-partitition MERGE/UPDATE with delete-preventing trigger leads to incorrect memory access - Mailing list pgsql-bugs

From Richard Guo
Subject Re: BUG #18238: Cross-partitition MERGE/UPDATE with delete-preventing trigger leads to incorrect memory access
Date
Msg-id CAMbWs48TaqQ-moMVu2tEbCB7qH5r-CMzd4LLFGov1LF-406FfQ@mail.gmail.com
Whole thread Raw
In response to Re: BUG #18238: Cross-partitition MERGE/UPDATE with delete-preventing trigger leads to incorrect memory access  (Dean Rasheed <dean.a.rasheed@gmail.com>)
Responses Re: BUG #18238: Cross-partitition MERGE/UPDATE with delete-preventing trigger leads to incorrect memory access
List pgsql-bugs

On Mon, Dec 11, 2023 at 8:53 PM Dean Rasheed <dean.a.rasheed@gmail.com> wrote:
The easiest way to do that is to have ExecDelete() return the
TM_Result status to ExecCrossPartitionUpdate(). I think
ExecCrossPartitionUpdate() should then return the TM_Result status to
ExecUpdateAct(), so that it can return the correct status, rather than
just assuming TM_Updated on failure, though possibly that's not
strictly necessary.

The simplest fix is for ExecMergeMatched() to pass canSetTag to
ExecUpdateAct(), so that it updates the command tag, if it does a
cross-partition update. That makes that code path in
ExecMergeMatched() more consistent with ExecUpdate().

So I think we need something like the attached.

I think this is the right way to go.  +1.

BTW, while testing this patch, I encountered some confusion regarding
cross-partition update.  As we know, cross-partition update works by
first deleting the old tuple from the current partition.  So if we have
BEFORE ROW DELETE triggers that suppress the delete, the update would be
suppressed.  For in-partition update, there is no such problem.  For
instance (based on Alexander's query):

CREATE TABLE t (a int) PARTITION BY RANGE (a);
CREATE TABLE tp1 PARTITION OF t FOR VALUES FROM (0) TO (10);
CREATE TABLE tp2 PARTITION OF t FOR VALUES FROM (10) TO (20);

INSERT INTO t VALUES (0), (5);    -- into tp1
INSERT INTO t VALUES (10), (15);  -- into tp2

CREATE FUNCTION tf() RETURNS TRIGGER LANGUAGE plpgsql AS
  $$ BEGIN RETURN NULL; END; $$;

CREATE TRIGGER tr BEFORE DELETE ON t
  FOR EACH ROW EXECUTE PROCEDURE tf();

-- update suppressed by the BEFORE ROW DELETE trigger
# UPDATE t SET a = 15 WHERE a = 0;
UPDATE 0

-- update performed successfully
# UPDATE t SET a = 5 WHERE a = 0;
UPDATE 1

Does this match the expected behavior?

Thanks
Richard

pgsql-bugs by date:

Previous
From: Edouard Tollet
Date:
Subject: Issue with pg_get_functiondef
Next
From: Daniel Gustafsson
Date:
Subject: Re: BUG #18224: message bug in libpqwalreceiver.c.