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

Commitd732148

Browse files
committed
Fix cloning of row triggers to sub-partitions
When row triggers exist in partitioned partitions that are not eitherpart of FKs or deferred unique constraints, they are not correctlycloned to their partitions. That's because they are marked "internal",and those are purposefully skipped when doing the clone triggers dance.Fix by relaxing the condition on which internal triggers are skipped.Amit Langote initially diagnosed the problem and proposed a fix, but Iused a different approach.Reported-by: Petr FedorovDiscussion:https://postgr.es/m/6b3f0646-ba8c-b3a9-c62d-1c6651a1920f@phystech.edu
1 parent98b75c3 commitd732148

File tree

3 files changed

+90
-15
lines changed

3 files changed

+90
-15
lines changed

‎src/backend/commands/tablecmds.c

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15988,6 +15988,54 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
1598815988
MemoryContextDelete(cxt);
1598915989
}
1599015990

15991+
/*
15992+
* isPartitionTrigger
15993+
*Subroutine for CloneRowTriggersToPartition: determine whether
15994+
*the given trigger has been cloned from another one.
15995+
*
15996+
* We use pg_depend as a proxy for this, since we don't have any direct
15997+
* evidence. This is an ugly hack to cope with a catalog deficiency.
15998+
* Keep away from children. Do not stare with naked eyes. Do not propagate.
15999+
*/
16000+
static bool
16001+
isPartitionTrigger(Oid trigger_oid)
16002+
{
16003+
Relationpg_depend;
16004+
ScanKeyData key[2];
16005+
SysScanDescscan;
16006+
HeapTupletup;
16007+
boolfound = false;
16008+
16009+
pg_depend = table_open(DependRelationId, AccessShareLock);
16010+
16011+
ScanKeyInit(&key[0], Anum_pg_depend_classid,
16012+
BTEqualStrategyNumber,
16013+
F_OIDEQ,
16014+
ObjectIdGetDatum(TriggerRelationId));
16015+
ScanKeyInit(&key[1], Anum_pg_depend_objid,
16016+
BTEqualStrategyNumber,
16017+
F_OIDEQ,
16018+
ObjectIdGetDatum(trigger_oid));
16019+
16020+
scan = systable_beginscan(pg_depend, DependDependerIndexId,
16021+
true, NULL, 2, key);
16022+
while ((tup = systable_getnext(scan)) != NULL)
16023+
{
16024+
Form_pg_dependdep = (Form_pg_depend) GETSTRUCT(tup);
16025+
16026+
if (dep->refclassid == TriggerRelationId)
16027+
{
16028+
found = true;
16029+
break;
16030+
}
16031+
}
16032+
16033+
systable_endscan(scan);
16034+
table_close(pg_depend, AccessShareLock);
16035+
16036+
return found;
16037+
}
16038+
1599116039
/*
1599216040
* CloneRowTriggersToPartition
1599316041
*subroutine for ATExecAttachPartition/DefineRelation to create row
@@ -16028,8 +16076,21 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
1602816076
if (!TRIGGER_FOR_ROW(trigForm->tgtype))
1602916077
continue;
1603016078

16031-
/* We don't clone internal triggers, either */
16032-
if (trigForm->tgisinternal)
16079+
/*
16080+
* Internal triggers require careful examination. Ideally, we don't
16081+
* clone them.
16082+
*
16083+
* However, if our parent is a partitioned relation, there might be
16084+
* internal triggers that need cloning. In that case, we must
16085+
* skip clone it if the trigger on parent depends on another trigger.
16086+
*
16087+
* Note we dare not verify that the other trigger belongs to an
16088+
* ancestor relation of our parent, because that creates deadlock
16089+
* opportunities.
16090+
*/
16091+
if (trigForm->tgisinternal &&
16092+
(!parent->rd_rel->relispartition ||
16093+
!isPartitionTrigger(trigForm->oid)))
1603316094
continue;
1603416095

1603516096
/*

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

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1981,15 +1981,22 @@ create trigger trg1 after insert on trigpart for each row execute procedure trig
19811981
create table trigpart2 partition of trigpart for values from (1000) to (2000);
19821982
create table trigpart3 (like trigpart);
19831983
alter table trigpart attach partition trigpart3 for values from (2000) to (3000);
1984+
create table trigpart4 partition of trigpart for values from (3000) to (4000) partition by range (a);
1985+
create table trigpart41 partition of trigpart4 for values from (3000) to (3500);
1986+
create table trigpart42 (like trigpart);
1987+
alter table trigpart4 attach partition trigpart42 for values from (3500) to (4000);
19841988
select tgrelid::regclass, tgname, tgfoid::regproc from pg_trigger
19851989
where tgrelid::regclass::text like 'trigpart%' order by tgrelid::regclass::text;
1986-
tgrelid | tgname | tgfoid
1987-
-----------+--------+-----------------
1988-
trigpart | trg1 | trigger_nothing
1989-
trigpart1 | trg1 | trigger_nothing
1990-
trigpart2 | trg1 | trigger_nothing
1991-
trigpart3 | trg1 | trigger_nothing
1992-
(4 rows)
1990+
tgrelid | tgname | tgfoid
1991+
------------+--------+-----------------
1992+
trigpart | trg1 | trigger_nothing
1993+
trigpart1 | trg1 | trigger_nothing
1994+
trigpart2 | trg1 | trigger_nothing
1995+
trigpart3 | trg1 | trigger_nothing
1996+
trigpart4 | trg1 | trigger_nothing
1997+
trigpart41 | trg1 | trigger_nothing
1998+
trigpart42 | trg1 | trigger_nothing
1999+
(7 rows)
19932000

19942001
drop trigger trg1 on trigpart1;-- fail
19952002
ERROR: cannot drop trigger trg1 on table trigpart1 because trigger trg1 on table trigpart requires it
@@ -2003,12 +2010,15 @@ HINT: You can drop trigger trg1 on table trigpart instead.
20032010
drop table trigpart2;-- ok, trigger should be gone in that partition
20042011
select tgrelid::regclass, tgname, tgfoid::regproc from pg_trigger
20052012
where tgrelid::regclass::text like 'trigpart%' order by tgrelid::regclass::text;
2006-
tgrelid | tgname | tgfoid
2007-
-----------+--------+-----------------
2008-
trigpart | trg1 | trigger_nothing
2009-
trigpart1 | trg1 | trigger_nothing
2010-
trigpart3 | trg1 | trigger_nothing
2011-
(3 rows)
2013+
tgrelid | tgname | tgfoid
2014+
------------+--------+-----------------
2015+
trigpart | trg1 | trigger_nothing
2016+
trigpart1 | trg1 | trigger_nothing
2017+
trigpart3 | trg1 | trigger_nothing
2018+
trigpart4 | trg1 | trigger_nothing
2019+
trigpart41 | trg1 | trigger_nothing
2020+
trigpart42 | trg1 | trigger_nothing
2021+
(6 rows)
20122022

20132023
drop trigger trg1 on trigpart;-- ok, all gone
20142024
select tgrelid::regclass, tgname, tgfoid::regproc from pg_trigger

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,10 @@ create trigger trg1 after insert on trigpart for each row execute procedure trig
13661366
createtabletrigpart2 partition of trigpart forvaluesfrom (1000) to (2000);
13671367
createtabletrigpart3 (like trigpart);
13681368
altertable trigpart attach partition trigpart3 forvaluesfrom (2000) to (3000);
1369+
createtabletrigpart4 partition of trigpart forvaluesfrom (3000) to (4000) partition by range (a);
1370+
createtabletrigpart41 partition of trigpart4 forvaluesfrom (3000) to (3500);
1371+
createtabletrigpart42 (like trigpart);
1372+
altertable trigpart4 attach partition trigpart42 forvaluesfrom (3500) to (4000);
13691373
select tgrelid::regclass, tgname, tgfoid::regprocfrom pg_trigger
13701374
where tgrelid::regclass::textlike'trigpart%'order by tgrelid::regclass::text;
13711375
droptrigger trg1on trigpart1;-- fail

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp