Thanks to visit codestin.com
Credit goes to github.com

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: <[email protected]>
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)