@@ -339,6 +339,7 @@ static void exec_eval_cleanup(PLpgSQL_execstate *estate);
339
339
static void exec_prepare_plan (PLpgSQL_execstate * estate ,
340
340
PLpgSQL_expr * expr ,int cursorOptions );
341
341
static void exec_simple_check_plan (PLpgSQL_execstate * estate ,PLpgSQL_expr * expr );
342
+ static bool exec_is_simple_query (PLpgSQL_expr * expr );
342
343
static void exec_save_simple_expr (PLpgSQL_expr * expr ,CachedPlan * cplan );
343
344
static void exec_check_rw_parameter (PLpgSQL_expr * expr );
344
345
static void exec_check_assignable (PLpgSQL_execstate * estate ,int dno );
@@ -6092,12 +6093,18 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
6092
6093
* release it, so we don't leak plans intra-transaction.
6093
6094
*/
6094
6095
if (expr -> expr_simple_plan_lxid == curlxid )
6095
- {
6096
6096
ReleaseCachedPlan (expr -> expr_simple_plan ,
6097
6097
estate -> simple_eval_resowner );
6098
- expr -> expr_simple_plan = NULL ;
6099
- expr -> expr_simple_plan_lxid = InvalidLocalTransactionId ;
6100
- }
6098
+
6099
+ /*
6100
+ * Reset to "not simple" to leave sane state (with no dangling
6101
+ * pointers) in case we fail while replanning. expr_simple_plansource
6102
+ * can be left alone however, as that cannot move.
6103
+ */
6104
+ expr -> expr_simple_expr = NULL ;
6105
+ expr -> expr_rw_param = NULL ;
6106
+ expr -> expr_simple_plan = NULL ;
6107
+ expr -> expr_simple_plan_lxid = InvalidLocalTransactionId ;
6101
6108
6102
6109
/* Do the replanning work in the eval_mcontext */
6103
6110
oldcontext = MemoryContextSwitchTo (get_eval_mcontext (estate ));
@@ -6113,11 +6120,15 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
6113
6120
Assert (cplan != NULL );
6114
6121
6115
6122
/*
6116
- * This test probably can't fail either, but if it does, cope by
6117
- * declaring the plan to be non-simple. On success, we'll acquire a
6118
- * refcount on the new plan, stored in simple_eval_resowner.
6123
+ * Recheck exec_is_simple_query, which could now report false in
6124
+ * edge-case scenarios such as a non-SRF having been replaced with a
6125
+ * SRF. Also recheck CachedPlanAllowsSimpleValidityCheck, just to be
6126
+ * sure. If either test fails, cope by declaring the plan to be
6127
+ * non-simple. On success, we'll acquire a refcount on the new plan,
6128
+ * stored in simple_eval_resowner.
6119
6129
*/
6120
- if (CachedPlanAllowsSimpleValidityCheck (expr -> expr_simple_plansource ,
6130
+ if (exec_is_simple_query (expr )&&
6131
+ CachedPlanAllowsSimpleValidityCheck (expr -> expr_simple_plansource ,
6121
6132
cplan ,
6122
6133
estate -> simple_eval_resowner ))
6123
6134
{
@@ -6129,9 +6140,6 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
6129
6140
{
6130
6141
/* Release SPI_plan_get_cached_plan's refcount */
6131
6142
ReleaseCachedPlan (cplan ,CurrentResourceOwner );
6132
- /* Mark expression as non-simple, and fail */
6133
- expr -> expr_simple_expr = NULL ;
6134
- expr -> expr_rw_param = NULL ;
6135
6143
return false;
6136
6144
}
6137
6145
@@ -7972,7 +7980,6 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
7972
7980
{
7973
7981
List * plansources ;
7974
7982
CachedPlanSource * plansource ;
7975
- Query * query ;
7976
7983
CachedPlan * cplan ;
7977
7984
MemoryContext oldcontext ;
7978
7985
@@ -7988,31 +7995,88 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
7988
7995
* called immediately after creating the CachedPlanSource, we need not
7989
7996
* worry about the query being stale.
7990
7997
*/
7998
+ if (!exec_is_simple_query (expr ))
7999
+ return ;
8000
+
8001
+ /* exec_is_simple_query verified that there's just one CachedPlanSource */
8002
+ plansources = SPI_plan_get_plan_sources (expr -> plan );
8003
+ plansource = (CachedPlanSource * )linitial (plansources );
7991
8004
7992
8005
/*
7993
- * We can only test queries that resulted in exactly one CachedPlanSource
8006
+ * Get the generic plan for the query. If replanning is needed, do that
8007
+ * work in the eval_mcontext. (Note that replanning could throw an error,
8008
+ * in which case the expr is left marked "not simple", which is fine.)
8009
+ */
8010
+ oldcontext = MemoryContextSwitchTo (get_eval_mcontext (estate ));
8011
+ cplan = SPI_plan_get_cached_plan (expr -> plan );
8012
+ MemoryContextSwitchTo (oldcontext );
8013
+
8014
+ /* Can't fail, because we checked for a single CachedPlanSource above */
8015
+ Assert (cplan != NULL );
8016
+
8017
+ /*
8018
+ * Verify that plancache.c thinks the plan is simple enough to use
8019
+ * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8020
+ * that this could fail, but if it does, just treat plan as not simple. On
8021
+ * success, save a refcount on the plan in the simple-expression resowner.
8022
+ */
8023
+ if (CachedPlanAllowsSimpleValidityCheck (plansource ,cplan ,
8024
+ estate -> simple_eval_resowner ))
8025
+ {
8026
+ /* Remember that we have the refcount */
8027
+ expr -> expr_simple_plansource = plansource ;
8028
+ expr -> expr_simple_plan = cplan ;
8029
+ expr -> expr_simple_plan_lxid = MyProc -> lxid ;
8030
+
8031
+ /* Share the remaining work with the replan code path */
8032
+ exec_save_simple_expr (expr ,cplan );
8033
+ }
8034
+
8035
+ /*
8036
+ * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8037
+ * refcount is held by the wrong resowner, so we can't just repurpose it.)
8038
+ */
8039
+ ReleaseCachedPlan (cplan ,CurrentResourceOwner );
8040
+ }
8041
+
8042
+ /*
8043
+ * exec_is_simple_query - precheck a query tree to see if it might be simple
8044
+ *
8045
+ * Check the analyzed-and-rewritten form of a query to see if we will be
8046
+ * able to treat it as a simple expression. It is caller's responsibility
8047
+ * that the CachedPlanSource be up-to-date.
8048
+ */
8049
+ static bool
8050
+ exec_is_simple_query (PLpgSQL_expr * expr )
8051
+ {
8052
+ List * plansources ;
8053
+ CachedPlanSource * plansource ;
8054
+ Query * query ;
8055
+
8056
+ /*
8057
+ * We can only test queries that resulted in exactly one CachedPlanSource.
7994
8058
*/
7995
8059
plansources = SPI_plan_get_plan_sources (expr -> plan );
7996
8060
if (list_length (plansources )!= 1 )
7997
- return ;
8061
+ return false ;
7998
8062
plansource = (CachedPlanSource * )linitial (plansources );
7999
8063
8000
8064
/*
8001
8065
* 1. There must be one single querytree.
8002
8066
*/
8003
8067
if (list_length (plansource -> query_list )!= 1 )
8004
- return ;
8068
+ return false ;
8005
8069
query = (Query * )linitial (plansource -> query_list );
8006
8070
8007
8071
/*
8008
- * 2. It must be a plain SELECT query without any input tables
8072
+ * 2. It must be a plain SELECT query without any input tables.
8009
8073
*/
8010
8074
if (!IsA (query ,Query ))
8011
- return ;
8075
+ return false ;
8012
8076
if (query -> commandType != CMD_SELECT )
8013
- return ;
8077
+ return false ;
8014
8078
if (query -> rtable != NIL )
8015
- return ;
8079
+ return false ;
8016
8080
8017
8081
/*
8018
8082
* 3. Can't have any subplans, aggregates, qual clauses either. (These
@@ -8036,51 +8100,18 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
8036
8100
query -> limitOffset ||
8037
8101
query -> limitCount ||
8038
8102
query -> setOperations )
8039
- return ;
8103
+ return false ;
8040
8104
8041
8105
/*
8042
- * 4. The query must have a single attribute as result
8106
+ * 4. The query must have a single attribute as result.
8043
8107
*/
8044
8108
if (list_length (query -> targetList )!= 1 )
8045
- return ;
8109
+ return false ;
8046
8110
8047
8111
/*
8048
8112
* OK, we can treat it as a simple plan.
8049
- *
8050
- * Get the generic plan for the query. If replanning is needed, do that
8051
- * work in the eval_mcontext. (Note that replanning could throw an error,
8052
- * in which case the expr is left marked "not simple", which is fine.)
8053
- */
8054
- oldcontext = MemoryContextSwitchTo (get_eval_mcontext (estate ));
8055
- cplan = SPI_plan_get_cached_plan (expr -> plan );
8056
- MemoryContextSwitchTo (oldcontext );
8057
-
8058
- /* Can't fail, because we checked for a single CachedPlanSource above */
8059
- Assert (cplan != NULL );
8060
-
8061
- /*
8062
- * Verify that plancache.c thinks the plan is simple enough to use
8063
- * CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8064
- * that this could fail, but if it does, just treat plan as not simple. On
8065
- * success, save a refcount on the plan in the simple-expression resowner.
8066
- */
8067
- if (CachedPlanAllowsSimpleValidityCheck (plansource ,cplan ,
8068
- estate -> simple_eval_resowner ))
8069
- {
8070
- /* Remember that we have the refcount */
8071
- expr -> expr_simple_plansource = plansource ;
8072
- expr -> expr_simple_plan = cplan ;
8073
- expr -> expr_simple_plan_lxid = MyProc -> lxid ;
8074
-
8075
- /* Share the remaining work with the replan code path */
8076
- exec_save_simple_expr (expr ,cplan );
8077
- }
8078
-
8079
- /*
8080
- * Release the plan refcount obtained by SPI_plan_get_cached_plan. (This
8081
- * refcount is held by the wrong resowner, so we can't just repurpose it.)
8082
8113
*/
8083
- ReleaseCachedPlan ( cplan , CurrentResourceOwner ) ;
8114
+ return true ;
8084
8115
}
8085
8116
8086
8117
/*