diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index 88a5c28d19..ffa117b66c 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 */ + } + } + } } }