aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2016-11-25 13:44:47 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2016-11-25 13:44:47 -0500
commit4e026b32d4024b03856b4981b26c747b7fef7afb (patch)
treee470014e587e1504e8be56f306aa7454ae3ddf47 /src
parent8afb811088c2a8bfa2b68bd24c05471b8ea4a8ce (diff)
downloadpostgresql-4e026b32d4024b03856b4981b26c747b7fef7afb.tar.gz
postgresql-4e026b32d4024b03856b4981b26c747b7fef7afb.zip
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>
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/tablecmds.c18
-rw-r--r--src/test/regress/expected/foreign_key.out13
-rw-r--r--src/test/regress/sql/foreign_key.sql13
3 files changed, 44 insertions, 0 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f97bee5b0e4..6322fa75a76 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7723,6 +7723,24 @@ ATExecDropConstraint(Relation rel, const char *constrName,
is_no_inherit_constraint = con->connoinherit;
/*
+ * If it's a foreign-key constraint, we'd better lock the referenced
+ * table and check that that's not in use, just as we've already done
+ * for the constrained table (else we might, eg, be dropping a trigger
+ * that has unfired events). But we can/must skip that in the
+ * self-referential case.
+ */
+ if (con->contype == CONSTRAINT_FOREIGN &&
+ con->confrelid != RelationGetRelid(rel))
+ {
+ Relation frel;
+
+ /* Must match lock taken by RemoveTriggerById: */
+ frel = heap_open(con->confrelid, AccessExclusiveLock);
+ CheckTableNotInUse(frel, "ALTER TABLE");
+ heap_close(frel, NoLock);
+ }
+
+ /*
* Perform the actual constraint deletion
*/
conobj.classId = ConstraintRelationId;
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index 46a30b44289..fef072eddfa 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -1401,4 +1401,17 @@ rollback to x;
commit; -- fail
ERROR: insert or update on table "fktable2" violates foreign key constraint "fktable2_f1_fkey"
DETAIL: Key (f1)=(2) is not present in table "pktable2".
+--
+-- Test that we prevent dropping FK constraint with pending trigger events
+--
+begin;
+insert into fktable2 values(2);
+alter table fktable2 drop constraint fktable2_f1_fkey;
+ERROR: cannot ALTER TABLE "fktable2" because it has pending trigger events
+commit;
+begin;
+delete from pktable2 where f1 = 1;
+alter table fktable2 drop constraint fktable2_f1_fkey;
+ERROR: cannot ALTER TABLE "pktable2" because it has pending trigger events
+commit;
drop table pktable2, fktable2;
diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql
index cc36ab5bafc..5f19dad03cd 100644
--- a/src/test/regress/sql/foreign_key.sql
+++ b/src/test/regress/sql/foreign_key.sql
@@ -1041,4 +1041,17 @@ delete from fktable2;
rollback to x;
commit; -- fail
+--
+-- Test that we prevent dropping FK constraint with pending trigger events
+--
+begin;
+insert into fktable2 values(2);
+alter table fktable2 drop constraint fktable2_f1_fkey;
+commit;
+
+begin;
+delete from pktable2 where f1 = 1;
+alter table fktable2 drop constraint fktable2_f1_fkey;
+commit;
+
drop table pktable2, fktable2;