1515 * that matches the event is marked invalid, as is its generic CachedPlan
1616 * if it has one. When (and if) the next demand for a cached plan occurs,
1717 * parse analysis and rewrite is repeated to build a new valid query tree,
18- * and then planning is performed as normal.
18+ * and then planning is performed as normal. We also force re-analysis and
19+ * re-planning if the active search_path is different from the previous time.
1920 *
2021 * Note that if the sinval was a result of user DDL actions, parse analysis
2122 * could throw an error, for example if a column referenced by the query is
22- * no longer present. The creator of a cached plan can specify whether it
23- * is allowable for the query to change output tupdesc on replan (this
24- * could happen with "SELECT *" for example) --- if so, it's up to the
23+ * no longer present. Another possibility is for the query's output tupdesc
24+ * to change (for instance "SELECT *" might expand differently than before).
25+ * The creator of a cached plan can specify whether it is allowable for the
26+ * query to change output tupdesc on replan --- if so, it's up to the
2527 * caller to notice changes and cope with them.
2628 *
2729 * Currently, we track exactly the dependencies of plans on relations and
@@ -174,11 +176,11 @@ CreateCachedPlan(Node *raw_parse_tree,
174176plansource -> cursor_options = 0 ;
175177plansource -> fixed_result = false;
176178plansource -> resultDesc = NULL ;
177- plansource -> search_path = NULL ;
178179plansource -> context = source_context ;
179180plansource -> query_list = NIL ;
180181plansource -> relationOids = NIL ;
181182plansource -> invalItems = NIL ;
183+ plansource -> search_path = NULL ;
182184plansource -> query_context = NULL ;
183185plansource -> gplan = NULL ;
184186plansource -> is_oneshot = false;
@@ -239,11 +241,11 @@ CreateOneShotCachedPlan(Node *raw_parse_tree,
239241plansource -> cursor_options = 0 ;
240242plansource -> fixed_result = false;
241243plansource -> resultDesc = NULL ;
242- plansource -> search_path = NULL ;
243244plansource -> context = CurrentMemoryContext ;
244245plansource -> query_list = NIL ;
245246plansource -> relationOids = NIL ;
246247plansource -> invalItems = NIL ;
248+ plansource -> search_path = NULL ;
247249plansource -> query_context = NULL ;
248250plansource -> gplan = NULL ;
249251plansource -> is_oneshot = true;
@@ -360,6 +362,14 @@ CompleteCachedPlan(CachedPlanSource *plansource,
360362& plansource -> relationOids ,
361363& plansource -> invalItems );
362364
365+ /*
366+ * Also save the current search_path in the query_context. (This should
367+ * not generate much extra cruft either, since almost certainly the path
368+ * is already valid.) Again, don't really need it for one-shot plans.
369+ */
370+ if (!plansource -> is_oneshot )
371+ plansource -> search_path = GetOverrideSearchPath (querytree_context );
372+
363373/*
364374 * Save the final parameter types (or other parameter specification data)
365375 * into the source_context, as well as our other parameters. Also save
@@ -383,12 +393,6 @@ CompleteCachedPlan(CachedPlanSource *plansource,
383393
384394MemoryContextSwitchTo (oldcxt );
385395
386- /*
387- * Fetch current search_path into dedicated context, but do any
388- * recalculation work required in caller's context.
389- */
390- plansource -> search_path = GetOverrideSearchPath (source_context );
391-
392396plansource -> is_complete = true;
393397plansource -> is_valid = true;
394398}
@@ -546,6 +550,23 @@ RevalidateCachedQuery(CachedPlanSource *plansource)
546550return NIL ;
547551}
548552
553+ /*
554+ * If the query is currently valid, we should have a saved search_path ---
555+ * check to see if that matches the current environment. If not, we want
556+ * to force replan.
557+ */
558+ if (plansource -> is_valid )
559+ {
560+ Assert (plansource -> search_path != NULL );
561+ if (!OverrideSearchPathMatchesCurrent (plansource -> search_path ))
562+ {
563+ /* Invalidate the querytree and generic plan */
564+ plansource -> is_valid = false;
565+ if (plansource -> gplan )
566+ plansource -> gplan -> is_valid = false;
567+ }
568+ }
569+
549570/*
550571 * If the query is currently valid, acquire locks on the referenced
551572 * objects; then check again. We need to do it this way to cover the race
@@ -578,6 +599,7 @@ RevalidateCachedQuery(CachedPlanSource *plansource)
578599plansource -> query_list = NIL ;
579600plansource -> relationOids = NIL ;
580601plansource -> invalItems = NIL ;
602+ plansource -> search_path = NULL ;
581603
582604/*
583605 * Free the query_context.We don't really expect MemoryContextDelete to
@@ -602,14 +624,6 @@ RevalidateCachedQuery(CachedPlanSource *plansource)
602624 */
603625Assert (plansource -> is_complete );
604626
605- /*
606- * Restore the search_path that was in use when the plan was made. See
607- * comments for PushOverrideSearchPath about limitations of this.
608- *
609- * (XXX is there anything else we really need to restore?)
610- */
611- PushOverrideSearchPath (plansource -> search_path );
612-
613627/*
614628 * If a snapshot is already set (the normal case), we can just use that
615629 * for parsing/planning. But if it isn't, install one. Note: no point in
@@ -645,9 +659,6 @@ RevalidateCachedQuery(CachedPlanSource *plansource)
645659if (snapshot_set )
646660PopActiveSnapshot ();
647661
648- /* Now we can restore current search path */
649- PopOverrideSearchPath ();
650-
651662/*
652663 * Check or update the result tupdesc.XXX should we use a weaker
653664 * condition than equalTupleDescs() here?
@@ -699,6 +710,13 @@ RevalidateCachedQuery(CachedPlanSource *plansource)
699710& plansource -> relationOids ,
700711& plansource -> invalItems );
701712
713+ /*
714+ * Also save the current search_path in the query_context. (This should
715+ * not generate much extra cruft either, since almost certainly the path
716+ * is already valid.)
717+ */
718+ plansource -> search_path = GetOverrideSearchPath (querytree_context );
719+
702720MemoryContextSwitchTo (oldcxt );
703721
704722/* Now reparent the finished query_context and save the links */
@@ -848,20 +866,6 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
848866qlist = plansource -> query_list ;
849867}
850868
851- /*
852- * Restore the search_path that was in use when the plan was made. See
853- * comments for PushOverrideSearchPath about limitations of this.
854- *
855- * (XXX is there anything else we really need to restore?)
856- *
857- * Note: it's a bit annoying to do this and snapshot-setting twice in the
858- * case where we have to do both re-analysis and re-planning. However,
859- * until there's some evidence that the cost is actually meaningful
860- * compared to parse analysis + planning, I'm not going to contort the
861- * code enough to avoid that.
862- */
863- PushOverrideSearchPath (plansource -> search_path );
864-
865869/*
866870 * If a snapshot is already set (the normal case), we can just use that
867871 * for planning. But if it isn't, and we need one, install one.
@@ -894,9 +898,6 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
894898if (snapshot_set )
895899PopActiveSnapshot ();
896900
897- /* Now we can restore current search path */
898- PopOverrideSearchPath ();
899-
900901/*
901902 * Normally we make a dedicated memory context for the CachedPlan and its
902903 * subsidiary data. (It's probably not going to be large, but just in
@@ -1268,7 +1269,6 @@ CopyCachedPlan(CachedPlanSource *plansource)
12681269newsource -> resultDesc = CreateTupleDescCopy (plansource -> resultDesc );
12691270else
12701271newsource -> resultDesc = NULL ;
1271- newsource -> search_path = CopyOverrideSearchPath (plansource -> search_path );
12721272newsource -> context = source_context ;
12731273
12741274querytree_context = AllocSetContextCreate (source_context ,
@@ -1280,6 +1280,8 @@ CopyCachedPlan(CachedPlanSource *plansource)
12801280newsource -> query_list = (List * )copyObject (plansource -> query_list );
12811281newsource -> relationOids = (List * )copyObject (plansource -> relationOids );
12821282newsource -> invalItems = (List * )copyObject (plansource -> invalItems );
1283+ if (plansource -> search_path )
1284+ newsource -> search_path = CopyOverrideSearchPath (plansource -> search_path );
12831285newsource -> query_context = querytree_context ;
12841286
12851287newsource -> gplan = NULL ;