@@ -235,7 +235,8 @@ static HTAB *shared_cast_hash = NULL;
235
235
static void coerce_function_result_tuple (PLpgSQL_execstate * estate ,
236
236
TupleDesc tupdesc );
237
237
static void plpgsql_exec_error_callback (void * arg );
238
- static PLpgSQL_datum * copy_plpgsql_datum (PLpgSQL_datum * datum );
238
+ static void copy_plpgsql_datums (PLpgSQL_execstate * estate ,
239
+ PLpgSQL_function * func );
239
240
static MemoryContext get_stmt_mcontext (PLpgSQL_execstate * estate );
240
241
static void push_stmt_mcontext (PLpgSQL_execstate * estate );
241
242
static void pop_stmt_mcontext (PLpgSQL_execstate * estate );
@@ -458,8 +459,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
458
459
* Make local execution copies of all the datums
459
460
*/
460
461
estate .err_text = gettext_noop ("during initialization of execution state" );
461
- for (i = 0 ; i < estate .ndatums ; i ++ )
462
- estate .datums [i ] = copy_plpgsql_datum (func -> datums [i ]);
462
+ copy_plpgsql_datums (& estate , func );
463
463
464
464
/*
465
465
* Store the actual call argument values into the appropriate variables
@@ -859,8 +859,7 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
859
859
* Make local execution copies of all the datums
860
860
*/
861
861
estate .err_text = gettext_noop ("during initialization of execution state" );
862
- for (i = 0 ; i < estate .ndatums ; i ++ )
863
- estate .datums [i ] = copy_plpgsql_datum (func -> datums [i ]);
862
+ copy_plpgsql_datums (& estate , func );
864
863
865
864
/*
866
865
* Put the OLD and NEW tuples into record variables
@@ -1153,7 +1152,6 @@ plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
1153
1152
{
1154
1153
PLpgSQL_execstate estate ;
1155
1154
ErrorContextCallback plerrcontext ;
1156
- int i ;
1157
1155
int rc ;
1158
1156
PLpgSQL_var * var ;
1159
1157
@@ -1174,8 +1172,7 @@ plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
1174
1172
* Make local execution copies of all the datums
1175
1173
*/
1176
1174
estate .err_text = gettext_noop ("during initialization of execution state" );
1177
- for (i = 0 ; i < estate .ndatums ; i ++ )
1178
- estate .datums [i ] = copy_plpgsql_datum (func -> datums [i ]);
1175
+ copy_plpgsql_datums (& estate , func );
1179
1176
1180
1177
/*
1181
1178
* Assign the special tg_ variables
@@ -1290,57 +1287,73 @@ plpgsql_exec_error_callback(void *arg)
1290
1287
* Support function for initializing local execution variables
1291
1288
* ----------
1292
1289
*/
1293
- static PLpgSQL_datum *
1294
- copy_plpgsql_datum (PLpgSQL_datum * datum )
1290
+ static void
1291
+ copy_plpgsql_datums (PLpgSQL_execstate * estate ,
1292
+ PLpgSQL_function * func )
1295
1293
{
1296
- PLpgSQL_datum * result ;
1294
+ int ndatums = estate -> ndatums ;
1295
+ PLpgSQL_datum * * indatums ;
1296
+ PLpgSQL_datum * * outdatums ;
1297
+ char * workspace ;
1298
+ char * ws_next ;
1299
+ int i ;
1297
1300
1298
- switch (datum -> dtype )
1299
- {
1300
- case PLPGSQL_DTYPE_VAR :
1301
- {
1302
- PLpgSQL_var * new = palloc (sizeof (PLpgSQL_var ));
1301
+ /* Allocate local datum-pointer array */
1302
+ estate -> datums = (PLpgSQL_datum * * )
1303
+ palloc (sizeof (PLpgSQL_datum * ) * ndatums );
1303
1304
1304
- memcpy (new , datum , sizeof (PLpgSQL_var ));
1305
- /* should be preset to null/non-freeable */
1306
- Assert (new -> isnull );
1307
- Assert (!new -> freeval );
1305
+ /*
1306
+ * To reduce palloc overhead, we make a single palloc request for all the
1307
+ * space needed for locally-instantiated datums.
1308
+ */
1309
+ workspace = palloc (func -> copiable_size );
1310
+ ws_next = workspace ;
1308
1311
1309
- result = (PLpgSQL_datum * ) new ;
1310
- }
1311
- break ;
1312
+ /* Fill datum-pointer array, copying datums into workspace as needed */
1313
+ indatums = func -> datums ;
1314
+ outdatums = estate -> datums ;
1315
+ for (i = 0 ; i < ndatums ; i ++ )
1316
+ {
1317
+ PLpgSQL_datum * indatum = indatums [i ];
1318
+ PLpgSQL_datum * outdatum ;
1312
1319
1313
- case PLPGSQL_DTYPE_REC :
1314
- {
1315
- PLpgSQL_rec * new = palloc (sizeof (PLpgSQL_rec ));
1320
+ /* This must agree with plpgsql_finish_datums on what is copiable */
1321
+ switch (indatum -> dtype )
1322
+ {
1323
+ case PLPGSQL_DTYPE_VAR :
1324
+ outdatum = (PLpgSQL_datum * ) ws_next ;
1325
+ memcpy (outdatum , indatum , sizeof (PLpgSQL_var ));
1326
+ ws_next += MAXALIGN (sizeof (PLpgSQL_var ));
1327
+ break ;
1316
1328
1317
- memcpy (new , datum , sizeof (PLpgSQL_rec ));
1318
- /* should be preset to empty */
1319
- Assert (new -> erh == NULL );
1329
+ case PLPGSQL_DTYPE_REC :
1330
+ outdatum = (PLpgSQL_datum * ) ws_next ;
1331
+ memcpy (outdatum , indatum , sizeof (PLpgSQL_rec ));
1332
+ ws_next += MAXALIGN (sizeof (PLpgSQL_rec ));
1333
+ break ;
1320
1334
1321
- result = ( PLpgSQL_datum * ) new ;
1322
- }
1323
- break ;
1335
+ case PLPGSQL_DTYPE_ROW :
1336
+ case PLPGSQL_DTYPE_RECFIELD :
1337
+ case PLPGSQL_DTYPE_ARRAYELEM :
1324
1338
1325
- case PLPGSQL_DTYPE_ROW :
1326
- case PLPGSQL_DTYPE_RECFIELD :
1327
- case PLPGSQL_DTYPE_ARRAYELEM :
1339
+ /*
1340
+ * These datum records are read-only at runtime, so no need to
1341
+ * copy them (well, RECFIELD and ARRAYELEM contain cached
1342
+ * data, but we'd just as soon centralize the caching anyway).
1343
+ */
1344
+ outdatum = indatum ;
1345
+ break ;
1328
1346
1329
- /*
1330
- * These datum records are read-only at runtime, so no need to
1331
- * copy them (well, RECFIELD and ARRAYELEM contain cached data,
1332
- * but we'd just as soon centralize the caching anyway)
1333
- */
1334
- result = datum ;
1335
- break ;
1347
+ default :
1348
+ elog (ERROR , "unrecognized dtype: %d" , indatum -> dtype );
1349
+ outdatum = NULL ; /* keep compiler quiet */
1350
+ break ;
1351
+ }
1336
1352
1337
- default :
1338
- elog (ERROR , "unrecognized dtype: %d" , datum -> dtype );
1339
- result = NULL ; /* keep compiler quiet */
1340
- break ;
1353
+ outdatums [i ] = outdatum ;
1341
1354
}
1342
1355
1343
- return result ;
1356
+ Assert ( ws_next == workspace + func -> copiable_size ) ;
1344
1357
}
1345
1358
1346
1359
/*
@@ -3504,8 +3517,8 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
3504
3517
3505
3518
estate -> found_varno = func -> found_varno ;
3506
3519
estate -> ndatums = func -> ndatums ;
3507
- estate -> datums = palloc ( sizeof ( PLpgSQL_datum * ) * estate -> ndatums ) ;
3508
- /* caller is expected to fill the datums array */
3520
+ estate -> datums = NULL ;
3521
+ /* the datums array will be filled by copy_plpgsql_datums() */
3509
3522
estate -> datum_context = CurrentMemoryContext ;
3510
3523
3511
3524
/* initialize our ParamListInfo with appropriate hook functions */
0 commit comments