8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.239 2009/04/02 20:16:30 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.240 2009/04/09 02:57:53 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
24
24
#include "funcapi.h"
25
25
#include "nodes/nodeFuncs.h"
26
26
#include "parser/scansup.h"
27
+ #include "storage/proc.h"
27
28
#include "tcop/tcopprot.h"
28
29
#include "utils/array.h"
29
30
#include "utils/builtins.h"
@@ -51,27 +52,26 @@ typedef struct
51
52
* creates its own "eval_econtext" ExprContext within this estate for
52
53
* per-evaluation workspace. eval_econtext is freed at normal function exit,
53
54
* and the EState is freed at transaction end (in case of error, we assume
54
- * that the abort mechanisms clean it all up). In order to be sure
55
- * ExprContext callbacks are handled properly, each subtransaction has to have
56
- * its own such EState; hence we need a stack. We use a simple counter to
57
- * distinguish different instantiations of the EState, so that we can tell
58
- * whether we have a current copy of a prepared expression .
55
+ * that the abort mechanisms clean it all up). Furthermore, any exception
56
+ * block within a function has to have its own eval_econtext separate from
57
+ * the containing function's, so that we can clean up ExprContext callbacks
58
+ * properly at subtransaction exit. We maintain a stack that tracks the
59
+ * individual econtexts so that we can clean up correctly at subxact exit .
59
60
*
60
61
* This arrangement is a bit tedious to maintain, but it's worth the trouble
61
62
* so that we don't have to re-prepare simple expressions on each trip through
62
63
* a function. (We assume the case to optimize is many repetitions of a
63
64
* function within a transaction.)
64
65
*/
65
- typedef struct SimpleEstateStackEntry
66
+ typedef struct SimpleEcontextStackEntry
66
67
{
67
- EState * xact_eval_estate ; /* EState for current xact level */
68
- long int xact_estate_simple_id ; /* ID for xact_eval_estate */
69
- SubTransactionId xact_subxid ; /* ID for current subxact */
70
- struct SimpleEstateStackEntry * next ; /* next stack entry up */
71
- } SimpleEstateStackEntry ;
68
+ ExprContext * stack_econtext ; /* a stacked econtext */
69
+ SubTransactionId xact_subxid ; /* ID for current subxact */
70
+ struct SimpleEcontextStackEntry * next ; /* next stack entry up */
71
+ } SimpleEcontextStackEntry ;
72
72
73
- static SimpleEstateStackEntry * simple_estate_stack = NULL ;
74
- static long int simple_estate_id_counter = 0 ;
73
+ static EState * simple_eval_estate = NULL ;
74
+ static SimpleEcontextStackEntry * simple_econtext_stack = NULL ;
75
75
76
76
/************************************************************
77
77
* Local function forward declarations
@@ -193,6 +193,7 @@ static void validate_tupdesc_compat(TupleDesc expected, TupleDesc returned,
193
193
const char * msg );
194
194
static void exec_set_found (PLpgSQL_execstate * estate , bool state );
195
195
static void plpgsql_create_econtext (PLpgSQL_execstate * estate );
196
+ static void plpgsql_destroy_econtext (PLpgSQL_execstate * estate );
196
197
static void free_var (PLpgSQL_var * var );
197
198
static void assign_text_var (PLpgSQL_var * var , const char * str );
198
199
static PreparedParamsData * exec_eval_using_params (PLpgSQL_execstate * estate ,
@@ -452,8 +453,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
452
453
((* plugin_ptr )-> func_end ) (& estate , func );
453
454
454
455
/* Clean up any leftover temporary memory */
455
- FreeExprContext (estate .eval_econtext );
456
- estate .eval_econtext = NULL ;
456
+ plpgsql_destroy_econtext (& estate );
457
457
exec_eval_cleanup (& estate );
458
458
459
459
/*
@@ -718,8 +718,7 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
718
718
((* plugin_ptr )-> func_end ) (& estate , func );
719
719
720
720
/* Clean up any leftover temporary memory */
721
- FreeExprContext (estate .eval_econtext );
722
- estate .eval_econtext = NULL ;
721
+ plpgsql_destroy_econtext (& estate );
723
722
exec_eval_cleanup (& estate );
724
723
725
724
/*
@@ -984,8 +983,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
984
983
MemoryContext oldcontext = CurrentMemoryContext ;
985
984
ResourceOwner oldowner = CurrentResourceOwner ;
986
985
ExprContext * old_eval_econtext = estate -> eval_econtext ;
987
- EState * old_eval_estate = estate -> eval_estate ;
988
- long int old_eval_estate_simple_id = estate -> eval_estate_simple_id ;
989
986
990
987
estate -> err_text = gettext_noop ("during statement block entry" );
991
988
@@ -1034,10 +1031,11 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
1034
1031
MemoryContextSwitchTo (oldcontext );
1035
1032
CurrentResourceOwner = oldowner ;
1036
1033
1037
- /* Revert to outer eval_econtext */
1034
+ /*
1035
+ * Revert to outer eval_econtext. (The inner one was automatically
1036
+ * cleaned up during subxact exit.)
1037
+ */
1038
1038
estate -> eval_econtext = old_eval_econtext ;
1039
- estate -> eval_estate = old_eval_estate ;
1040
- estate -> eval_estate_simple_id = old_eval_estate_simple_id ;
1041
1039
1042
1040
/*
1043
1041
* AtEOSubXact_SPI() should not have popped any SPI context, but
@@ -1064,8 +1062,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
1064
1062
1065
1063
/* Revert to outer eval_econtext */
1066
1064
estate -> eval_econtext = old_eval_econtext ;
1067
- estate -> eval_estate = old_eval_estate ;
1068
- estate -> eval_estate_simple_id = old_eval_estate_simple_id ;
1069
1065
1070
1066
/*
1071
1067
* If AtEOSubXact_SPI() popped any SPI context of the subxact, it
@@ -4333,6 +4329,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
4333
4329
Oid * rettype )
4334
4330
{
4335
4331
ExprContext * econtext = estate -> eval_econtext ;
4332
+ LocalTransactionId curlxid = MyProc -> lxid ;
4336
4333
CachedPlanSource * plansource ;
4337
4334
CachedPlan * cplan ;
4338
4335
ParamListInfo paramLI ;
@@ -4373,14 +4370,14 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
4373
4370
4374
4371
/*
4375
4372
* Prepare the expression for execution, if it's not been done already in
4376
- * the current eval_estate . (This will be forced to happen if we called
4373
+ * the current transaction . (This will be forced to happen if we called
4377
4374
* exec_simple_check_plan above.)
4378
4375
*/
4379
- if (expr -> expr_simple_id != estate -> eval_estate_simple_id )
4376
+ if (expr -> expr_simple_lxid != curlxid )
4380
4377
{
4381
4378
expr -> expr_simple_state = ExecPrepareExpr (expr -> expr_simple_expr ,
4382
- estate -> eval_estate );
4383
- expr -> expr_simple_id = estate -> eval_estate_simple_id ;
4379
+ simple_eval_estate );
4380
+ expr -> expr_simple_lxid = curlxid ;
4384
4381
}
4385
4382
4386
4383
/*
@@ -5103,7 +5100,7 @@ exec_simple_check_plan(PLpgSQL_expr *expr)
5103
5100
*/
5104
5101
expr -> expr_simple_expr = tle -> expr ;
5105
5102
expr -> expr_simple_state = NULL ;
5106
- expr -> expr_simple_id = -1 ;
5103
+ expr -> expr_simple_lxid = InvalidLocalTransactionId ;
5107
5104
/* Also stash away the expression result type */
5108
5105
expr -> expr_simple_type = exprType ((Node * ) tle -> expr );
5109
5106
}
@@ -5165,46 +5162,69 @@ exec_set_found(PLpgSQL_execstate *estate, bool state)
5165
5162
/*
5166
5163
* plpgsql_create_econtext --- create an eval_econtext for the current function
5167
5164
*
5168
- * We may need to create a new eval_estate too, if there's not one already
5169
- * for the current (sub) transaction. The EState will be cleaned up at
5170
- * (sub) transaction end.
5165
+ * We may need to create a new simple_eval_estate too, if there's not one
5166
+ * already for the current transaction. The EState will be cleaned up at
5167
+ * transaction end.
5171
5168
*/
5172
5169
static void
5173
5170
plpgsql_create_econtext (PLpgSQL_execstate * estate )
5174
5171
{
5175
- SubTransactionId my_subxid = GetCurrentSubTransactionId ();
5176
- SimpleEstateStackEntry * entry = simple_estate_stack ;
5172
+ SimpleEcontextStackEntry * entry ;
5177
5173
5178
- /* Create new EState if not one for current subxact */
5179
- if (entry == NULL ||
5180
- entry -> xact_subxid != my_subxid )
5174
+ /*
5175
+ * Create an EState for evaluation of simple expressions, if there's not
5176
+ * one already in the current transaction. The EState is made a child of
5177
+ * TopTransactionContext so it will have the right lifespan.
5178
+ */
5179
+ if (simple_eval_estate == NULL )
5181
5180
{
5182
5181
MemoryContext oldcontext ;
5183
5182
5184
- /* Stack entries are kept in TopTransactionContext for simplicity */
5185
- entry = (SimpleEstateStackEntry * )
5186
- MemoryContextAlloc (TopTransactionContext ,
5187
- sizeof (SimpleEstateStackEntry ));
5188
-
5189
- /* But each EState should be a child of its CurTransactionContext */
5190
- oldcontext = MemoryContextSwitchTo (CurTransactionContext );
5191
- entry -> xact_eval_estate = CreateExecutorState ();
5183
+ oldcontext = MemoryContextSwitchTo (TopTransactionContext );
5184
+ simple_eval_estate = CreateExecutorState ();
5192
5185
MemoryContextSwitchTo (oldcontext );
5186
+ }
5193
5187
5194
- /* Assign a reasonably-unique ID to this EState */
5195
- entry -> xact_estate_simple_id = simple_estate_id_counter ++ ;
5196
- entry -> xact_subxid = my_subxid ;
5188
+ /*
5189
+ * Create a child econtext for the current function.
5190
+ */
5191
+ estate -> eval_econtext = CreateExprContext (simple_eval_estate );
5197
5192
5198
- entry -> next = simple_estate_stack ;
5199
- simple_estate_stack = entry ;
5200
- }
5193
+ /*
5194
+ * Make a stack entry so we can clean up the econtext at subxact end.
5195
+ * Stack entries are kept in TopTransactionContext for simplicity.
5196
+ */
5197
+ entry = (SimpleEcontextStackEntry * )
5198
+ MemoryContextAlloc (TopTransactionContext ,
5199
+ sizeof (SimpleEcontextStackEntry ));
5201
5200
5202
- /* Link plpgsql estate to it */
5203
- estate -> eval_estate = entry -> xact_eval_estate ;
5204
- estate -> eval_estate_simple_id = entry -> xact_estate_simple_id ;
5201
+ entry -> stack_econtext = estate -> eval_econtext ;
5202
+ entry -> xact_subxid = GetCurrentSubTransactionId ();
5205
5203
5206
- /* And create a child econtext for the current function */
5207
- estate -> eval_econtext = CreateExprContext (estate -> eval_estate );
5204
+ entry -> next = simple_econtext_stack ;
5205
+ simple_econtext_stack = entry ;
5206
+ }
5207
+
5208
+ /*
5209
+ * plpgsql_destroy_econtext --- destroy function's econtext
5210
+ *
5211
+ * We check that it matches the top stack entry, and destroy the stack
5212
+ * entry along with the context.
5213
+ */
5214
+ static void
5215
+ plpgsql_destroy_econtext (PLpgSQL_execstate * estate )
5216
+ {
5217
+ SimpleEcontextStackEntry * next ;
5218
+
5219
+ Assert (simple_econtext_stack != NULL );
5220
+ Assert (simple_econtext_stack -> stack_econtext == estate -> eval_econtext );
5221
+
5222
+ next = simple_econtext_stack -> next ;
5223
+ pfree (simple_econtext_stack );
5224
+ simple_econtext_stack = next ;
5225
+
5226
+ FreeExprContext (estate -> eval_econtext );
5227
+ estate -> eval_econtext = NULL ;
5208
5228
}
5209
5229
5210
5230
/*
@@ -5220,29 +5240,31 @@ plpgsql_xact_cb(XactEvent event, void *arg)
5220
5240
* If we are doing a clean transaction shutdown, free the EState (so that
5221
5241
* any remaining resources will be released correctly). In an abort, we
5222
5242
* expect the regular abort recovery procedures to release everything of
5223
- * interest. We don't need to free the individual stack entries since
5224
- * TopTransactionContext is about to go away anyway.
5225
- *
5226
- * Note: if plpgsql_subxact_cb is doing its job, there should be at most
5227
- * one stack entry, but we may as well code this as a loop.
5243
+ * interest.
5228
5244
*/
5229
5245
if (event != XACT_EVENT_ABORT )
5230
5246
{
5231
- while (simple_estate_stack != NULL )
5232
- {
5233
- FreeExecutorState (simple_estate_stack -> xact_eval_estate );
5234
- simple_estate_stack = simple_estate_stack -> next ;
5235
- }
5247
+ /* Shouldn't be any econtext stack entries left at commit */
5248
+ Assert (simple_econtext_stack == NULL );
5249
+
5250
+ if (simple_eval_estate )
5251
+ FreeExecutorState (simple_eval_estate );
5252
+ simple_eval_estate = NULL ;
5236
5253
}
5237
5254
else
5238
- simple_estate_stack = NULL ;
5255
+ {
5256
+ simple_econtext_stack = NULL ;
5257
+ simple_eval_estate = NULL ;
5258
+ }
5239
5259
}
5240
5260
5241
5261
/*
5242
5262
* plpgsql_subxact_cb --- post-subtransaction-commit-or-abort cleanup
5243
5263
*
5244
- * If a simple-expression EState was created in the current subtransaction,
5245
- * it has to be cleaned up.
5264
+ * Make sure any simple-expression econtexts created in the current
5265
+ * subtransaction get cleaned up. We have to do this explicitly because
5266
+ * no other code knows which child econtexts of simple_eval_estate belong
5267
+ * to which level of subxact.
5246
5268
*/
5247
5269
void
5248
5270
plpgsql_subxact_cb (SubXactEvent event , SubTransactionId mySubid ,
@@ -5251,16 +5273,15 @@ plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid,
5251
5273
if (event == SUBXACT_EVENT_START_SUB )
5252
5274
return ;
5253
5275
5254
- if ( simple_estate_stack != NULL &&
5255
- simple_estate_stack -> xact_subxid == mySubid )
5276
+ while ( simple_econtext_stack != NULL &&
5277
+ simple_econtext_stack -> xact_subxid == mySubid )
5256
5278
{
5257
- SimpleEstateStackEntry * next ;
5279
+ SimpleEcontextStackEntry * next ;
5258
5280
5259
- if (event == SUBXACT_EVENT_COMMIT_SUB )
5260
- FreeExecutorState (simple_estate_stack -> xact_eval_estate );
5261
- next = simple_estate_stack -> next ;
5262
- pfree (simple_estate_stack );
5263
- simple_estate_stack = next ;
5281
+ FreeExprContext (simple_econtext_stack -> stack_econtext );
5282
+ next = simple_econtext_stack -> next ;
5283
+ pfree (simple_econtext_stack );
5284
+ simple_econtext_stack = next ;
5264
5285
}
5265
5286
}
5266
5287
0 commit comments