Skip to content

Commit 6cbe84c

Browse files
committed
Check for pending trigger events on far end when dropping an FK constraint.
When dropping a foreign key constraint with ALTER TABLE DROP CONSTRAINT, we refuse the drop if there are any pending trigger events on the named table; this ensures that we won't remove the pg_trigger row that will be consulted by those events. But we should make the same check for the referenced relation, else we might remove a due-to-be-referenced pg_trigger row for that relation too, resulting in "could not find trigger NNN" or "relation NNN has no triggers" errors at commit. Per bug #14431 from Benjie Gillam. Back-patch to all supported branches. Report: <20161124114911.6530.31200@wrigleys.postgresql.org>
1 parent 7816d13 commit 6cbe84c

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

src/backend/commands/tablecmds.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7688,6 +7688,24 @@ ATExecDropConstraint(Relation rel, const char *constrName,
76887688

76897689
is_no_inherit_constraint = con->connoinherit;
76907690

7691+
/*
7692+
* If it's a foreign-key constraint, we'd better lock the referenced
7693+
* table and check that that's not in use, just as we've already done
7694+
* for the constrained table (else we might, eg, be dropping a trigger
7695+
* that has unfired events). But we can/must skip that in the
7696+
* self-referential case.
7697+
*/
7698+
if (con->contype == CONSTRAINT_FOREIGN &&
7699+
con->confrelid != RelationGetRelid(rel))
7700+
{
7701+
Relation frel;
7702+
7703+
/* Must match lock taken by RemoveTriggerById: */
7704+
frel = heap_open(con->confrelid, AccessExclusiveLock);
7705+
CheckTableNotInUse(frel, "ALTER TABLE");
7706+
heap_close(frel, NoLock);
7707+
}
7708+
76917709
/*
76927710
* Perform the actual constraint deletion
76937711
*/

src/test/regress/expected/foreign_key.out

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,4 +1379,17 @@ rollback to x;
13791379
commit; -- fail
13801380
ERROR: insert or update on table "fktable2" violates foreign key constraint "fktable2_f1_fkey"
13811381
DETAIL: Key (f1)=(2) is not present in table "pktable2".
1382+
--
1383+
-- Test that we prevent dropping FK constraint with pending trigger events
1384+
--
1385+
begin;
1386+
insert into fktable2 values(2);
1387+
alter table fktable2 drop constraint fktable2_f1_fkey;
1388+
ERROR: cannot ALTER TABLE "fktable2" because it has pending trigger events
1389+
commit;
1390+
begin;
1391+
delete from pktable2 where f1 = 1;
1392+
alter table fktable2 drop constraint fktable2_f1_fkey;
1393+
ERROR: cannot ALTER TABLE "pktable2" because it has pending trigger events
1394+
commit;
13821395
drop table pktable2, fktable2;

src/test/regress/sql/foreign_key.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,4 +1031,17 @@ delete from fktable2;
10311031
rollback to x;
10321032
commit; -- fail
10331033

1034+
--
1035+
-- Test that we prevent dropping FK constraint with pending trigger events
1036+
--
1037+
begin;
1038+
insert into fktable2 values(2);
1039+
alter table fktable2 drop constraint fktable2_f1_fkey;
1040+
commit;
1041+
1042+
begin;
1043+
delete from pktable2 where f1 = 1;
1044+
alter table fktable2 drop constraint fktable2_f1_fkey;
1045+
commit;
1046+
10341047
drop table pktable2, fktable2;

0 commit comments

Comments
 (0)