Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8e58f80

Browse files
committed
Fix MakeTransitionCaptureState() to return a consistent result
When an UPDATE trigger referencing a new table and a DELETE triggerreferencing an old table are both present, MakeTransitionCaptureState()returns an inconsistent result for UPDATE commands in its set of flagsand tuplestores holding the TransitionCaptureState for transitiontables.As proved by the test added here, this issue causes a crash in v14 andearlier versions (down to 11, actually, older versions do not supporttriggers on partitioned tables) during cross-partition updates on apartitioned table. v15 and newer versions are safe thanks to7103ebb.This commit fixes the function so that it returns a consistent stateby using portions of the changes made in commit7103ebb for v13 andv14. v15 and newer versions are slightly tweaked to match with theolder versions, mainly for consistency across branches.Author: Kyotaro HoriguchiDiscussion:https://postgr.es/m/20250207.150238.968446820828052276.horikyota.ntt@gmail.comBackpatch-through: 13
1 parent80b23bf commit8e58f80

File tree

3 files changed

+115
-16
lines changed

3 files changed

+115
-16
lines changed

‎src/backend/commands/trigger.c

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4511,8 +4511,10 @@ TransitionCaptureState *
45114511
MakeTransitionCaptureState(TriggerDesc*trigdesc,Oidrelid,CmdTypecmdType)
45124512
{
45134513
TransitionCaptureState*state;
4514-
boolneed_old,
4515-
need_new;
4514+
boolneed_old_upd,
4515+
need_new_upd,
4516+
need_old_del,
4517+
need_new_ins;
45164518
AfterTriggersTableData*table;
45174519
MemoryContextoldcxt;
45184520
ResourceOwnersaveResourceOwner;
@@ -4524,23 +4526,25 @@ MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
45244526
switch (cmdType)
45254527
{
45264528
caseCMD_INSERT:
4527-
need_old= false;
4528-
need_new=trigdesc->trig_insert_new_table;
4529+
need_old_upd=need_old_del=need_new_upd= false;
4530+
need_new_ins=trigdesc->trig_insert_new_table;
45294531
break;
45304532
caseCMD_UPDATE:
4531-
need_old=trigdesc->trig_update_old_table;
4532-
need_new=trigdesc->trig_update_new_table;
4533+
need_old_upd=trigdesc->trig_update_old_table;
4534+
need_new_upd=trigdesc->trig_update_new_table;
4535+
need_old_del=need_new_ins= false;
45334536
break;
45344537
caseCMD_DELETE:
4535-
need_old=trigdesc->trig_delete_old_table;
4536-
need_new= false;
4538+
need_old_del=trigdesc->trig_delete_old_table;
4539+
need_old_upd=need_new_upd=need_new_ins= false;
45374540
break;
45384541
default:
45394542
elog(ERROR,"unexpected CmdType: %d", (int)cmdType);
4540-
need_old=need_new= false;/* keep compiler quiet */
4543+
/* keep compiler quiet */
4544+
need_old_upd=need_new_upd=need_old_del=need_new_ins= false;
45414545
break;
45424546
}
4543-
if (!need_old&& !need_new)
4547+
if (!need_old_upd&& !need_new_upd&& !need_new_ins&& !need_old_del)
45444548
returnNULL;
45454549

45464550
/* Check state, like AfterTriggerSaveEvent. */
@@ -4570,20 +4574,20 @@ MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
45704574
saveResourceOwner=CurrentResourceOwner;
45714575
CurrentResourceOwner=CurTransactionResourceOwner;
45724576

4573-
if (need_old&&table->old_tuplestore==NULL)
4577+
if ((need_old_upd||need_old_del)&&table->old_tuplestore==NULL)
45744578
table->old_tuplestore=tuplestore_begin_heap(false, false,work_mem);
4575-
if (need_new&&table->new_tuplestore==NULL)
4579+
if ((need_new_upd||need_new_ins)&&table->new_tuplestore==NULL)
45764580
table->new_tuplestore=tuplestore_begin_heap(false, false,work_mem);
45774581

45784582
CurrentResourceOwner=saveResourceOwner;
45794583
MemoryContextSwitchTo(oldcxt);
45804584

45814585
/* Now build the TransitionCaptureState struct, in caller's context */
45824586
state= (TransitionCaptureState*)palloc0(sizeof(TransitionCaptureState));
4583-
state->tcs_delete_old_table=trigdesc->trig_delete_old_table;
4584-
state->tcs_update_old_table=trigdesc->trig_update_old_table;
4585-
state->tcs_update_new_table=trigdesc->trig_update_new_table;
4586-
state->tcs_insert_new_table=trigdesc->trig_insert_new_table;
4587+
state->tcs_delete_old_table=need_old_del;
4588+
state->tcs_update_old_table=need_old_upd;
4589+
state->tcs_update_new_table=need_new_upd;
4590+
state->tcs_insert_new_table=need_new_ins;
45874591
state->tcs_private=table;
45884592

45894593
returnstate;

‎src/test/regress/expected/triggers.out

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2988,6 +2988,55 @@ drop trigger child_row_trig on child;
29882988
alter table parent attach partition child for values in ('AAA');
29892989
drop table child, parent;
29902990
--
2991+
-- Verify access of transition tables with UPDATE triggers and tuples
2992+
-- moved across partitions.
2993+
--
2994+
create or replace function dump_update_new() returns trigger language plpgsql as
2995+
$$
2996+
begin
2997+
raise notice 'trigger = %, new table = %', TG_NAME,
2998+
(select string_agg(new_table::text, ', ' order by a) from new_table);
2999+
return null;
3000+
end;
3001+
$$;
3002+
create or replace function dump_update_old() returns trigger language plpgsql as
3003+
$$
3004+
begin
3005+
raise notice 'trigger = %, old table = %', TG_NAME,
3006+
(select string_agg(old_table::text, ', ' order by a) from old_table);
3007+
return null;
3008+
end;
3009+
$$;
3010+
create table trans_tab_parent (a text) partition by list (a);
3011+
create table trans_tab_child1 partition of trans_tab_parent for values in ('AAA1', 'AAA2');
3012+
create table trans_tab_child2 partition of trans_tab_parent for values in ('BBB1', 'BBB2');
3013+
create trigger trans_tab_parent_update_trig
3014+
after update on trans_tab_parent referencing old table as old_table
3015+
for each statement execute procedure dump_update_old();
3016+
create trigger trans_tab_parent_insert_trig
3017+
after insert on trans_tab_parent referencing new table as new_table
3018+
for each statement execute procedure dump_insert();
3019+
create trigger trans_tab_parent_delete_trig
3020+
after delete on trans_tab_parent referencing old table as old_table
3021+
for each statement execute procedure dump_delete();
3022+
insert into trans_tab_parent values ('AAA1'), ('BBB1');
3023+
NOTICE: trigger = trans_tab_parent_insert_trig, new table = (AAA1), (BBB1)
3024+
-- should not trigger access to new table when moving across partitions.
3025+
update trans_tab_parent set a = 'BBB2' where a = 'AAA1';
3026+
NOTICE: trigger = trans_tab_parent_update_trig, old table = (AAA1)
3027+
drop trigger trans_tab_parent_update_trig on trans_tab_parent;
3028+
create trigger trans_tab_parent_update_trig
3029+
after update on trans_tab_parent referencing new table as new_table
3030+
for each statement execute procedure dump_update_new();
3031+
-- should not trigger access to old table when moving across partitions.
3032+
update trans_tab_parent set a = 'AAA2' where a = 'BBB1';
3033+
NOTICE: trigger = trans_tab_parent_update_trig, new table = (AAA2)
3034+
delete from trans_tab_parent;
3035+
NOTICE: trigger = trans_tab_parent_delete_trig, old table = (AAA2), (BBB2)
3036+
-- clean up
3037+
drop table trans_tab_parent, trans_tab_child1, trans_tab_child2;
3038+
drop function dump_update_new, dump_update_old;
3039+
--
29913040
-- Verify behavior of statement triggers on (non-partition)
29923041
-- inheritance hierarchy with transition tables; similar to the
29933042
-- partition case, except there is no rerouting on insertion and child

‎src/test/regress/sql/triggers.sql

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,52 @@ alter table parent attach partition child for values in ('AAA');
21152115

21162116
droptable child, parent;
21172117

2118+
--
2119+
-- Verify access of transition tables with UPDATE triggers and tuples
2120+
-- moved across partitions.
2121+
--
2122+
create or replacefunctiondump_update_new() returns trigger language plpgsqlas
2123+
$$
2124+
begin
2125+
raise notice'trigger = %, new table = %', TG_NAME,
2126+
(select string_agg(new_table::text,','order by a)from new_table);
2127+
returnnull;
2128+
end;
2129+
$$;
2130+
create or replacefunctiondump_update_old() returns trigger language plpgsqlas
2131+
$$
2132+
begin
2133+
raise notice'trigger = %, old table = %', TG_NAME,
2134+
(select string_agg(old_table::text,','order by a)from old_table);
2135+
returnnull;
2136+
end;
2137+
$$;
2138+
createtabletrans_tab_parent (atext) partition by list (a);
2139+
createtabletrans_tab_child1 partition of trans_tab_parent forvaluesin ('AAA1','AAA2');
2140+
createtabletrans_tab_child2 partition of trans_tab_parent forvaluesin ('BBB1','BBB2');
2141+
createtriggertrans_tab_parent_update_trig
2142+
afterupdateon trans_tab_parent referencing old tableas old_table
2143+
for each statement execute procedure dump_update_old();
2144+
createtriggertrans_tab_parent_insert_trig
2145+
after inserton trans_tab_parent referencing new tableas new_table
2146+
for each statement execute procedure dump_insert();
2147+
createtriggertrans_tab_parent_delete_trig
2148+
afterdeleteon trans_tab_parent referencing old tableas old_table
2149+
for each statement execute procedure dump_delete();
2150+
insert into trans_tab_parentvalues ('AAA1'), ('BBB1');
2151+
-- should not trigger access to new table when moving across partitions.
2152+
update trans_tab_parentset a='BBB2'where a='AAA1';
2153+
droptrigger trans_tab_parent_update_trigon trans_tab_parent;
2154+
createtriggertrans_tab_parent_update_trig
2155+
afterupdateon trans_tab_parent referencing new tableas new_table
2156+
for each statement execute procedure dump_update_new();
2157+
-- should not trigger access to old table when moving across partitions.
2158+
update trans_tab_parentset a='AAA2'where a='BBB1';
2159+
deletefrom trans_tab_parent;
2160+
-- clean up
2161+
droptable trans_tab_parent, trans_tab_child1, trans_tab_child2;
2162+
dropfunction dump_update_new, dump_update_old;
2163+
21182164
--
21192165
-- Verify behavior of statement triggers on (non-partition)
21202166
-- inheritance hierarchy with transition tables; similar to the

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp