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

Commitadc9cb6

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 parentf565f53 commitadc9cb6

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
@@ -15242,6 +15242,54 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
1524215242
MemoryContextDelete(cxt);
1524315243
}
1524415244

15245+
/*
15246+
* isPartitionTrigger
15247+
*Subroutine for CloneRowTriggersToPartition: determine whether
15248+
*the given trigger has been cloned from another one.
15249+
*
15250+
* We use pg_depend as a proxy for this, since we don't have any direct
15251+
* evidence. This is an ugly hack to cope with a catalog deficiency.
15252+
* Keep away from children. Do not stare with naked eyes. Do not propagate.
15253+
*/
15254+
staticbool
15255+
isPartitionTrigger(Oidtrigger_oid)
15256+
{
15257+
Relationpg_depend;
15258+
ScanKeyDatakey[2];
15259+
SysScanDescscan;
15260+
HeapTupletup;
15261+
boolfound= false;
15262+
15263+
pg_depend=heap_open(DependRelationId,AccessShareLock);
15264+
15265+
ScanKeyInit(&key[0],Anum_pg_depend_classid,
15266+
BTEqualStrategyNumber,
15267+
F_OIDEQ,
15268+
ObjectIdGetDatum(TriggerRelationId));
15269+
ScanKeyInit(&key[1],Anum_pg_depend_objid,
15270+
BTEqualStrategyNumber,
15271+
F_OIDEQ,
15272+
ObjectIdGetDatum(trigger_oid));
15273+
15274+
scan=systable_beginscan(pg_depend,DependDependerIndexId,
15275+
true,NULL,2,key);
15276+
while ((tup=systable_getnext(scan))!=NULL)
15277+
{
15278+
Form_pg_dependdep= (Form_pg_depend)GETSTRUCT(tup);
15279+
15280+
if (dep->refclassid==TriggerRelationId)
15281+
{
15282+
found= true;
15283+
break;
15284+
}
15285+
}
15286+
15287+
systable_endscan(scan);
15288+
heap_close(pg_depend,AccessShareLock);
15289+
15290+
returnfound;
15291+
}
15292+
1524515293
/*
1524615294
* CloneRowTriggersToPartition
1524715295
*subroutine for ATExecAttachPartition/DefineRelation to create row
@@ -15282,8 +15330,21 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
1528215330
if (!TRIGGER_FOR_ROW(trigForm->tgtype))
1528315331
continue;
1528415332

15285-
/* We don't clone internal triggers, either */
15286-
if (trigForm->tgisinternal)
15333+
/*
15334+
* Internal triggers require careful examination. Ideally, we don't
15335+
* clone them.
15336+
*
15337+
* However, if our parent is a partitioned relation, there might be
15338+
* internal triggers that need cloning. In that case, we must
15339+
* skip clone it if the trigger on parent depends on another trigger.
15340+
*
15341+
* Note we dare not verify that the other trigger belongs to an
15342+
* ancestor relation of our parent, because that creates deadlock
15343+
* opportunities.
15344+
*/
15345+
if (trigForm->tgisinternal&&
15346+
(!parent->rd_rel->relispartition||
15347+
!isPartitionTrigger(HeapTupleGetOid(tuple))))
1528715348
continue;
1528815349

1528915350
/*

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

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

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

20112021
drop trigger trg1 on trigpart;-- ok, all gone
20122022
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
@@ -1371,6 +1371,10 @@ create trigger trg1 after insert on trigpart for each row execute procedure trig
13711371
createtabletrigpart2 partition of trigpart forvaluesfrom (1000) to (2000);
13721372
createtabletrigpart3 (like trigpart);
13731373
altertable trigpart attach partition trigpart3 forvaluesfrom (2000) to (3000);
1374+
createtabletrigpart4 partition of trigpart forvaluesfrom (3000) to (4000) partition by range (a);
1375+
createtabletrigpart41 partition of trigpart4 forvaluesfrom (3000) to (3500);
1376+
createtabletrigpart42 (like trigpart);
1377+
altertable trigpart4 attach partition trigpart42 forvaluesfrom (3500) to (4000);
13741378
select tgrelid::regclass, tgname, tgfoid::regprocfrom pg_trigger
13751379
where tgrelid::regclass::textlike'trigpart%'order by tgrelid::regclass::text;
13761380
droptrigger trg1on trigpart1;-- fail

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp