@@ -98,6 +98,10 @@ static SimpleEcontextStackEntry *simple_econtext_stack = NULL;
98
98
*
99
99
* The evaluation state trees (cast_exprstate) are managed in the same way as
100
100
* simple expressions (i.e., we assume cast expressions are always simple).
101
+ *
102
+ * As with simple expressions, DO blocks don't use the shared hash table but
103
+ * must have their own. This isn't ideal, but we don't want to deal with
104
+ * multiple simple_eval_estates within a DO block.
101
105
*/
102
106
typedef struct /* lookup key for cast info */
103
107
{
@@ -118,8 +122,8 @@ typedef struct /* cast_hash table entry */
118
122
LocalTransactionId cast_lxid ;
119
123
} plpgsql_CastHashEntry ;
120
124
121
- static MemoryContext cast_hash_context = NULL ;
122
- static HTAB * cast_hash = NULL ;
125
+ static MemoryContext shared_cast_context = NULL ;
126
+ static HTAB * shared_cast_hash = NULL ;
123
127
124
128
/************************************************************
125
129
* Local function forward declarations
@@ -283,7 +287,9 @@ static char *format_preparedparamsdata(PLpgSQL_execstate *estate,
283
287
* difference that this code is aware of is that for a DO block, we want
284
288
* to use a private simple_eval_estate, which is created and passed in by
285
289
* the caller. For regular functions, pass NULL, which implies using
286
- * shared_simple_eval_estate.
290
+ * shared_simple_eval_estate. (When using a private simple_eval_estate,
291
+ * we must also use a private cast hashtable, but that's taken care of
292
+ * within plpgsql_estate_setup.)
287
293
* ----------
288
294
*/
289
295
Datum
@@ -3286,6 +3292,8 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
3286
3292
ReturnSetInfo * rsi ,
3287
3293
EState * simple_eval_estate )
3288
3294
{
3295
+ HASHCTL ctl ;
3296
+
3289
3297
/* this link will be restored at exit from plpgsql_call_handler */
3290
3298
func -> cur_estate = estate ;
3291
3299
@@ -3333,11 +3341,44 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
3333
3341
estate -> paramLI -> parserSetupArg = NULL ; /* filled during use */
3334
3342
estate -> paramLI -> numParams = estate -> ndatums ;
3335
3343
3336
- /* set up for use of appropriate simple-expression EState */
3344
+ /* set up for use of appropriate simple-expression EState and cast hash */
3337
3345
if (simple_eval_estate )
3346
+ {
3338
3347
estate -> simple_eval_estate = simple_eval_estate ;
3348
+ /* Private cast hash just lives in function's main context */
3349
+ memset (& ctl , 0 , sizeof (ctl ));
3350
+ ctl .keysize = sizeof (plpgsql_CastHashKey );
3351
+ ctl .entrysize = sizeof (plpgsql_CastHashEntry );
3352
+ ctl .hcxt = CurrentMemoryContext ;
3353
+ estate -> cast_hash = hash_create ("PLpgSQL private cast cache" ,
3354
+ 16 , /* start small and extend */
3355
+ & ctl ,
3356
+ HASH_ELEM | HASH_BLOBS | HASH_CONTEXT );
3357
+ estate -> cast_hash_context = CurrentMemoryContext ;
3358
+ }
3339
3359
else
3360
+ {
3340
3361
estate -> simple_eval_estate = shared_simple_eval_estate ;
3362
+ /* Create the session-wide cast-info hash table if we didn't already */
3363
+ if (shared_cast_hash == NULL )
3364
+ {
3365
+ shared_cast_context = AllocSetContextCreate (TopMemoryContext ,
3366
+ "PLpgSQL cast info" ,
3367
+ ALLOCSET_DEFAULT_MINSIZE ,
3368
+ ALLOCSET_DEFAULT_INITSIZE ,
3369
+ ALLOCSET_DEFAULT_MAXSIZE );
3370
+ memset (& ctl , 0 , sizeof (ctl ));
3371
+ ctl .keysize = sizeof (plpgsql_CastHashKey );
3372
+ ctl .entrysize = sizeof (plpgsql_CastHashEntry );
3373
+ ctl .hcxt = shared_cast_context ;
3374
+ shared_cast_hash = hash_create ("PLpgSQL cast cache" ,
3375
+ 16 , /* start small and extend */
3376
+ & ctl ,
3377
+ HASH_ELEM | HASH_BLOBS | HASH_CONTEXT );
3378
+ }
3379
+ estate -> cast_hash = shared_cast_hash ;
3380
+ estate -> cast_hash_context = shared_cast_context ;
3381
+ }
3341
3382
3342
3383
estate -> eval_tuptable = NULL ;
3343
3384
estate -> eval_processed = 0 ;
@@ -6014,32 +6055,12 @@ get_cast_hashentry(PLpgSQL_execstate *estate,
6014
6055
LocalTransactionId curlxid ;
6015
6056
MemoryContext oldcontext ;
6016
6057
6017
- /* Create the session-wide cast-info hash table if we didn't already */
6018
- if (cast_hash == NULL )
6019
- {
6020
- HASHCTL ctl ;
6021
-
6022
- cast_hash_context = AllocSetContextCreate (TopMemoryContext ,
6023
- "PLpgSQL cast info" ,
6024
- ALLOCSET_DEFAULT_MINSIZE ,
6025
- ALLOCSET_DEFAULT_INITSIZE ,
6026
- ALLOCSET_DEFAULT_MAXSIZE );
6027
- memset (& ctl , 0 , sizeof (ctl ));
6028
- ctl .keysize = sizeof (plpgsql_CastHashKey );
6029
- ctl .entrysize = sizeof (plpgsql_CastHashEntry );
6030
- ctl .hcxt = cast_hash_context ;
6031
- cast_hash = hash_create ("PLpgSQL cast cache" ,
6032
- 16 , /* start small and extend */
6033
- & ctl ,
6034
- HASH_ELEM | HASH_BLOBS | HASH_CONTEXT );
6035
- }
6036
-
6037
6058
/* Look for existing entry */
6038
6059
cast_key .srctype = srctype ;
6039
6060
cast_key .dsttype = dsttype ;
6040
6061
cast_key .srctypmod = srctypmod ;
6041
6062
cast_key .dsttypmod = dsttypmod ;
6042
- cast_entry = (plpgsql_CastHashEntry * ) hash_search (cast_hash ,
6063
+ cast_entry = (plpgsql_CastHashEntry * ) hash_search (estate -> cast_hash ,
6043
6064
(void * ) & cast_key ,
6044
6065
HASH_FIND , NULL );
6045
6066
@@ -6124,15 +6145,15 @@ get_cast_hashentry(PLpgSQL_execstate *estate,
6124
6145
cast_expr = (Node * ) expression_planner ((Expr * ) cast_expr );
6125
6146
6126
6147
/* Now copy the tree into cast_hash_context */
6127
- MemoryContextSwitchTo (cast_hash_context );
6148
+ MemoryContextSwitchTo (estate -> cast_hash_context );
6128
6149
6129
6150
cast_expr = copyObject (cast_expr );
6130
6151
}
6131
6152
6132
6153
MemoryContextSwitchTo (oldcontext );
6133
6154
6134
6155
/* Now we can fill in a hashtable entry. */
6135
- cast_entry = (plpgsql_CastHashEntry * ) hash_search (cast_hash ,
6156
+ cast_entry = (plpgsql_CastHashEntry * ) hash_search (estate -> cast_hash ,
6136
6157
(void * ) & cast_key ,
6137
6158
HASH_ENTER , & found );
6138
6159
Assert (!found ); /* wasn't there a moment ago */
@@ -6154,7 +6175,9 @@ get_cast_hashentry(PLpgSQL_execstate *estate,
6154
6175
* executions. (We will leak some memory intra-transaction if that
6155
6176
* happens a lot, but we don't expect it to.) It's okay to update the
6156
6177
* hash table with the new tree because all plpgsql functions within a
6157
- * given transaction share the same simple_eval_estate.
6178
+ * given transaction share the same simple_eval_estate. (Well, regular
6179
+ * functions do; DO blocks have private simple_eval_estates, and private
6180
+ * cast hash tables to go with them.)
6158
6181
*/
6159
6182
curlxid = MyProc -> lxid ;
6160
6183
if (cast_entry -> cast_lxid != curlxid || cast_entry -> cast_in_use )
0 commit comments