Skip to content

Commit fd53a67

Browse files
committed
Prevent RevalidateCachedPlan from making any permanent change in
ActiveSnapshot. Having it affect ActiveSnapshot only in the unusual case of needing to replan seems a bad idea, and there's also the problem that the created snap might be in a relatively short-lived context, as noted by Jan Wieck. Also, there's no need to force a new snap at all unless we are called with no snap currently set, which is an unusual case in itself.
1 parent 689dea4 commit fd53a67

File tree

1 file changed

+47
-7
lines changed

1 file changed

+47
-7
lines changed

src/backend/utils/cache/plancache.c

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
* Portions Copyright (c) 1994, Regents of the University of California
3434
*
3535
* IDENTIFICATION
36-
* $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.8 2007/04/16 18:21:07 tgl Exp $
36+
* $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.9 2007/05/14 18:13:21 tgl Exp $
3737
*
3838
*-------------------------------------------------------------------------
3939
*/
@@ -69,6 +69,7 @@ static List *cached_plans_list = NIL;
6969

7070
static void StoreCachedPlan(CachedPlanSource *plansource, List *stmt_list,
7171
MemoryContext plan_context);
72+
static List *do_planning(List *querytrees, int cursorOptions);
7273
static void AcquireExecutorLocks(List *stmt_list, bool acquire);
7374
static void AcquirePlannerLocks(List *stmt_list, bool acquire);
7475
static void LockRelid(Oid relid, LOCKMODE lockmode, void *arg);
@@ -462,12 +463,8 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
462463

463464
if (plansource->fully_planned)
464465
{
465-
/*
466-
* Generate plans for queries. Assume snapshot is not set yet
467-
* (XXX this may be wasteful, won't all callers have done that?)
468-
*/
469-
slist = pg_plan_queries(slist, plansource->cursor_options, NULL,
470-
true);
466+
/* Generate plans for queries */
467+
slist = do_planning(slist, plansource->cursor_options);
471468
}
472469

473470
/*
@@ -522,6 +519,49 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
522519
return plan;
523520
}
524521

522+
/*
523+
* Invoke the planner on some rewritten queries. This is broken out of
524+
* RevalidateCachedPlan just to avoid plastering "volatile" all over that
525+
* function's variables.
526+
*/
527+
static List *
528+
do_planning(List *querytrees, int cursorOptions)
529+
{
530+
List *stmt_list;
531+
532+
/*
533+
* If a snapshot is already set (the normal case), we can just use that
534+
* for planning. But if it isn't, we have to tell pg_plan_queries to make
535+
* a snap if it needs one. In that case we should arrange to reset
536+
* ActiveSnapshot afterward, to ensure that RevalidateCachedPlan has no
537+
* caller-visible effects on the snapshot. Having to replan is an unusual
538+
* case, and it seems a really bad idea for RevalidateCachedPlan to affect
539+
* the snapshot only in unusual cases. (Besides, the snap might have
540+
* been created in a short-lived context.)
541+
*/
542+
if (ActiveSnapshot != NULL)
543+
stmt_list = pg_plan_queries(querytrees, cursorOptions, NULL, false);
544+
else
545+
{
546+
PG_TRY();
547+
{
548+
stmt_list = pg_plan_queries(querytrees, cursorOptions, NULL, true);
549+
}
550+
PG_CATCH();
551+
{
552+
/* Restore global vars and propagate error */
553+
ActiveSnapshot = NULL;
554+
PG_RE_THROW();
555+
}
556+
PG_END_TRY();
557+
558+
ActiveSnapshot = NULL;
559+
}
560+
561+
return stmt_list;
562+
}
563+
564+
525565
/*
526566
* ReleaseCachedPlan: release active use of a cached plan.
527567
*

0 commit comments

Comments
 (0)