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

From: Richard Guo <guofenglinux(at)gmail(dot)com>
To: Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com>
Cc: jian he <jian(dot)universality(at)gmail(dot)com>, exclusion(at)gmail(dot)com, pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: BUG #18238: Cross-partitition MERGE/UPDATE with delete-preventing trigger leads to incorrect memory access
Date: 2023-12-12 09:50:27
Message-ID: CAMbWs48TaqQ-moMVu2tEbCB7qH5r-CMzd4LLFGov1LF-406FfQ@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

On Mon, Dec 11, 2023 at 8:53 PM Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)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

In response to

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Daniel Gustafsson 2023-12-12 10:20:31 Re: BUG #18224: message bug in libpqwalreceiver.c.
Previous Message Edouard Tollet 2023-12-12 09:33:27 Issue with pg_get_functiondef