summaryrefslogtreecommitdiff
path: root/src/backend/commands/trigger.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-05-27 21:13:25 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-05-27 21:13:25 +0000
commit35b6007efee916e5b4dfbd4e98fcbef9b8259355 (patch)
tree05247dca739821d8564eb064a10228e792be0cd7 /src/backend/commands/trigger.c
parent8eecf95d415b8b73ae05e7221c00388d1abe2d27 (diff)
Back-patch the 8.3 fix that prohibits TRUNCATE, CLUSTER, and REINDEX when the
current transaction has any open references to the target relation or index (implying it has an active query using the relation). Also back-patch the 8.2 fix that prohibits TRUNCATE and CLUSTER when there are pending AFTER-trigger events. Per suggestion from Heikki.
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r--src/backend/commands/trigger.c43
1 files changed, 20 insertions, 23 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 47de3ca6fc2..75e0cf150d8 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.210.2.4 2007/08/15 19:15:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.210.2.5 2008/05/27 21:13:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3190,28 +3190,29 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
}
/* ----------
- * AfterTriggerCheckTruncate()
- * Test deferred-trigger status to see if a TRUNCATE is OK.
+ * AfterTriggerPendingOnRel()
+ * Test to see if there are any pending after-trigger events for rel.
*
- * The argument is a list of OIDs of relations due to be truncated.
- * We raise error if there are any pending after-trigger events for them.
+ * This is used by TRUNCATE, CLUSTER, ALTER TABLE, etc to detect whether
+ * it is unsafe to perform major surgery on a relation. Note that only
+ * local pending events are examined. We assume that having exclusive lock
+ * on a rel guarantees there are no unserviced events in other backends ---
+ * but having a lock does not prevent there being such events in our own.
*
* In some scenarios it'd be reasonable to remove pending events (more
* specifically, mark them DONE by the current subxact) but without a lot
* of knowledge of the trigger semantics we can't do this in general.
* ----------
*/
-void
-AfterTriggerCheckTruncate(List *relids)
+bool
+AfterTriggerPendingOnRel(Oid relid)
{
AfterTriggerEvent event;
int depth;
- /*
- * Ignore call if we aren't in a transaction. (Shouldn't happen?)
- */
+ /* No-op if we aren't in a transaction. (Shouldn't happen?) */
if (afterTriggers == NULL)
- return;
+ return false;
/* Scan queued events */
for (event = afterTriggers->events.head;
@@ -3221,21 +3222,18 @@ AfterTriggerCheckTruncate(List *relids)
/*
* We can ignore completed events. (Even if a DONE flag is rolled
* back by subxact abort, it's OK because the effects of the TRUNCATE
- * must get rolled back too.)
+ * or whatever must get rolled back too.)
*/
if (event->ate_event & AFTER_TRIGGER_DONE)
continue;
- if (list_member_oid(relids, event->ate_relid))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot truncate table \"%s\" because it has pending trigger events",
- get_rel_name(event->ate_relid))));
+ if (event->ate_relid == relid)
+ return true;
}
/*
* Also scan events queued by incomplete queries. This could only matter
- * if a TRUNCATE is executed by a function or trigger within an updating
+ * if TRUNCATE/etc is executed by a function or trigger within an updating
* query on the same relation, which is pretty perverse, but let's check.
*/
for (depth = 0; depth <= afterTriggers->query_depth; depth++)
@@ -3247,13 +3245,12 @@ AfterTriggerCheckTruncate(List *relids)
if (event->ate_event & AFTER_TRIGGER_DONE)
continue;
- if (list_member_oid(relids, event->ate_relid))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot truncate table \"%s\" because it has pending trigger events",
- get_rel_name(event->ate_relid))));
+ if (event->ate_relid == relid)
+ return true;
}
}
+
+ return false;
}