aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-01-13 16:56:56 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2010-01-13 16:56:56 +0000
commitdbba3a1465472bda66265e6a38fd24cbe619f233 (patch)
tree431e042905f4f619d392d56a60d15f78eee3ecd8 /src
parentb3627d1de3ec03adea8551465351bc536f12f526 (diff)
downloadpostgresql-dbba3a1465472bda66265e6a38fd24cbe619f233.tar.gz
postgresql-dbba3a1465472bda66265e6a38fd24cbe619f233.zip
Fix bug #5269: ResetPlanCache mustn't invalidate cached utility statements,
especially not ROLLBACK. ROLLBACK might need to be executed in an already aborted transaction, when there is no safe way to revalidate the plan. But in general there's no point in marking utility statements invalid, since they have no plans in the normal sense of the word; so we might as well work a bit harder here to avoid future revalidation cycles. Back-patch to 8.4, where the bug was introduced.
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/cache/plancache.c55
1 files changed, 49 insertions, 6 deletions
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 88a5c28d19b..ffa117b66cd 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -35,7 +35,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.32 2010/01/02 16:57:55 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.33 2010/01/13 16:56:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1068,14 +1068,57 @@ PlanCacheSysCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
void
ResetPlanCache(void)
{
- ListCell *lc;
+ ListCell *lc1;
- foreach(lc, cached_plans_list)
+ foreach(lc1, cached_plans_list)
{
- CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
+ CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
CachedPlan *plan = plansource->plan;
+ ListCell *lc2;
- if (plan)
- plan->dead = true;
+ /* No work if it's already invalidated */
+ if (!plan || plan->dead)
+ continue;
+
+ /*
+ * We *must not* mark transaction control statements as dead,
+ * particularly not ROLLBACK, because they may need to be executed in
+ * aborted transactions when we can't revalidate them (cf bug #5269).
+ * In general there is no point in invalidating utility statements
+ * since they have no plans anyway. So mark it dead only if it
+ * contains at least one non-utility statement.
+ */
+ if (plan->fully_planned)
+ {
+ /* Search statement list for non-utility statements */
+ foreach(lc2, plan->stmt_list)
+ {
+ PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc2);
+
+ Assert(!IsA(plannedstmt, Query));
+ if (IsA(plannedstmt, PlannedStmt))
+ {
+ /* non-utility statement, so invalidate */
+ plan->dead = true;
+ break; /* out of stmt_list scan */
+ }
+ }
+ }
+ else
+ {
+ /* Search Query list for non-utility statements */
+ foreach(lc2, plan->stmt_list)
+ {
+ Query *query = (Query *) lfirst(lc2);
+
+ Assert(IsA(query, Query));
+ if (query->commandType != CMD_UTILITY)
+ {
+ /* non-utility statement, so invalidate */
+ plan->dead = true;
+ break; /* out of stmt_list scan */
+ }
+ }
+ }
}
}