Skip to content

Commit f8bbfad

Browse files
committed
Disallow TRUNCATE when there are any pending after-trigger events for
the target relation(s). There might be some cases where we could discard the pending event instead, but for the moment a conservative approach seems sufficient. Per report from Markus Schiltknecht and subsequent discussion.
1 parent 395c816 commit f8bbfad

File tree

3 files changed

+79
-4
lines changed

3 files changed

+79
-4
lines changed

src/backend/commands/tablecmds.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.201 2006/08/25 04:06:48 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.202 2006/09/04 21:15:55 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -611,6 +611,13 @@ ExecuteTruncate(TruncateStmt *stmt)
611611
heap_truncate_check_FKs(rels, false);
612612
#endif
613613

614+
/*
615+
* Also check for pending AFTER trigger events on the target relations.
616+
* We can't just leave those be, since they will try to fetch tuples
617+
* that the TRUNCATE removes.
618+
*/
619+
AfterTriggerCheckTruncate(relids);
620+
614621
/*
615622
* OK, truncate each table.
616623
*/

src/backend/commands/trigger.c

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.206 2006/08/03 16:04:41 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.207 2006/09/04 21:15:56 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -3117,6 +3117,74 @@ AfterTriggerSetState(ConstraintsSetStmt *stmt)
31173117
}
31183118
}
31193119

3120+
/* ----------
3121+
* AfterTriggerCheckTruncate()
3122+
* Test deferred-trigger status to see if a TRUNCATE is OK.
3123+
*
3124+
* The argument is a list of OIDs of relations due to be truncated.
3125+
* We raise error if there are any pending after-trigger events for them.
3126+
*
3127+
* In some scenarios it'd be reasonable to remove pending events (more
3128+
* specifically, mark them DONE by the current subxact) but without a lot
3129+
* of knowledge of the trigger semantics we can't do this in general.
3130+
* ----------
3131+
*/
3132+
void
3133+
AfterTriggerCheckTruncate(List *relids)
3134+
{
3135+
AfterTriggerEvent event;
3136+
int depth;
3137+
3138+
/*
3139+
* Ignore call if we aren't in a transaction. (Shouldn't happen?)
3140+
*/
3141+
if (afterTriggers == NULL)
3142+
return;
3143+
3144+
/* Scan queued events */
3145+
for (event = afterTriggers->events.head;
3146+
event != NULL;
3147+
event = event->ate_next)
3148+
{
3149+
/*
3150+
* We can ignore completed events. (Even if a DONE flag is rolled
3151+
* back by subxact abort, it's OK because the effects of the
3152+
* TRUNCATE must get rolled back too.)
3153+
*/
3154+
if (event->ate_event & AFTER_TRIGGER_DONE)
3155+
continue;
3156+
3157+
if (list_member_oid(relids, event->ate_relid))
3158+
ereport(ERROR,
3159+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3160+
errmsg("cannot truncate table \"%s\" because it has pending trigger events",
3161+
get_rel_name(event->ate_relid))));
3162+
}
3163+
3164+
/*
3165+
* Also scan events queued by incomplete queries. This could only
3166+
* matter if a TRUNCATE is executed by a function or trigger within
3167+
* an updating query on the same relation, which is pretty perverse,
3168+
* but let's check.
3169+
*/
3170+
for (depth = 0; depth <= afterTriggers->query_depth; depth++)
3171+
{
3172+
for (event = afterTriggers->query_stack[depth].head;
3173+
event != NULL;
3174+
event = event->ate_next)
3175+
{
3176+
if (event->ate_event & AFTER_TRIGGER_DONE)
3177+
continue;
3178+
3179+
if (list_member_oid(relids, event->ate_relid))
3180+
ereport(ERROR,
3181+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3182+
errmsg("cannot truncate table \"%s\" because it has pending trigger events",
3183+
get_rel_name(event->ate_relid))));
3184+
}
3185+
}
3186+
}
3187+
31203188

31213189
/* ----------
31223190
* AfterTriggerSaveEvent()

src/include/commands/trigger.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.58 2006/06/16 20:23:45 adunstan Exp $
9+
* $PostgreSQL: pgsql/src/include/commands/trigger.h,v 1.59 2006/09/04 21:15:56 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -164,8 +164,8 @@ extern void AfterTriggerFireDeferred(void);
164164
extern void AfterTriggerEndXact(bool isCommit);
165165
extern void AfterTriggerBeginSubXact(void);
166166
extern void AfterTriggerEndSubXact(bool isCommit);
167-
168167
extern void AfterTriggerSetState(ConstraintsSetStmt *stmt);
168+
extern void AfterTriggerCheckTruncate(List *relids);
169169

170170

171171
/*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy