Skip to content

Commit 5f6463a

Browse files
committed
Fix ALTER TABLE .. ENABLE/DISABLE TRIGGER recursion
More precisely, correctly handle the ONLY flag indicating not to recurse. This was implemented in 86f5759 by recursing in trigger.c, but that's the wrong place; use ATSimpleRecursion instead, which behaves properly. However, because legacy inheritance has never recursed in that situation, make sure to do that only for new-style partitioning. I noticed this problem while testing a fix for another bug in the vicinity. This has been wrong all along, so backpatch to 11. Discussion: https://postgr.es/m/20201016235925.GA29829@alvherre.pgsql
1 parent 1f53d0b commit 5f6463a

File tree

4 files changed

+93
-21
lines changed

4 files changed

+93
-21
lines changed

src/backend/commands/tablecmds.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4317,6 +4317,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
43174317
case AT_DisableTrigAll:
43184318
case AT_DisableTrigUser:
43194319
ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4320+
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
4321+
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
43204322
pass = AT_PASS_MISC;
43214323
break;
43224324
case AT_EnableRule: /* ENABLE/DISABLE RULE variants */

src/backend/commands/trigger.c

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,27 +1530,6 @@ EnableDisableTrigger(Relation rel, const char *tgname,
15301530

15311531
heap_freetuple(newtup);
15321532

1533-
/*
1534-
* When altering FOR EACH ROW triggers on a partitioned table, do
1535-
* the same on the partitions as well.
1536-
*/
1537-
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
1538-
(TRIGGER_FOR_ROW(oldtrig->tgtype)))
1539-
{
1540-
PartitionDesc partdesc = RelationGetPartitionDesc(rel);
1541-
int i;
1542-
1543-
for (i = 0; i < partdesc->nparts; i++)
1544-
{
1545-
Relation part;
1546-
1547-
part = relation_open(partdesc->oids[i], lockmode);
1548-
EnableDisableTrigger(part, NameStr(oldtrig->tgname),
1549-
fires_when, skip_system, lockmode);
1550-
table_close(part, NoLock); /* keep lock till commit */
1551-
}
1552-
}
1553-
15541533
changed = true;
15551534
}
15561535

src/test/regress/expected/triggers.out

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2512,6 +2512,62 @@ select tgrelid::regclass, count(*) from pg_trigger
25122512
(5 rows)
25132513

25142514
drop table trg_clone;
2515+
-- Test the interaction between ALTER TABLE .. DISABLE TRIGGER and
2516+
-- both kinds of inheritance. Historically, legacy inheritance has
2517+
-- not recursed to children, so that behavior is preserved.
2518+
create table parent (a int);
2519+
create table child1 () inherits (parent);
2520+
create function trig_nothing() returns trigger language plpgsql
2521+
as $$ begin return null; end $$;
2522+
create trigger tg after insert on parent
2523+
for each row execute function trig_nothing();
2524+
create trigger tg after insert on child1
2525+
for each row execute function trig_nothing();
2526+
alter table parent disable trigger tg;
2527+
select tgrelid::regclass, tgname, tgenabled from pg_trigger
2528+
where tgrelid in ('parent'::regclass, 'child1'::regclass)
2529+
order by tgrelid::regclass::text;
2530+
tgrelid | tgname | tgenabled
2531+
---------+--------+-----------
2532+
child1 | tg | O
2533+
parent | tg | D
2534+
(2 rows)
2535+
2536+
alter table only parent enable always trigger tg;
2537+
select tgrelid::regclass, tgname, tgenabled from pg_trigger
2538+
where tgrelid in ('parent'::regclass, 'child1'::regclass)
2539+
order by tgrelid::regclass::text;
2540+
tgrelid | tgname | tgenabled
2541+
---------+--------+-----------
2542+
child1 | tg | O
2543+
parent | tg | A
2544+
(2 rows)
2545+
2546+
drop table parent, child1;
2547+
create table parent (a int) partition by list (a);
2548+
create table child1 partition of parent for values in (1);
2549+
create trigger tg after insert on parent
2550+
for each row execute procedure trig_nothing();
2551+
select tgrelid::regclass, tgname, tgenabled from pg_trigger
2552+
where tgrelid in ('parent'::regclass, 'child1'::regclass)
2553+
order by tgrelid::regclass::text;
2554+
tgrelid | tgname | tgenabled
2555+
---------+--------+-----------
2556+
child1 | tg | O
2557+
parent | tg | O
2558+
(2 rows)
2559+
2560+
alter table only parent enable always trigger tg;
2561+
select tgrelid::regclass, tgname, tgenabled from pg_trigger
2562+
where tgrelid in ('parent'::regclass, 'child1'::regclass)
2563+
order by tgrelid::regclass::text;
2564+
tgrelid | tgname | tgenabled
2565+
---------+--------+-----------
2566+
child1 | tg | O
2567+
parent | tg | A
2568+
(2 rows)
2569+
2570+
drop table parent, child1;
25152571
--
25162572
-- Test the interaction between transition tables and both kinds of
25172573
-- inheritance. We'll dump the contents of the transition tables in a

src/test/regress/sql/triggers.sql

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1749,6 +1749,41 @@ select tgrelid::regclass, count(*) from pg_trigger
17491749
group by tgrelid::regclass order by tgrelid::regclass;
17501750
drop table trg_clone;
17511751

1752+
-- Test the interaction between ALTER TABLE .. DISABLE TRIGGER and
1753+
-- both kinds of inheritance. Historically, legacy inheritance has
1754+
-- not recursed to children, so that behavior is preserved.
1755+
create table parent (a int);
1756+
create table child1 () inherits (parent);
1757+
create function trig_nothing() returns trigger language plpgsql
1758+
as $$ begin return null; end $$;
1759+
create trigger tg after insert on parent
1760+
for each row execute function trig_nothing();
1761+
create trigger tg after insert on child1
1762+
for each row execute function trig_nothing();
1763+
alter table parent disable trigger tg;
1764+
select tgrelid::regclass, tgname, tgenabled from pg_trigger
1765+
where tgrelid in ('parent'::regclass, 'child1'::regclass)
1766+
order by tgrelid::regclass::text;
1767+
alter table only parent enable always trigger tg;
1768+
select tgrelid::regclass, tgname, tgenabled from pg_trigger
1769+
where tgrelid in ('parent'::regclass, 'child1'::regclass)
1770+
order by tgrelid::regclass::text;
1771+
drop table parent, child1;
1772+
1773+
create table parent (a int) partition by list (a);
1774+
create table child1 partition of parent for values in (1);
1775+
create trigger tg after insert on parent
1776+
for each row execute procedure trig_nothing();
1777+
select tgrelid::regclass, tgname, tgenabled from pg_trigger
1778+
where tgrelid in ('parent'::regclass, 'child1'::regclass)
1779+
order by tgrelid::regclass::text;
1780+
alter table only parent enable always trigger tg;
1781+
select tgrelid::regclass, tgname, tgenabled from pg_trigger
1782+
where tgrelid in ('parent'::regclass, 'child1'::regclass)
1783+
order by tgrelid::regclass::text;
1784+
drop table parent, child1;
1785+
1786+
17521787
--
17531788
-- Test the interaction between transition tables and both kinds of
17541789
-- inheritance. We'll dump the contents of the transition tables in a

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy