Fix for a crash caused by triggers in cross-partition updates

From: Kyotaro Horiguchi <horikyota(dot)ntt(at)gmail(dot)com>
To: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Fix for a crash caused by triggers in cross-partition updates
Date: 2025-02-07 06:02:38
Message-ID: 20250207.150238.968446820828052276.horikyota.ntt@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello.

We received a crash report related to cross-partition updates
involving multiple triggers.

After investigating the situation, we found that the crash occurs by
the following steps in PostgreSQL versions 11 through 14 (We have not
checked versions 10 and earlier.):

create table tp(a int) partition by range (a);
create table tc1 partition of tp for values from (0) to (10);
create table tc2 partition of tp for values from (10) to (20);
insert into tp values (1);
create or replace function trg() returns trigger as $$BEGIN RETURN NULL; END; $$ language plpgsql;
create trigger td after delete on tp referencing old table old for each statement execute function trg();
create trigger tu after update on tp referencing new table new for each statement execute function trg();

update tp set a = 11 where a = 1;
<crash>

In this scenario, AfterTriggerSaveEvent is passed an inconsistent
TransitionCaptureState. Specifically, it indicates that
delete_old_table is required, but the corresponding tuplestore
(old_tuplestore) is not actually provided, leading to a crash. This
issue occurs because the function indiscriminately sets the
.tcs_*_old/new_table flags regardless of cmdType. The inconsistency
results in a crash during ExecCrossPartitionUpdate, where ExecDelete
is invoked as part of an UPDATE command.

The crash appears to have been accidentally fixed in commit
3a46a45f6f0 by simply skipping tuple storage when a tuplestore is not
available (in TransitionTableAddTuple). However, I believe that
MakeTransitionCaptureState returning an inconsistent
TransitionCaptureState is fundamentally problematic.

The attached first patch adds a test case that causes the crash in
versions 11 through 14 but executes successfully in version 15 and
later.

The second patch provides a fix for versions 11 to 14, and the third
patch applies the same fix to version 15 and later, purely for
consistency with the first patch. These two patches are designed so
that the differences between the code after applying each of them
remain small.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

Attachment Content-Type Size
0001-Add-test-for-a-crash-bug.patch text/x-patch 5.3 KB
0002-Fix-MakeTransitionCaptureState-to-return-a-consisten_11-14.patch text/x-patch 4.0 KB
0002-Fix-MakeTransitionCaptureState-to-return-a-consisten_15-master.patch text/x-patch 1.8 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Michael Paquier 2025-02-07 06:07:18 Re: Statistics Import and Export
Previous Message Daniil Davydov 2025-02-07 05:54:00 Re: SLRU_PAGES_PER_SEGMENT as configure parameter