@@ -350,6 +350,7 @@ static void exec_prepare_plan(PLpgSQL_execstate *estate,
350
350
PLpgSQL_expr * expr ,int cursorOptions ,
351
351
bool keepplan );
352
352
static void exec_simple_check_plan (PLpgSQL_execstate * estate ,PLpgSQL_expr * expr );
353
+ static bool exec_is_simple_query (PLpgSQL_expr * expr );
353
354
static void exec_save_simple_expr (PLpgSQL_expr * expr ,CachedPlan * cplan );
354
355
static void exec_check_rw_parameter (PLpgSQL_expr * expr ,int target_dno );
355
356
static bool contains_target_param (Node * node ,int * target_dno );
@@ -6253,10 +6254,17 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
6253
6254
CurrentResourceOwner = estate -> simple_eval_resowner ;
6254
6255
ReleaseCachedPlan (expr -> expr_simple_plan , true);
6255
6256
CurrentResourceOwner = saveResourceOwner ;
6256
- expr -> expr_simple_plan = NULL ;
6257
- expr -> expr_simple_plan_lxid = InvalidLocalTransactionId ;
6258
6257
}
6259
6258
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
+
6260
6268
/* Do the replanning work in the eval_mcontext */
6261
6269
oldcontext = MemoryContextSwitchTo (get_eval_mcontext (estate ));
6262
6270
cplan = SPI_plan_get_cached_plan (expr -> plan );
@@ -6271,11 +6279,15 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
6271
6279
Assert (cplan != NULL );
6272
6280
6273
6281
/*
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.
6277
6288
*/
6278
- if (CachedPlanAllowsSimpleValidityCheck (expr -> expr_simple_plansource ,
6289
+ if (exec_is_simple_query (expr )&&
6290
+ CachedPlanAllowsSimpleValidityCheck (expr -> expr_simple_plansource ,
6279
6291
cplan ,
6280
6292
estate -> simple_eval_resowner ))
6281
6293
{
@@ -6287,8 +6299,6 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
6287
6299
{
6288
6300
/* Release SPI_plan_get_cached_plan's refcount */
6289
6301
ReleaseCachedPlan (cplan , true);
6290
- /* Mark expression as non-simple, and fail */
6291
- expr -> expr_simple_expr = NULL ;
6292
6302
return false;
6293
6303
}
6294
6304
@@ -8116,7 +8126,6 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
8116
8126
{
8117
8127
List * plansources ;
8118
8128
CachedPlanSource * plansource ;
8119
- Query * query ;
8120
8129
CachedPlan * cplan ;
8121
8130
MemoryContext oldcontext ;
8122
8131
@@ -8131,31 +8140,88 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
8131
8140
* called immediately after creating the CachedPlanSource, we need not
8132
8141
* worry about the query being stale.
8133
8142
*/
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
+ }
8134
8179
8135
8180
/*
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.
8137
8203
*/
8138
8204
plansources = SPI_plan_get_plan_sources (expr -> plan );
8139
8205
if (list_length (plansources )!= 1 )
8140
- return ;
8206
+ return false ;
8141
8207
plansource = (CachedPlanSource * )linitial (plansources );
8142
8208
8143
8209
/*
8144
8210
* 1. There must be one single querytree.
8145
8211
*/
8146
8212
if (list_length (plansource -> query_list )!= 1 )
8147
- return ;
8213
+ return false ;
8148
8214
query = (Query * )linitial (plansource -> query_list );
8149
8215
8150
8216
/*
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.
8152
8218
*/
8153
8219
if (!IsA (query ,Query ))
8154
- return ;
8220
+ return false ;
8155
8221
if (query -> commandType != CMD_SELECT )
8156
- return ;
8222
+ return false ;
8157
8223
if (query -> rtable != NIL )
8158
- return ;
8224
+ return false ;
8159
8225
8160
8226
/*
8161
8227
* 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)
8179
8245
query -> limitOffset ||
8180
8246
query -> limitCount ||
8181
8247
query -> setOperations )
8182
- return ;
8248
+ return false ;
8183
8249
8184
8250
/*
8185
- * 4. The query must have a single attribute as result
8251
+ * 4. The query must have a single attribute as result.
8186
8252
*/
8187
8253
if (list_length (query -> targetList )!= 1 )
8188
- return ;
8254
+ return false ;
8189
8255
8190
8256
/*
8191
8257
* 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.)
8196
8258
*/
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;
8227
8260
}
8228
8261
8229
8262
/*