From c7fa0b3cc32c408366c3bb807a660389a7125b17 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Mon, 28 Feb 2022 16:35:08 +0900 Subject: [PATCH v9 2/2] Introduce more simplifications in MakeFuncResultTuplestore() This doubles the amount of code cut compared to the first patch, adding more SRF-related logic into a central function. --- src/include/funcapi.h | 7 +- src/backend/access/transam/xlogfuncs.c | 17 +--- src/backend/commands/event_trigger.c | 34 ++------ src/backend/commands/extension.c | 51 ++--------- src/backend/commands/prepare.c | 19 +--- src/backend/foreign/foreign.c | 22 +---- src/backend/libpq/hba.c | 23 ++--- src/backend/replication/logical/launcher.c | 17 +--- .../replication/logical/logicalfuncs.c | 7 +- src/backend/replication/logical/origin.c | 21 +---- src/backend/replication/slotfuncs.c | 17 +--- src/backend/replication/walsender.c | 17 +--- src/backend/storage/ipc/shmem.c | 21 ++--- src/backend/utils/adt/datetime.c | 15 +--- src/backend/utils/adt/genfile.c | 34 ++------ src/backend/utils/adt/jsonfuncs.c | 86 +++---------------- src/backend/utils/adt/mcxtfuncs.c | 17 +--- src/backend/utils/adt/misc.c | 21 +---- src/backend/utils/adt/pgstatfuncs.c | 49 ++--------- src/backend/utils/adt/varlena.c | 15 +--- src/backend/utils/fmgr/funcapi.c | 47 +++++++--- src/backend/utils/misc/guc.c | 18 +--- src/backend/utils/misc/pg_config.c | 18 +--- src/backend/utils/mmgr/portalmem.c | 22 +---- 24 files changed, 129 insertions(+), 486 deletions(-) diff --git a/src/include/funcapi.h b/src/include/funcapi.h index b9f9e92d1a..11491a7c33 100644 --- a/src/include/funcapi.h +++ b/src/include/funcapi.h @@ -229,8 +229,11 @@ extern TupleDesc BlessTupleDesc(TupleDesc tupdesc); extern AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc); extern HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values); extern Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple); -extern Tuplestorestate *MakeFuncResultTuplestore(FunctionCallInfo fcinfo, - TupleDesc *result_tupdesc); + +/* flag bits for MakeFuncResultTuplestore() */ +#define TUPSTORE_SRF_USE_EXPECTED 0x01 /* use expectedDesc as tupdesc */ +#define TUPSTORE_SRF_BLESS 0x02 /* validate tuple for SRF */ +extern void MakeFuncResultTuplestore(FunctionCallInfo fcinfo, bits32 flags); /*---------- diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index 2fc1ed023c..60c24b2bf3 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -166,10 +166,6 @@ Datum pg_stop_backup_v2(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; Datum values[3]; bool nulls[3]; @@ -178,15 +174,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS) XLogRecPtr stoppoint; SessionBackupState status = get_backup_status(); - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); MemSet(values, 0, sizeof(values)); MemSet(nulls, 0, sizeof(nulls)); @@ -237,7 +225,8 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS) /* Stoppoint is included on both exclusive and nonexclusive backups */ values[0] = LSNGetDatum(stoppoint); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); return (Datum) 0; } diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 68cad0a580..58a6415b9e 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -1290,10 +1290,6 @@ Datum pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; slist_iter iter; /* @@ -1307,15 +1303,7 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS) "pg_event_trigger_dropped_objects()"))); /* Build tuplestore to hold the result rows */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); slist_foreach(iter, &(currentEventTriggerState->SQLDropList)) { @@ -1384,7 +1372,8 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS) nulls[i++] = true; } - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } return (Datum) 0; @@ -1832,10 +1821,6 @@ Datum pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; ListCell *lc; /* @@ -1848,15 +1833,7 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS) "pg_event_trigger_ddl_commands()"))); /* Build tuplestore to hold the result rows */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); foreach(lc, currentEventTriggerState->commandList) { @@ -2027,7 +2004,8 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS) break; } - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } PG_RETURN_VOID(); diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index a30e91b328..43a62ce8e0 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1932,24 +1932,12 @@ Datum pg_available_extensions(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; char *location; DIR *dir; struct dirent *de; /* Build tuplestore to hold the result rows */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); location = get_extension_control_directory(); dir = AllocateDir(location); @@ -2001,7 +1989,8 @@ pg_available_extensions(PG_FUNCTION_ARGS) else values[2] = CStringGetTextDatum(control->comment); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } FreeDir(dir); @@ -2023,24 +2012,12 @@ Datum pg_available_extension_versions(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; char *location; DIR *dir; struct dirent *de; /* Build tuplestore to hold the result rows */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); location = get_extension_control_directory(); dir = AllocateDir(location); @@ -2075,7 +2052,8 @@ pg_available_extension_versions(PG_FUNCTION_ARGS) control = read_extension_control_file(extname); /* scan extension's script directory for install scripts */ - get_available_versions_for_extension(control, tupstore, tupdesc); + get_available_versions_for_extension(control, rsinfo->setResult, + rsinfo->setDesc); } FreeDir(dir); @@ -2288,10 +2266,6 @@ pg_extension_update_paths(PG_FUNCTION_ARGS) { Name extname = PG_GETARG_NAME(0); ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; List *evi_list; ExtensionControlFile *control; ListCell *lc1; @@ -2300,15 +2274,7 @@ pg_extension_update_paths(PG_FUNCTION_ARGS) check_valid_extension_name(NameStr(*extname)); /* Build tuplestore to hold the result rows */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); /* Read the extension's control file */ control = read_extension_control_file(NameStr(*extname)); @@ -2365,7 +2331,8 @@ pg_extension_update_paths(PG_FUNCTION_ARGS) pfree(pathbuf.data); } - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } } diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index 040711ee75..5fc04f31ff 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -702,26 +702,12 @@ Datum pg_prepared_statement(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - - /* need to build tuplestore in query context */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); /* * We put all the tuples into a tuplestore in one scan of the hashtable. * This avoids any issue of the hashtable possibly changing between calls. */ - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - /* generate junk in short-term context */ - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); /* hash table might be uninitialized */ if (prepared_queries) @@ -746,7 +732,8 @@ pg_prepared_statement(PG_FUNCTION_ARGS) values[5] = Int64GetDatumFast(prep_stmt->plansource->num_generic_plans); values[6] = Int64GetDatumFast(prep_stmt->plansource->num_custom_plans); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } } diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index 1f86340cc8..a5d2e28f40 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -511,27 +511,12 @@ pg_options_to_table(PG_FUNCTION_ARGS) ListCell *cell; List *options; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; options = untransformRelOptions(array); rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - /* - * Now prepare the result set. - */ - tupstore = MakeFuncResultTuplestore(fcinfo, NULL); - tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + /* prepare the result set */ + MakeFuncResultTuplestore(fcinfo, TUPSTORE_SRF_USE_EXPECTED); foreach(cell, options) { @@ -551,7 +536,8 @@ pg_options_to_table(PG_FUNCTION_ARGS) values[1] = (Datum) 0; nulls[1] = true; } - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } return (Datum) 0; diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 02d43eb22e..b179c4e66d 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -2703,30 +2703,19 @@ fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc) Datum pg_hba_file_rules(PG_FUNCTION_ARGS) { - Tuplestorestate *tuple_store; - TupleDesc tupdesc; - MemoryContext old_cxt; ReturnSetInfo *rsi; /* - * We must use the Materialize mode to be safe against HBA file changes - * while the cursor is open. It's also more efficient than having to look + * Build tuplestore to hold the result rows. We must use the + * Materialize mode to be safe against HBA file changes while the + * cursor is open. It's also more efficient than having to look * up our current position in the parsed list every time. */ - rsi = (ReturnSetInfo *) fcinfo->resultinfo; - rsi->returnMode = SFRM_Materialize; - - /* Build tuplestore to hold the result rows */ - old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory); - - tuple_store = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsi->setDesc = tupdesc; - rsi->setResult = tuple_store; - - MemoryContextSwitchTo(old_cxt); + MakeFuncResultTuplestore(fcinfo, 0); /* Fill the tuplestore */ - fill_hba_view(tuple_store, tupdesc); + rsi = (ReturnSetInfo *) fcinfo->resultinfo; + fill_hba_view(rsi->setResult, rsi->setDesc); PG_RETURN_NULL(); } diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c index a1054edada..ba5df518be 100644 --- a/src/backend/replication/logical/launcher.c +++ b/src/backend/replication/logical/launcher.c @@ -930,20 +930,8 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS) Oid subid = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); int i; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); /* Make sure we get consistent view of the workers. */ LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); @@ -996,7 +984,8 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS) else values[7] = TimestampTzGetDatum(worker.reply_time); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); /* * If only a single subscription was requested, and we found it, diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c index b7d056653b..c95b115437 100644 --- a/src/backend/replication/logical/logicalfuncs.c +++ b/src/backend/replication/logical/logicalfuncs.c @@ -189,10 +189,9 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin } } - p->tupstore = MakeFuncResultTuplestore(fcinfo, &p->tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = p->tupstore; - rsinfo->setDesc = p->tupdesc; + MakeFuncResultTuplestore(fcinfo, 0); + p->tupstore = rsinfo->setResult; + p->tupdesc = rsinfo->setDesc; /* * Compute the current end-of-wal. diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c index 4edc4300a8..17faeb6f22 100644 --- a/src/backend/replication/logical/origin.c +++ b/src/backend/replication/logical/origin.c @@ -1482,29 +1482,13 @@ Datum pg_show_replication_origin_status(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; int i; #define REPLICATION_ORIGIN_PROGRESS_COLS 4 /* we want to return 0 rows if slot is set to zero */ replorigin_check_prerequisites(false, true); - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); - - if (tupdesc->natts != REPLICATION_ORIGIN_PROGRESS_COLS) - elog(ERROR, "wrong function definition"); + MakeFuncResultTuplestore(fcinfo, 0); /* prevent slots from being concurrently dropped */ LWLockAcquire(ReplicationOriginLock, LW_SHARED); @@ -1554,7 +1538,8 @@ pg_show_replication_origin_status(PG_FUNCTION_ARGS) LWLockRelease(&state->lock); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } LWLockRelease(ReplicationOriginLock); diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c index 3e9db7714e..f366e5e934 100644 --- a/src/backend/replication/slotfuncs.c +++ b/src/backend/replication/slotfuncs.c @@ -233,10 +233,6 @@ pg_get_replication_slots(PG_FUNCTION_ARGS) { #define PG_GET_REPLICATION_SLOTS_COLS 14 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; XLogRecPtr currlsn; int slotno; @@ -246,15 +242,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS) * name, which shouldn't contain anything particularly sensitive. */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); currlsn = GetXLogWriteRecPtr(); @@ -417,7 +405,8 @@ pg_get_replication_slots(PG_FUNCTION_ARGS) Assert(i == PG_GET_REPLICATION_SLOTS_COLS); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } LWLockRelease(ReplicationSlotControlLock); diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 79e32f7ecf..71d56691b1 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -3403,23 +3403,11 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS) { #define PG_STAT_GET_WAL_SENDERS_COLS 12 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; SyncRepStandbyData *sync_standbys; int num_standbys; int i; - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); /* * Get the currently active synchronous standbys. This could be out of @@ -3563,7 +3551,8 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS) values[11] = TimestampTzGetDatum(replyTime); } - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } return (Datum) 0; diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index 02cdda7a73..2bc7495ec3 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -537,25 +537,13 @@ pg_get_shmem_allocations(PG_FUNCTION_ARGS) { #define PG_GET_SHMEM_SIZES_COLS 4 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; HASH_SEQ_STATUS hstat; ShmemIndexEnt *ent; Size named_allocated = 0; Datum values[PG_GET_SHMEM_SIZES_COLS]; bool nulls[PG_GET_SHMEM_SIZES_COLS]; - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); LWLockAcquire(ShmemIndexLock, LW_SHARED); @@ -571,7 +559,8 @@ pg_get_shmem_allocations(PG_FUNCTION_ARGS) values[3] = Int64GetDatum(ent->allocated_size); named_allocated += ent->allocated_size; - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } /* output shared memory allocated but not counted via the shmem index */ @@ -579,7 +568,7 @@ pg_get_shmem_allocations(PG_FUNCTION_ARGS) nulls[1] = true; values[2] = Int64GetDatum(ShmemSegHdr->freeoffset - named_allocated); values[3] = values[2]; - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); /* output as-of-yet unused shared memory */ nulls[0] = true; @@ -587,7 +576,7 @@ pg_get_shmem_allocations(PG_FUNCTION_ARGS) nulls[1] = false; values[2] = Int64GetDatum(ShmemSegHdr->totalsize - ShmemSegHdr->freeoffset); values[3] = values[2]; - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); LWLockRelease(ShmemIndexLock); diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 6467f25895..1d1310aecb 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -4786,8 +4786,6 @@ Datum pg_timezone_names(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; pg_tzenum *tzenum; pg_tz *tz; Datum values[4]; @@ -4798,17 +4796,8 @@ pg_timezone_names(PG_FUNCTION_ARGS) const char *tzn; Interval *resInterval; struct pg_tm itm; - MemoryContext oldcontext; - /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */ - oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); /* initialize timezone scanning code */ tzenum = pg_tzenumerate_start(); @@ -4850,7 +4839,7 @@ pg_timezone_names(PG_FUNCTION_ARGS) values[3] = BoolGetDatum(tm.tm_isdst > 0); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); } pg_tzenumerate_end(tzenum); diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index 8678511c2a..c74017bc3e 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -477,11 +477,8 @@ pg_ls_dir(PG_FUNCTION_ARGS) char *location; bool missing_ok = false; bool include_dot_dirs = false; - TupleDesc tupdesc; - Tuplestorestate *tupstore; DIR *dirdesc; struct dirent *de; - MemoryContext oldcontext; location = convert_and_check_filename(PG_GETARG_TEXT_PP(0)); @@ -494,18 +491,7 @@ pg_ls_dir(PG_FUNCTION_ARGS) include_dot_dirs = PG_GETARG_BOOL(2); } - /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */ - oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - - tupdesc = CreateTemplateTupleDesc(1); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pg_ls_dir", TEXTOID, -1, 0); - - tupstore = MakeFuncResultTuplestore(fcinfo, NULL); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, TUPSTORE_SRF_USE_EXPECTED); dirdesc = AllocateDir(location); if (!dirdesc) @@ -529,7 +515,8 @@ pg_ls_dir(PG_FUNCTION_ARGS) values[0] = CStringGetTextDatum(de->d_name); nulls[0] = false; - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } FreeDir(dirdesc); @@ -559,21 +546,10 @@ static Datum pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; DIR *dirdesc; struct dirent *de; - MemoryContext oldcontext; - /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */ - oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); /* * Now walk the directory. Note that we must do this within a single SRF @@ -621,7 +597,7 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok) values[2] = TimestampTzGetDatum(time_t_to_timestamptz(attrib.st_mtime)); memset(nulls, 0, sizeof(nulls)); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); } FreeDir(dirdesc); diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index 6f5f2451fe..ca22f5b8c3 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -1909,9 +1909,6 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text) { Jsonb *jb = PG_GETARG_JSONB_P(0); ReturnSetInfo *rsi; - Tuplestorestate *tuple_store; - TupleDesc tupdesc; - TupleDesc ret_tdesc; MemoryContext old_cxt, tmp_cxt; bool skipNested = false; @@ -1926,17 +1923,7 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text) funcname))); rsi = (ReturnSetInfo *) fcinfo->resultinfo; - - rsi->returnMode = SFRM_Materialize; - - old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory); - - tuple_store = MakeFuncResultTuplestore(fcinfo, &tupdesc); - - ret_tdesc = CreateTupleDescCopy(tupdesc); - BlessTupleDesc(ret_tdesc); - - MemoryContextSwitchTo(old_cxt); + MakeFuncResultTuplestore(fcinfo, TUPSTORE_SRF_BLESS); tmp_cxt = AllocSetContextCreate(CurrentMemoryContext, "jsonb_each temporary cxt", @@ -1951,7 +1938,6 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text) if (r == WJB_KEY) { text *key; - HeapTuple tuple; Datum values[2]; bool nulls[2] = {false, false}; @@ -1988,9 +1974,7 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text) values[1] = PointerGetDatum(val); } - tuple = heap_form_tuple(ret_tdesc, values, nulls); - - tuplestore_puttuple(tuple_store, tuple); + tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls); /* clean up and switch back */ MemoryContextSwitchTo(old_cxt); @@ -2000,9 +1984,6 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text) MemoryContextDelete(tmp_cxt); - rsi->setResult = tuple_store; - rsi->setDesc = ret_tdesc; - PG_RETURN_NULL(); } @@ -2014,8 +1995,6 @@ each_worker(FunctionCallInfo fcinfo, bool as_text) JsonLexContext *lex; JsonSemAction *sem; ReturnSetInfo *rsi; - MemoryContext old_cxt; - TupleDesc tupdesc; EachState *state; lex = makeJsonLexContext(json, true); @@ -2024,17 +2003,9 @@ each_worker(FunctionCallInfo fcinfo, bool as_text) rsi = (ReturnSetInfo *) fcinfo->resultinfo; - rsi->returnMode = SFRM_Materialize; - - /* make these in a sufficiently long-lived memory context */ - old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory); - - state->tuple_store = MakeFuncResultTuplestore(fcinfo, &tupdesc); - - state->ret_tdesc = CreateTupleDescCopy(tupdesc); - BlessTupleDesc(state->ret_tdesc); - - MemoryContextSwitchTo(old_cxt); + MakeFuncResultTuplestore(fcinfo, TUPSTORE_SRF_BLESS); + state->tuple_store = rsi->setResult; + state->ret_tdesc = rsi->setDesc; sem->semstate = (void *) state; sem->array_start = each_array_start; @@ -2053,9 +2024,6 @@ each_worker(FunctionCallInfo fcinfo, bool as_text) MemoryContextDelete(state->tmp_cxt); - rsi->setResult = state->tuple_store; - rsi->setDesc = state->ret_tdesc; - PG_RETURN_NULL(); } @@ -2180,9 +2148,6 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, { Jsonb *jb = PG_GETARG_JSONB_P(0); ReturnSetInfo *rsi; - Tuplestorestate *tuple_store; - TupleDesc tupdesc; - TupleDesc ret_tdesc; MemoryContext old_cxt, tmp_cxt; bool skipNested = false; @@ -2201,16 +2166,8 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, rsi = (ReturnSetInfo *) fcinfo->resultinfo; - rsi->returnMode = SFRM_Materialize; - - old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory); - - tuple_store = MakeFuncResultTuplestore(fcinfo, NULL); - tupdesc = rsi->expectedDesc; - ret_tdesc = CreateTupleDescCopy(tupdesc); - BlessTupleDesc(ret_tdesc); - - MemoryContextSwitchTo(old_cxt); + MakeFuncResultTuplestore(fcinfo, + TUPSTORE_SRF_USE_EXPECTED | TUPSTORE_SRF_BLESS); tmp_cxt = AllocSetContextCreate(CurrentMemoryContext, "jsonb_array_elements temporary cxt", @@ -2224,7 +2181,6 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, if (r == WJB_ELEM) { - HeapTuple tuple; Datum values[1]; bool nulls[1] = {false}; @@ -2250,9 +2206,7 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, values[0] = PointerGetDatum(val); } - tuple = heap_form_tuple(ret_tdesc, values, nulls); - - tuplestore_puttuple(tuple_store, tuple); + tuplestore_putvalues(rsi->setResult, rsi->setDesc, values, nulls); /* clean up and switch back */ MemoryContextSwitchTo(old_cxt); @@ -2262,9 +2216,6 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, MemoryContextDelete(tmp_cxt); - rsi->setResult = tuple_store; - rsi->setDesc = ret_tdesc; - PG_RETURN_NULL(); } @@ -2289,27 +2240,15 @@ elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text) JsonLexContext *lex = makeJsonLexContext(json, as_text); JsonSemAction *sem; ReturnSetInfo *rsi; - MemoryContext old_cxt; - TupleDesc tupdesc; ElementsState *state; state = palloc0(sizeof(ElementsState)); sem = palloc0(sizeof(JsonSemAction)); + MakeFuncResultTuplestore(fcinfo, TUPSTORE_SRF_USE_EXPECTED | TUPSTORE_SRF_BLESS); rsi = (ReturnSetInfo *) fcinfo->resultinfo; - - rsi->returnMode = SFRM_Materialize; - - /* make these in a sufficiently long-lived memory context */ - old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory); - - state->tuple_store = MakeFuncResultTuplestore(fcinfo, NULL); - - tupdesc = rsi->expectedDesc; - state->ret_tdesc = CreateTupleDescCopy(tupdesc); - BlessTupleDesc(state->ret_tdesc); - - MemoryContextSwitchTo(old_cxt); + state->tuple_store = rsi->setResult; + state->ret_tdesc = rsi->setDesc; sem->semstate = (void *) state; sem->object_start = elements_object_start; @@ -2329,9 +2268,6 @@ elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text) MemoryContextDelete(state->tmp_cxt); - rsi->setResult = state->tuple_store; - rsi->setDesc = state->ret_tdesc; - PG_RETURN_NULL(); } diff --git a/src/backend/utils/adt/mcxtfuncs.c b/src/backend/utils/adt/mcxtfuncs.c index 9b89651808..3afd1edbab 100644 --- a/src/backend/utils/adt/mcxtfuncs.c +++ b/src/backend/utils/adt/mcxtfuncs.c @@ -120,22 +120,9 @@ Datum pg_get_backend_memory_contexts(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); - - PutMemoryContextsStatsTupleStore(tupstore, tupdesc, + MakeFuncResultTuplestore(fcinfo, 0); + PutMemoryContextsStatsTupleStore(rsinfo->setResult, rsinfo->setDesc, TopMemoryContext, NULL, 0); return (Datum) 0; diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index d946f679e5..e950fc898b 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -203,27 +203,11 @@ pg_tablespace_databases(PG_FUNCTION_ARGS) { Oid tablespaceOid = PG_GETARG_OID(0); ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; char *location; DIR *dirdesc; struct dirent *de; - MemoryContext oldcontext; - /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */ - oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - - tupdesc = CreateTemplateTupleDesc(1); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pg_tablespace_databases", - OIDOID, -1, 0); - - tupstore = MakeFuncResultTuplestore(fcinfo, NULL); - - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, TUPSTORE_SRF_USE_EXPECTED); if (tablespaceOid == GLOBALTABLESPACE_OID) { @@ -279,7 +263,8 @@ pg_tablespace_databases(PG_FUNCTION_ARGS) values[0] = ObjectIdGetDatum(datOid); nulls[0] = false; - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); } FreeDir(dirdesc); diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index abde31b854..9097cb64e9 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -461,11 +461,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS) int curr_backend; char *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0)); ProgressCommandType cmdtype; - TupleDesc tupdesc; - Tuplestorestate *tupstore; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - MemoryContext per_query_ctx; - MemoryContext oldcontext; /* Translate command name into command type code. */ if (pg_strcasecmp(cmd, "VACUUM") == 0) @@ -485,14 +481,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid command name: \"%s\"", cmd))); - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); /* 1-based index */ for (curr_backend = 1; curr_backend <= num_backends; curr_backend++) @@ -538,7 +527,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS) nulls[i + 3] = true; } - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); } return (Datum) 0; @@ -555,20 +544,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) int curr_backend; int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0); ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); /* 1-based index */ for (curr_backend = 1; curr_backend <= num_backends; curr_backend++) @@ -601,7 +578,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) nulls[5] = false; values[5] = CStringGetTextDatum(""); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); continue; } @@ -915,7 +892,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) nulls[29] = true; } - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); /* If only a single backend was requested, and we found it, break. */ if (pid != -1) @@ -1838,22 +1815,10 @@ pg_stat_get_slru(PG_FUNCTION_ARGS) { #define PG_STAT_GET_SLRU_COLS 9 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; int i; PgStat_SLRUStats *stats; - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); /* request SLRU stats from the stat collector */ stats = pgstat_fetch_slru(); @@ -1885,7 +1850,7 @@ pg_stat_get_slru(PG_FUNCTION_ARGS) values[7] = Int64GetDatum(stat.truncate); values[8] = TimestampTzGetDatum(stat.stat_reset_timestamp); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); } return (Datum) 0; diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 40e46540c5..64c949ae23 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -4833,23 +4833,14 @@ text_to_table(PG_FUNCTION_ARGS) { ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo; SplitTextOutputData tstate; - MemoryContext old_cxt; - - /* OK, prepare tuplestore in per-query memory */ - old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory); tstate.astate = NULL; - tstate.tupstore = MakeFuncResultTuplestore(fcinfo, NULL); - tstate.tupdesc = CreateTupleDescCopy(rsi->expectedDesc); - - MemoryContextSwitchTo(old_cxt); + MakeFuncResultTuplestore(fcinfo, TUPSTORE_SRF_USE_EXPECTED); + tstate.tupstore = rsi->setResult; + tstate.tupdesc = rsi->setDesc; (void) split_text(fcinfo, &tstate); - rsi->returnMode = SFRM_Materialize; - rsi->setResult = tstate.tupstore; - rsi->setDesc = tstate.tupdesc; - return (Datum) 0; } diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index 094228c767..73c9b42c9e 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -1761,40 +1761,61 @@ build_function_result_tupdesc_d(char prokind, } /* - * Helper function to construct tuplestore + * MakeFuncResultTuplestore + * + * Helper function to construct a tuplestore for a set-returning + * function, storing the tuplestore and the tupledesc created into + * the function's ReturnSetInfo. + * + * "flags" can be set to TUPSTORE_SRF_USE_EXPECTED, so as the tuple + * descriptor used comes from expectedDesc, which is the one expected + * by the caller. TUPSTORE_SRF_BLESS would complete the information + * associated to the tuple descriptor, which is necessary when the + * tuple descriptor comes from a transient RECORD datatype. */ -Tuplestorestate * -MakeFuncResultTuplestore(FunctionCallInfo fcinfo, TupleDesc *tupdesc) +void +MakeFuncResultTuplestore(FunctionCallInfo fcinfo, bits32 flags) { bool random_access; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; Tuplestorestate *tupstore; + MemoryContext old_context, per_query_ctx; + TupleDesc stored_tupdesc; - /* Must be called in per query memory context */ - Assert(CurrentMemoryContext == rsinfo->econtext->ecxt_per_query_memory); - - /* check to see if caller supports us returning a tuplestore */ + /* check to see if caller supports returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize) || - (tupdesc == NULL && rsinfo->expectedDesc == NULL)) + ((flags & TUPSTORE_SRF_USE_EXPECTED) != 0 && rsinfo->expectedDesc == NULL)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not allowed in this context"))); /* If needed, build a tuple descriptor for our result type */ - if (tupdesc != NULL) + if ((flags & TUPSTORE_SRF_USE_EXPECTED) != 0) + stored_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc); + else { - if (get_call_result_type(fcinfo, NULL, tupdesc) != TYPEFUNC_COMPOSITE) + if (get_call_result_type(fcinfo, NULL, &stored_tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); } - random_access = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0; - tupstore = tuplestore_begin_heap(random_access, false, work_mem); + /* If requested, bless the tuple descriptor */ + if ((flags & TUPSTORE_SRF_BLESS) != 0) + BlessTupleDesc(stored_tupdesc); - return tupstore; + random_access = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0; + + /* This must be done in the per-query memory context */ + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + old_context = MemoryContextSwitchTo(per_query_ctx); + tupstore = tuplestore_begin_heap(random_access, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = stored_tupdesc; + MemoryContextSwitchTo(old_context); } /* diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 21c9ec0122..1272e377f7 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10157,28 +10157,14 @@ show_all_file_settings(PG_FUNCTION_ARGS) { #define NUM_PG_FILE_SETTINGS_ATTS 7 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; ConfigVariable *conf; int seqno; - MemoryContext per_query_ctx; - MemoryContext oldcontext; /* Scan the config files using current context as workspace */ conf = ProcessConfigFileInternal(PGC_SIGHUP, false, DEBUG3); - /* Switch into long-lived context to construct returned data structures */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - /* Build a tuplestore to return our results in */ - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - /* The rest can be done in short-lived context */ - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); /* Process the results and create a tuplestore */ for (seqno = 1; conf != NULL; conf = conf->next, seqno++) @@ -10226,7 +10212,7 @@ show_all_file_settings(PG_FUNCTION_ARGS) nulls[6] = true; /* shove row into tuplestore */ - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); } return (Datum) 0; diff --git a/src/backend/utils/misc/pg_config.c b/src/backend/utils/misc/pg_config.c index bb0d531443..add2ca33d8 100644 --- a/src/backend/utils/misc/pg_config.c +++ b/src/backend/utils/misc/pg_config.c @@ -25,26 +25,12 @@ Datum pg_config(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - Tuplestorestate *tupstore; - TupleDesc tupdesc; - MemoryContext oldcontext; ConfigData *configdata; size_t configdata_len; int i = 0; - if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - elog(ERROR, "return type must be a row type"); - - /* Build tuplestore to hold the result rows */ - oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - /* initialize our tuplestore */ - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); configdata = get_configdata(my_exec_path, &configdata_len); for (i = 0; i < configdata_len; i++) @@ -58,7 +44,7 @@ pg_config(PG_FUNCTION_ARGS) values[0] = CStringGetTextDatum(configdata[i].name); values[1] = CStringGetTextDatum(configdata[i].setting); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); } return (Datum) 0; diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index 1432961b7f..aeac0b29f0 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -1132,28 +1132,14 @@ Datum pg_cursor(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; HASH_SEQ_STATUS hash_seq; PortalHashEnt *hentry; - /* need to build tuplestore in query context */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - /* * We put all the tuples into a tuplestore in one scan of the hashtable. * This avoids any issue of the hashtable possibly changing between calls. */ - tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - /* generate junk in short-term context */ - MemoryContextSwitchTo(oldcontext); + MakeFuncResultTuplestore(fcinfo, 0); hash_seq_init(&hash_seq, PortalHashTable); while ((hentry = hash_seq_search(&hash_seq)) != NULL) @@ -1175,13 +1161,9 @@ pg_cursor(PG_FUNCTION_ARGS) values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL); values[5] = TimestampTzGetDatum(portal->creation_time); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); } - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - return (Datum) 0; } -- 2.35.1