diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-05-27 21:14:00 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-05-27 21:14:00 +0000 |
commit | c59eef17c96d98833c98341491ff9ca2da5a06b8 (patch) | |
tree | 63aee284cfd6898264418adbd9714c01a12641cc /src/backend/commands/tablecmds.c | |
parent | ea2827116540c5d8db51da030a4c4c9d4e4ab130 (diff) | |
download | postgresql-c59eef17c96d98833c98341491ff9ca2da5a06b8.tar.gz postgresql-c59eef17c96d98833c98341491ff9ca2da5a06b8.zip |
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/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 97caafbb8e1..ccc25c88f4a 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.91.2.3 2008/05/09 22:38:05 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.91.2.4 2008/05/27 21:14:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -398,6 +398,12 @@ TruncateRelation(const RangeVar *relation) errmsg("cannot truncate temporary tables of other sessions"))); /* + * Also check for active uses of the relation in the current + * transaction, including open scans and pending AFTER trigger events. + */ + CheckTableNotInUse(rel, "TRUNCATE"); + + /* * Don't allow truncate on tables which are referenced by foreign keys */ heap_truncate_check_FKs(rel); @@ -1592,6 +1598,48 @@ update_ri_trigger_args(Oid relid, CommandCounterIncrement(); } +/* + * Disallow TRUNCATE (and similar commands) when the current backend has + * any open reference to the target table besides the one just acquired by + * the calling command; this implies there's an open cursor or active plan. + * We need this check because our AccessExclusiveLock doesn't protect us + * against stomping on our own foot, only other people's feet! + * + * We also reject these commands if there are any pending AFTER trigger events + * for the rel. This is certainly necessary for CLUSTER, because it does not + * preserve tuple TIDs and so the pending events would try to fetch the wrong + * tuples. It might be overly cautious in other cases, but again it seems + * better to err on the side of paranoia. + * + * REINDEX calls this with "rel" referencing the index to be rebuilt; here + * we are worried about active indexscans on the index. The trigger-event + * check can be skipped, since we are doing no damage to the parent table. + * + * The statement name (eg, "TRUNCATE") is passed for use in error messages. + */ +void +CheckTableNotInUse(Relation rel, const char *stmt) +{ + int expected_refcnt; + + expected_refcnt = rel->rd_isnailed ? 2 : 1; + if (rel->rd_refcnt != expected_refcnt) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + /* translator: first %s is a SQL command, eg ALTER TABLE */ + errmsg("cannot %s \"%s\" because " + "it is being used by active queries in this session", + stmt, RelationGetRelationName(rel)))); + + if (rel->rd_rel->relkind != RELKIND_INDEX && + AfterTriggerPendingOnRel(RelationGetRelid(rel))) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + /* translator: first %s is a SQL command, eg ALTER TABLE */ + errmsg("cannot %s \"%s\" because " + "it has pending trigger events", + stmt, RelationGetRelationName(rel)))); +} /* ---------------- * AlterTableAddColumn |