@@ -2122,55 +2122,82 @@ exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
2122
2122
2123
2123
/*
2124
2124
* exec_stmt_call
2125
+ *
2126
+ * NOTE: this is used for both CALL and DO statements.
2125
2127
*/
2126
2128
static int
2127
2129
exec_stmt_call (PLpgSQL_execstate * estate ,PLpgSQL_stmt_call * stmt )
2128
2130
{
2129
2131
PLpgSQL_expr * expr = stmt -> expr ;
2132
+ SPIPlanPtr orig_plan = expr -> plan ;
2133
+ bool local_plan ;
2134
+ PLpgSQL_variable * volatile cur_target = stmt -> target ;
2130
2135
volatile LocalTransactionId before_lxid ;
2131
2136
LocalTransactionId after_lxid ;
2132
2137
volatile bool pushed_active_snap = false;
2133
2138
volatile int rc ;
2134
2139
2140
+ /*
2141
+ * If not in atomic context, we make a local plan that we'll just use for
2142
+ * this invocation, and will free at the end. Otherwise, transaction ends
2143
+ * would cause errors about plancache leaks.
2144
+ *
2145
+ * XXX This would be fixable with some plancache/resowner surgery
2146
+ * elsewhere, but for now we'll just work around this here.
2147
+ */
2148
+ local_plan = !estate -> atomic ;
2149
+
2135
2150
/* PG_TRY to ensure we clear the plan link, if needed, on failure */
2136
2151
PG_TRY ();
2137
2152
{
2138
2153
SPIPlanPtr plan = expr -> plan ;
2139
2154
ParamListInfo paramLI ;
2140
2155
2141
- if (plan == NULL )
2156
+ /*
2157
+ * Make a plan if we don't have one, or if we need a local one. Note
2158
+ * that we'll overwrite expr->plan either way; the PG_TRY block will
2159
+ * ensure we undo that on the way out, if the plan is local.
2160
+ */
2161
+ if (plan == NULL || local_plan )
2142
2162
{
2163
+ /* Don't let SPI save the plan if it's going to be local */
2164
+ exec_prepare_plan (estate ,expr ,0 , !local_plan );
2165
+ plan = expr -> plan ;
2143
2166
2144
2167
/*
2145
- * Don't save the plan if not in atomic context. Otherwise,
2146
- * transaction ends would cause errors about plancache leaks.
2147
- *
2148
- * XXX This would be fixable with some plancache/resowner surgery
2149
- * elsewhere, but for now we'll just work around this here.
2168
+ * A CALL or DO can never be a simple expression. (If it could
2169
+ * be, we'd have to worry about saving/restoring the previous
2170
+ * values of the related expr fields, not just expr->plan.)
2150
2171
*/
2151
- exec_prepare_plan ( estate , expr , 0 , estate -> atomic );
2172
+ Assert (! expr -> expr_simple_expr );
2152
2173
2153
2174
/*
2154
2175
* The procedure call could end transactions, which would upset
2155
2176
* the snapshot management in SPI_execute*, so don't let it do it.
2156
2177
* Instead, we set the snapshots ourselves below.
2157
2178
*/
2158
- plan = expr -> plan ;
2159
2179
plan -> no_snapshots = true;
2160
2180
2161
2181
/*
2162
2182
* Force target to be recalculated whenever the plan changes, in
2163
2183
* case the procedure's argument list has changed.
2164
2184
*/
2165
2185
stmt -> target = NULL ;
2186
+ cur_target = NULL ;
2166
2187
}
2167
2188
2168
2189
/*
2169
2190
* We construct a DTYPE_ROW datum representing the plpgsql variables
2170
2191
* associated with the procedure's output arguments. Then we can use
2171
2192
* exec_move_row() to do the assignments.
2193
+ *
2194
+ * If we're using a local plan, also make a local target; otherwise,
2195
+ * since the above code will force a new plan each time through, we'd
2196
+ * repeatedly leak the memory for the target. (Note: we also leak the
2197
+ * target when a plan change is forced, but that isn't so likely to
2198
+ * cause excessive memory leaks.)
2172
2199
*/
2173
- if (stmt -> is_call && stmt -> target == NULL )
2200
+ if (stmt -> is_call && cur_target == NULL )
2174
2201
{
2175
2202
Node * node ;
2176
2203
FuncExpr * funcexpr ;
@@ -2185,6 +2212,9 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
2185
2212
int i ;
2186
2213
ListCell * lc ;
2187
2214
2215
+ /* Use eval_mcontext for any cruft accumulated here */
2216
+ oldcontext = MemoryContextSwitchTo (get_eval_mcontext (estate ));
2217
+
2188
2218
/*
2189
2219
* Get the parsed CallStmt, and look up the called procedure
2190
2220
*/
@@ -2216,17 +2246,20 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
2216
2246
ReleaseSysCache (func_tuple );
2217
2247
2218
2248
/*
2219
- * Begin constructing row Datum
2249
+ * Begin constructing row Datum; keep it in fn_cxt if it's to be
2250
+ * long-lived.
2220
2251
*/
2221
- oldcontext = MemoryContextSwitchTo (estate -> func -> fn_cxt );
2252
+ if (!local_plan )
2253
+ MemoryContextSwitchTo (estate -> func -> fn_cxt );
2222
2254
2223
2255
row = (PLpgSQL_row * )palloc0 (sizeof (PLpgSQL_row ));
2224
2256
row -> dtype = PLPGSQL_DTYPE_ROW ;
2225
2257
row -> refname = "(unnamed row)" ;
2226
2258
row -> lineno = -1 ;
2227
2259
row -> varnos = (int * )palloc (sizeof (int )* list_length (funcargs ));
2228
2260
2229
- MemoryContextSwitchTo (oldcontext );
2261
+ if (!local_plan )
2262
+ MemoryContextSwitchTo (get_eval_mcontext (estate ));
2230
2263
2231
2264
/*
2232
2265
* Examine procedure's argument list. Each output arg position
@@ -2270,7 +2303,13 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
2270
2303
2271
2304
row -> nfields = nfields ;
2272
2305
2273
- stmt -> target = (PLpgSQL_variable * )row ;
2306
+ cur_target = (PLpgSQL_variable * )row ;
2307
+
2308
+ /* We can save and re-use the target datum, if it's not local */
2309
+ if (!local_plan )
2310
+ stmt -> target = cur_target ;
2311
+
2312
+ MemoryContextSwitchTo (oldcontext );
2274
2313
}
2275
2314
2276
2315
paramLI = setup_param_list (estate ,expr );
@@ -2293,17 +2332,27 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
2293
2332
PG_CATCH ();
2294
2333
{
2295
2334
/*
2296
- * If we aren't saving the plan, unset the pointer. Note that it
2297
- * could have been unset already, in case of a recursive call.
2335
+ * If we are using a local plan, restore the old plan link.
2298
2336
*/
2299
- if (expr -> plan && ! expr -> plan -> saved )
2300
- expr -> plan = NULL ;
2337
+ if (local_plan )
2338
+ expr -> plan = orig_plan ;
2301
2339
PG_RE_THROW ();
2302
2340
}
2303
2341
PG_END_TRY ();
2304
2342
2305
- if (expr -> plan && !expr -> plan -> saved )
2306
- expr -> plan = NULL ;
2343
+ /*
2344
+ * If we are using a local plan, restore the old plan link; then free the
2345
+ * local plan to avoid memory leaks. (Note that the error exit path above
2346
+ * just clears the link without risking calling SPI_freeplan; we expect
2347
+ * that xact cleanup will take care of the mess in that case.)
2348
+ */
2349
+ if (local_plan )
2350
+ {
2351
+ SPIPlanPtr plan = expr -> plan ;
2352
+
2353
+ expr -> plan = orig_plan ;
2354
+ SPI_freeplan (plan );
2355
+ }
2307
2356
2308
2357
if (rc < 0 )
2309
2358
elog (ERROR ,"SPI_execute_plan_with_paramlist failed executing query \"%s\": %s" ,
@@ -2339,10 +2388,10 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
2339
2388
{
2340
2389
SPITupleTable * tuptab = SPI_tuptable ;
2341
2390
2342
- if (!stmt -> target )
2391
+ if (!cur_target )
2343
2392
elog (ERROR ,"DO statement returned a row" );
2344
2393
2345
- exec_move_row (estate ,stmt -> target ,tuptab -> vals [0 ],tuptab -> tupdesc );
2394
+ exec_move_row (estate ,cur_target ,tuptab -> vals [0 ],tuptab -> tupdesc );
2346
2395
}
2347
2396
else if (SPI_processed > 1 )
2348
2397
elog (ERROR ,"procedure call returned more than one row" );