From 8322ba28b46f5d51aee0516ec61f33f2f695f4c2 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Date: Tue, 4 Feb 2025 15:14:27 +0900
Subject: [PATCH 1/2] Add test for a crash bug

---
 src/test/regress/expected/triggers.out | 48 +++++++++++++++++++++++++
 src/test/regress/sql/triggers.sql      | 50 ++++++++++++++++++++++++++
 2 files changed, 98 insertions(+)

diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index d3e02ca63b3..5aed966eac3 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -2957,6 +2957,54 @@ drop trigger child_row_trig on child;
 alter table parent attach partition child for values in ('AAA');
 drop table child, parent;
 --
+-- Verify that UPDATE triggers do not access incorrect transition
+-- tables (which leads to a crash) due to other types of triggers.
+--
+create or replace function dump_update_new() returns trigger language plpgsql as
+$$
+  begin
+    raise notice 'trigger = %, new table = %',
+                 TG_NAME,
+                 (select string_agg(new_table::text, ', ' order by a) from new_table);
+    return null;
+  end;
+$$;
+create or replace function dump_update_old() returns trigger language plpgsql as
+$$
+  begin
+    raise notice 'trigger = %, old table = %',
+                 TG_NAME,
+                 (select string_agg(old_table::text, ', ' order by a) from old_table);
+    return null;
+  end;
+$$;
+create table parent (a text) partition by list (a);
+create table child1 partition of parent for values in ('AAA');
+create table child2 partition of parent for values in ('BBB');
+create trigger parent_update_trig
+  after update on parent referencing old table as old_table
+  for each statement execute procedure dump_update_old();
+create trigger parent_insert_trig
+  after insert on parent referencing new table as new_table
+  for each statement execute procedure dump_insert();
+create trigger parent_delete_trig
+  after delete on parent referencing old table as old_table
+  for each statement execute procedure dump_delete();
+insert into parent values ('AAA');
+NOTICE:  trigger = parent_insert_trig, new table = (AAA)
+update parent set a = 'BBB' where a = 'AAA'; -- should not trigger access to new
+NOTICE:  trigger = parent_update_trig, old table = (AAA)
+drop trigger parent_update_trig on parent;
+create trigger parent_update_trig
+  after update on parent referencing new table as new_table
+  for each statement execute procedure dump_update_new();
+update parent set a = 'AAA' where a = 'BBB'; -- should not trigger access to old
+NOTICE:  trigger = parent_update_trig, new table = (AAA)
+delete from parent;
+NOTICE:  trigger = parent_delete_trig, old table = (AAA)
+drop table parent, child1, child2;
+drop function dump_update_new, dump_update_old;
+--
 -- Verify behavior of statement triggers on (non-partition)
 -- inheritance hierarchy with transition tables; similar to the
 -- partition case, except there is no rerouting on insertion and child
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 4cc096265db..3f3e26ee1ee 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -2118,6 +2118,56 @@ alter table parent attach partition child for values in ('AAA');
 
 drop table child, parent;
 
+--
+-- Verify that UPDATE triggers do not access incorrect transition
+-- tables (which leads to a crash) due to other types of triggers.
+--
+create or replace function dump_update_new() returns trigger language plpgsql as
+$$
+  begin
+    raise notice 'trigger = %, new table = %',
+                 TG_NAME,
+                 (select string_agg(new_table::text, ', ' order by a) from new_table);
+    return null;
+  end;
+$$;
+
+create or replace function dump_update_old() returns trigger language plpgsql as
+$$
+  begin
+    raise notice 'trigger = %, old table = %',
+                 TG_NAME,
+                 (select string_agg(old_table::text, ', ' order by a) from old_table);
+    return null;
+  end;
+$$;
+
+create table parent (a text) partition by list (a);
+create table child1 partition of parent for values in ('AAA');
+create table child2 partition of parent for values in ('BBB');
+create trigger parent_update_trig
+  after update on parent referencing old table as old_table
+  for each statement execute procedure dump_update_old();
+create trigger parent_insert_trig
+  after insert on parent referencing new table as new_table
+  for each statement execute procedure dump_insert();
+create trigger parent_delete_trig
+  after delete on parent referencing old table as old_table
+  for each statement execute procedure dump_delete();
+
+insert into parent values ('AAA');
+update parent set a = 'BBB' where a = 'AAA'; -- should not trigger access to new
+
+drop trigger parent_update_trig on parent;
+create trigger parent_update_trig
+  after update on parent referencing new table as new_table
+  for each statement execute procedure dump_update_new();
+update parent set a = 'AAA' where a = 'BBB'; -- should not trigger access to old
+delete from parent;
+
+drop table parent, child1, child2;
+drop function dump_update_new, dump_update_old;
+
 --
 -- Verify behavior of statement triggers on (non-partition)
 -- inheritance hierarchy with transition tables; similar to the
-- 
2.43.5

