diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 49048c7e7df..72dce883524 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -3900,8 +3900,12 @@ AfterTriggerExecute(EState *estate, bool should_free_new = false; /* - * Locate trigger in trigdesc. + * Locate trigger in trigdesc. It might not be present, and in fact the + * trigdesc could be NULL, if the trigger was dropped since the event was + * queued. In that case, silently do nothing. */ + if (trigdesc == NULL) + return; for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++) { if (trigdesc->triggers[tgindx].tgoid == tgoid) @@ -3911,7 +3915,7 @@ AfterTriggerExecute(EState *estate, } } if (LocTriggerData.tg_trigger == NULL) - elog(ERROR, "could not find trigger %u", tgoid); + return; /* * If doing EXPLAIN ANALYZE, start charging time to this trigger. We want @@ -4235,6 +4239,7 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events, /* Catch calls with insufficient relcache refcounting */ Assert(!RelationHasReferenceCountZero(rel)); trigdesc = rInfo->ri_TrigDesc; + /* caution: trigdesc could be NULL here */ finfo = rInfo->ri_TrigFunctions; instr = rInfo->ri_TrigInstrument; if (slot1 != NULL) @@ -4250,9 +4255,6 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events, slot2 = MakeSingleTupleTableSlot(rel->rd_att, &TTSOpsMinimalTuple); } - if (trigdesc == NULL) /* should not happen */ - elog(ERROR, "relation %u has no triggers", - evtshared->ats_relid); } /* diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out index b559479f470..0e027decbb4 100644 --- a/src/test/regress/expected/triggers.out +++ b/src/test/regress/expected/triggers.out @@ -3286,6 +3286,17 @@ select * from trig_table; drop table refd_table, trig_table; -- +-- Test that we can drop a not-yet-fired deferred trigger +-- +create table refd_table (id int primary key); +create table trig_table (fk int references refd_table initially deferred); +begin; +insert into trig_table values (1); +drop table refd_table cascade; +NOTICE: drop cascades to constraint trig_table_fk_fkey on table trig_table +commit; +drop table trig_table; +-- -- self-referential FKs are even more fun -- create table self_ref (a int primary key, diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql index b18faf0d5a2..605d5cf05ee 100644 --- a/src/test/regress/sql/triggers.sql +++ b/src/test/regress/sql/triggers.sql @@ -2406,6 +2406,20 @@ select * from trig_table; drop table refd_table, trig_table; +-- +-- Test that we can drop a not-yet-fired deferred trigger +-- + +create table refd_table (id int primary key); +create table trig_table (fk int references refd_table initially deferred); + +begin; +insert into trig_table values (1); +drop table refd_table cascade; +commit; + +drop table trig_table; + -- -- self-referential FKs are even more fun --