aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/trigger.c15
-rw-r--r--src/test/regress/expected/triggers.out38
-rw-r--r--src/test/regress/sql/triggers.sql45
3 files changed, 82 insertions, 16 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 0ec8d84a1b5..0fcf090f22f 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -4775,11 +4775,13 @@ GetAfterTriggersStoreSlot(AfterTriggersTableData *table,
MemoryContext oldcxt;
/*
- * We only need this slot only until AfterTriggerEndQuery, but making
- * it last till end-of-subxact is good enough. It'll be freed by
- * AfterTriggerFreeQuery().
+ * We need this slot only until AfterTriggerEndQuery, but making it
+ * last till end-of-subxact is good enough. It'll be freed by
+ * AfterTriggerFreeQuery(). However, the passed-in tupdesc might have
+ * a different lifespan, so we'd better make a copy of that.
*/
oldcxt = MemoryContextSwitchTo(CurTransactionContext);
+ tupdesc = CreateTupleDescCopy(tupdesc);
table->storeslot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual);
MemoryContextSwitchTo(oldcxt);
}
@@ -5098,7 +5100,12 @@ AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
if (ts)
tuplestore_end(ts);
if (table->storeslot)
- ExecDropSingleTupleTableSlot(table->storeslot);
+ {
+ TupleTableSlot *slot = table->storeslot;
+
+ table->storeslot = NULL;
+ ExecDropSingleTupleTableSlot(slot);
+ }
}
/*
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index 641f5e67c47..8b8eadd1812 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -3468,7 +3468,7 @@ insert into convslot_test_parent(col1) values ('1');
insert into convslot_test_child(col1) values ('1');
insert into convslot_test_parent(col1) values ('3');
insert into convslot_test_child(col1) values ('3');
-create or replace function trigger_function1()
+create function convslot_trig1()
returns trigger
language plpgsql
AS $$
@@ -3478,7 +3478,7 @@ raise notice 'trigger = %, old_table = %',
(select string_agg(old_table::text, ', ' order by col1) from old_table);
return null;
end; $$;
-create or replace function trigger_function2()
+create function convslot_trig2()
returns trigger
language plpgsql
AS $$
@@ -3490,10 +3490,10 @@ return null;
end; $$;
create trigger but_trigger after update on convslot_test_child
referencing new table as new_table
-for each statement execute function trigger_function2();
+for each statement execute function convslot_trig2();
update convslot_test_parent set col1 = col1 || '1';
NOTICE: trigger = but_trigger, new table = (11,tutu), (31,tutu)
-create or replace function trigger_function3()
+create function convslot_trig3()
returns trigger
language plpgsql
AS $$
@@ -3506,16 +3506,42 @@ return null;
end; $$;
create trigger but_trigger2 after update on convslot_test_child
referencing old table as old_table new table as new_table
-for each statement execute function trigger_function3();
+for each statement execute function convslot_trig3();
update convslot_test_parent set col1 = col1 || '1';
NOTICE: trigger = but_trigger, new table = (111,tutu), (311,tutu)
NOTICE: trigger = but_trigger2, old_table = (11,tutu), (31,tutu), new table = (111,tutu), (311,tutu)
create trigger bdt_trigger after delete on convslot_test_child
referencing old table as old_table
-for each statement execute function trigger_function1();
+for each statement execute function convslot_trig1();
delete from convslot_test_parent;
NOTICE: trigger = bdt_trigger, old_table = (111,tutu), (311,tutu)
drop table convslot_test_child, convslot_test_parent;
+drop function convslot_trig1();
+drop function convslot_trig2();
+drop function convslot_trig3();
+-- Bug #17607: variant of above in which trigger function raises an error;
+-- we don't see any ill effects unless trigger tuple requires mapping
+create table convslot_test_parent (id int primary key, val int)
+partition by range (id);
+create table convslot_test_part (val int, id int not null);
+alter table convslot_test_parent
+ attach partition convslot_test_part for values from (1) to (1000);
+create function convslot_trig4() returns trigger as
+$$begin raise exception 'BOOM!'; end$$ language plpgsql;
+create trigger convslot_test_parent_update
+ after update on convslot_test_parent
+ referencing old table as old_rows new table as new_rows
+ for each statement execute procedure convslot_trig4();
+insert into convslot_test_parent (id, val) values (1, 2);
+begin;
+savepoint svp;
+update convslot_test_parent set val = 3; -- error expected
+ERROR: BOOM!
+CONTEXT: PL/pgSQL function convslot_trig4() line 1 at RAISE
+rollback to savepoint svp;
+rollback;
+drop table convslot_test_parent;
+drop function convslot_trig4();
-- Test trigger renaming on partitioned tables
create table grandparent (id int, primary key (id)) partition by range (id);
create table middle partition of grandparent for values from (1) to (10)
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 9d21bbe2a94..4d8504fb246 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -2615,7 +2615,7 @@ insert into convslot_test_child(col1) values ('1');
insert into convslot_test_parent(col1) values ('3');
insert into convslot_test_child(col1) values ('3');
-create or replace function trigger_function1()
+create function convslot_trig1()
returns trigger
language plpgsql
AS $$
@@ -2626,7 +2626,7 @@ raise notice 'trigger = %, old_table = %',
return null;
end; $$;
-create or replace function trigger_function2()
+create function convslot_trig2()
returns trigger
language plpgsql
AS $$
@@ -2639,11 +2639,11 @@ end; $$;
create trigger but_trigger after update on convslot_test_child
referencing new table as new_table
-for each statement execute function trigger_function2();
+for each statement execute function convslot_trig2();
update convslot_test_parent set col1 = col1 || '1';
-create or replace function trigger_function3()
+create function convslot_trig3()
returns trigger
language plpgsql
AS $$
@@ -2657,15 +2657,48 @@ end; $$;
create trigger but_trigger2 after update on convslot_test_child
referencing old table as old_table new table as new_table
-for each statement execute function trigger_function3();
+for each statement execute function convslot_trig3();
update convslot_test_parent set col1 = col1 || '1';
create trigger bdt_trigger after delete on convslot_test_child
referencing old table as old_table
-for each statement execute function trigger_function1();
+for each statement execute function convslot_trig1();
delete from convslot_test_parent;
drop table convslot_test_child, convslot_test_parent;
+drop function convslot_trig1();
+drop function convslot_trig2();
+drop function convslot_trig3();
+
+-- Bug #17607: variant of above in which trigger function raises an error;
+-- we don't see any ill effects unless trigger tuple requires mapping
+
+create table convslot_test_parent (id int primary key, val int)
+partition by range (id);
+
+create table convslot_test_part (val int, id int not null);
+
+alter table convslot_test_parent
+ attach partition convslot_test_part for values from (1) to (1000);
+
+create function convslot_trig4() returns trigger as
+$$begin raise exception 'BOOM!'; end$$ language plpgsql;
+
+create trigger convslot_test_parent_update
+ after update on convslot_test_parent
+ referencing old table as old_rows new table as new_rows
+ for each statement execute procedure convslot_trig4();
+
+insert into convslot_test_parent (id, val) values (1, 2);
+
+begin;
+savepoint svp;
+update convslot_test_parent set val = 3; -- error expected
+rollback to savepoint svp;
+rollback;
+
+drop table convslot_test_parent;
+drop function convslot_trig4();
-- Test trigger renaming on partitioned tables
create table grandparent (id int, primary key (id)) partition by range (id);