@@ -350,6 +350,7 @@ static void exec_prepare_plan(PLpgSQL_execstate *estate,
350350PLpgSQL_expr * expr ,int cursorOptions ,
351351bool keepplan );
352352static void exec_simple_check_plan (PLpgSQL_execstate * estate ,PLpgSQL_expr * expr );
353+ static bool exec_is_simple_query (PLpgSQL_expr * expr );
353354static void exec_save_simple_expr (PLpgSQL_expr * expr ,CachedPlan * cplan );
354355static void exec_check_rw_parameter (PLpgSQL_expr * expr ,int target_dno );
355356static bool contains_target_param (Node * node ,int * target_dno );
@@ -6253,10 +6254,17 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
62536254CurrentResourceOwner = estate -> simple_eval_resowner ;
62546255ReleaseCachedPlan (expr -> expr_simple_plan , true);
62556256CurrentResourceOwner = saveResourceOwner ;
6256- expr -> expr_simple_plan = NULL ;
6257- expr -> expr_simple_plan_lxid = InvalidLocalTransactionId ;
62586257}
62596258
6259+ /*
6260+ * Reset to "not simple" to leave sane state (with no dangling
6261+ * pointers) in case we fail while replanning. expr_simple_plansource
6262+ * can be left alone however, as that cannot move.
6263+ */
6264+ expr -> expr_simple_expr = NULL ;
6265+ expr -> expr_simple_plan = NULL ;
6266+ expr -> expr_simple_plan_lxid = InvalidLocalTransactionId ;
6267+
62606268/* Do the replanning work in the eval_mcontext */
62616269oldcontext = MemoryContextSwitchTo (get_eval_mcontext (estate ));
62626270cplan = SPI_plan_get_cached_plan (expr -> plan );
@@ -6271,11 +6279,15 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
62716279Assert (cplan != NULL );
62726280
62736281/*
6274- * This test probably can't fail either, but if it does, cope by
6275- * declaring the plan to be non-simple. On success, we'll acquire a
6276- * refcount on the new plan, stored in simple_eval_resowner.
6282+ * Recheck exec_is_simple_query, which could now report false in
6283+ * edge-case scenarios such as a non-SRF having been replaced with a
6284+ * SRF. Also recheck CachedPlanAllowsSimpleValidityCheck, just to be
6285+ * sure. If either test fails, cope by declaring the plan to be
6286+ * non-simple. On success, we'll acquire a refcount on the new plan,
6287+ * stored in simple_eval_resowner.
62776288 */
6278- if (CachedPlanAllowsSimpleValidityCheck (expr -> expr_simple_plansource ,
6289+ if (exec_is_simple_query (expr )&&
6290+ CachedPlanAllowsSimpleValidityCheck (expr -> expr_simple_plansource ,
62796291cplan ,
62806292estate -> simple_eval_resowner ))
62816293{
@@ -6287,8 +6299,6 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
62876299{
62886300/* Release SPI_plan_get_cached_plan's refcount */
62896301ReleaseCachedPlan (cplan , true);
6290- /* Mark expression as non-simple, and fail */
6291- expr -> expr_simple_expr = NULL ;
62926302return false;
62936303}
62946304
@@ -8116,7 +8126,6 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
81168126{
81178127List * plansources ;
81188128CachedPlanSource * plansource ;
8119- Query * query ;
81208129CachedPlan * cplan ;
81218130MemoryContext oldcontext ;
81228131
@@ -8131,31 +8140,88 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
81318140 * called immediately after creating the CachedPlanSource, we need not
81328141 * worry about the query being stale.
81338142 */
8143+ if (!exec_is_simple_query (expr ))
8144+ return ;
8145+
8146+ /* exec_is_simple_query verified that there's just one CachedPlanSource */
8147+ plansources = SPI_plan_get_plan_sources (expr -> plan );
8148+ plansource = (CachedPlanSource * )linitial (plansources );
8149+
8150+ /*
8151+ * Get the generic plan for the query. If replanning is needed, do that
8152+ * work in the eval_mcontext. (Note that replanning could throw an error,
8153+ * in which case the expr is left marked "not simple", which is fine.)
8154+ */
8155+ oldcontext = MemoryContextSwitchTo (get_eval_mcontext (estate ));
8156+ cplan = SPI_plan_get_cached_plan (expr -> plan );
8157+ MemoryContextSwitchTo (oldcontext );
8158+
8159+ /* Can't fail, because we checked for a single CachedPlanSource above */
8160+ Assert (cplan != NULL );
8161+
8162+ /*
8163+ * Verify that plancache.c thinks the plan is simple enough to use
8164+ * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8165+ * that this could fail, but if it does, just treat plan as not simple. On
8166+ * success, save a refcount on the plan in the simple-expression resowner.
8167+ */
8168+ if (CachedPlanAllowsSimpleValidityCheck (plansource ,cplan ,
8169+ estate -> simple_eval_resowner ))
8170+ {
8171+ /* Remember that we have the refcount */
8172+ expr -> expr_simple_plansource = plansource ;
8173+ expr -> expr_simple_plan = cplan ;
8174+ expr -> expr_simple_plan_lxid = MyProc -> lxid ;
8175+
8176+ /* Share the remaining work with the replan code path */
8177+ exec_save_simple_expr (expr ,cplan );
8178+ }
81348179
81358180/*
8136- * We can only test queries that resulted in exactly one CachedPlanSource
8181+ * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8182+ * refcount is held by the wrong resowner, so we can't just repurpose it.)
8183+ */
8184+ ReleaseCachedPlan (cplan , true);
8185+ }
8186+
8187+ /*
8188+ * exec_is_simple_query - precheck a query tree to see if it might be simple
8189+ *
8190+ * Check the analyzed-and-rewritten form of a query to see if we will be
8191+ * able to treat it as a simple expression. It is caller's responsibility
8192+ * that the CachedPlanSource be up-to-date.
8193+ */
8194+ static bool
8195+ exec_is_simple_query (PLpgSQL_expr * expr )
8196+ {
8197+ List * plansources ;
8198+ CachedPlanSource * plansource ;
8199+ Query * query ;
8200+
8201+ /*
8202+ * We can only test queries that resulted in exactly one CachedPlanSource.
81378203 */
81388204plansources = SPI_plan_get_plan_sources (expr -> plan );
81398205if (list_length (plansources )!= 1 )
8140- return ;
8206+ return false ;
81418207plansource = (CachedPlanSource * )linitial (plansources );
81428208
81438209/*
81448210 * 1. There must be one single querytree.
81458211 */
81468212if (list_length (plansource -> query_list )!= 1 )
8147- return ;
8213+ return false ;
81488214query = (Query * )linitial (plansource -> query_list );
81498215
81508216/*
8151- * 2. It must be a plain SELECT query without any input tables
8217+ * 2. It must be a plain SELECT query without any input tables.
81528218 */
81538219if (!IsA (query ,Query ))
8154- return ;
8220+ return false ;
81558221if (query -> commandType != CMD_SELECT )
8156- return ;
8222+ return false ;
81578223if (query -> rtable != NIL )
8158- return ;
8224+ return false ;
81598225
81608226/*
81618227 * 3. Can't have any subplans, aggregates, qual clauses either. (These
@@ -8179,51 +8245,18 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
81798245query -> limitOffset ||
81808246query -> limitCount ||
81818247query -> setOperations )
8182- return ;
8248+ return false ;
81838249
81848250/*
8185- * 4. The query must have a single attribute as result
8251+ * 4. The query must have a single attribute as result.
81868252 */
81878253if (list_length (query -> targetList )!= 1 )
8188- return ;
8254+ return false ;
81898255
81908256/*
81918257 * OK, we can treat it as a simple plan.
8192- *
8193- * Get the generic plan for the query. If replanning is needed, do that
8194- * work in the eval_mcontext. (Note that replanning could throw an error,
8195- * in which case the expr is left marked "not simple", which is fine.)
81968258 */
8197- oldcontext = MemoryContextSwitchTo (get_eval_mcontext (estate ));
8198- cplan = SPI_plan_get_cached_plan (expr -> plan );
8199- MemoryContextSwitchTo (oldcontext );
8200-
8201- /* Can't fail, because we checked for a single CachedPlanSource above */
8202- Assert (cplan != NULL );
8203-
8204- /*
8205- * Verify that plancache.c thinks the plan is simple enough to use
8206- * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8207- * that this could fail, but if it does, just treat plan as not simple. On
8208- * success, save a refcount on the plan in the simple-expression resowner.
8209- */
8210- if (CachedPlanAllowsSimpleValidityCheck (plansource ,cplan ,
8211- estate -> simple_eval_resowner ))
8212- {
8213- /* Remember that we have the refcount */
8214- expr -> expr_simple_plansource = plansource ;
8215- expr -> expr_simple_plan = cplan ;
8216- expr -> expr_simple_plan_lxid = MyProc -> lxid ;
8217-
8218- /* Share the remaining work with the replan code path */
8219- exec_save_simple_expr (expr ,cplan );
8220- }
8221-
8222- /*
8223- * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8224- * refcount is held by the wrong resowner, so we can't just repurpose it.)
8225- */
8226- ReleaseCachedPlan (cplan , true);
8259+ return true;
82278260}
82288261
82298262/*