Fix for a crash caused by triggers in cross-partition updates
Kyotaro Horiguchi <horikyota.ntt@gmail.com>
From: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
To: pgsql-hackers@lists.postgresql.org
Date: 2025-02-07T06:02:38Z
Lists: pgsql-hackers
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Fix MakeTransitionCaptureState() to return a consistent result
- 5209058240f3 13.20 landed
- 8e58f8024d0a 14.17 landed
- a37c83d1e465 15.12 landed
- 139beb0355c2 16.8 landed
- 6342d49d89b9 17.4 landed
- 773c51dd39ad 18.0 landed
-
Add API of sorts for transition table handling in trigger.c
- 3a46a45f6f00 15.0 cited
Attachments
- 0001-Add-test-for-a-crash-bug.patch (text/x-patch)
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