summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/event_trigger.c62
-rw-r--r--src/backend/commands/extension.c93
-rw-r--r--src/backend/commands/prepare.c34
-rw-r--r--src/backend/foreign/foreign.c34
-rw-r--r--src/backend/libpq/hba.c46
-rw-r--r--src/backend/replication/logical/launcher.c31
-rw-r--r--src/backend/replication/logical/logicalfuncs.c21
-rw-r--r--src/backend/replication/logical/origin.c32
-rw-r--r--src/backend/replication/slotfuncs.c31
-rw-r--r--src/backend/replication/walsender.c31
-rw-r--r--src/backend/storage/ipc/shmem.c35
-rw-r--r--src/backend/utils/adt/datetime.c30
-rw-r--r--src/backend/utils/adt/genfile.c61
-rw-r--r--src/backend/utils/adt/jsonfuncs.c141
-rw-r--r--src/backend/utils/adt/mcxtfuncs.c33
-rw-r--r--src/backend/utils/adt/misc.c33
-rw-r--r--src/backend/utils/adt/pgstatfuncs.c91
-rw-r--r--src/backend/utils/adt/varlena.c27
-rw-r--r--src/backend/utils/fmgr/README4
-rw-r--r--src/backend/utils/fmgr/funcapi.c69
-rw-r--r--src/backend/utils/misc/guc.c31
-rw-r--r--src/backend/utils/misc/pg_config.c29
-rw-r--r--src/backend/utils/mmgr/portalmem.c37
-rw-r--r--src/include/funcapi.h12
24 files changed, 176 insertions, 872 deletions
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 1e8587502e5..3c3fc2515b7 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;
/*
@@ -1306,30 +1302,8 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
errmsg("%s can only be called in a sql_drop event trigger function",
"pg_event_trigger_dropped_objects()")));
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- 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 */
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
slist_foreach(iter, &(currentEventTriggerState->SQLDropList))
{
@@ -1398,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;
@@ -1846,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;
/*
@@ -1861,30 +1832,8 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
errmsg("%s can only be called in an event trigger function",
"pg_event_trigger_ddl_commands()")));
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- 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 */
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
foreach(lc, currentEventTriggerState->commandList)
{
@@ -2055,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 42503ef4543..1013790dbb3 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1932,38 +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;
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- 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 */
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
location = get_extension_control_directory();
dir = AllocateDir(location);
@@ -2015,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);
@@ -2037,38 +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;
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- 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 */
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
location = get_extension_control_directory();
dir = AllocateDir(location);
@@ -2103,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);
@@ -2316,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;
@@ -2327,30 +2273,8 @@ pg_extension_update_paths(PG_FUNCTION_ARGS)
/* Check extension name validity before any filesystem access */
check_valid_extension_name(NameStr(*extname));
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- 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 */
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
/* Read the extension's control file */
control = read_extension_control_file(NameStr(*extname));
@@ -2407,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 dce30aed6c1..d2d8ee120c3 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -702,41 +702,12 @@ Datum
pg_prepared_statement(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
- TupleDesc tupdesc;
- Tuplestorestate *tupstore;
- MemoryContext per_query_ctx;
- MemoryContext oldcontext;
-
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- /* 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 =
- tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
- false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- /* generate junk in short-term context */
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
/* hash table might be uninitialized */
if (prepared_queries)
@@ -761,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 c3406c3b9d9..cf222fc3e99 100644
--- a/src/backend/foreign/foreign.c
+++ b/src/backend/foreign/foreign.c
@@ -20,6 +20,7 @@
#include "catalog/pg_user_mapping.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
+#include "funcapi.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/builtins.h"
@@ -510,38 +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;
-
- /* check to see if caller supports us 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) ||
- rsinfo->expectedDesc == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
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.
- */
- tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ /* prepare the result set */
+ SetSingleFuncCall(fcinfo, SRF_SINGLE_USE_EXPECTED);
foreach(cell, options)
{
@@ -561,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 d84a40b7265..90953c38f3d 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -1685,8 +1685,8 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
if (parsedline->auth_method == uaCert)
{
/*
- * For auth method cert, client certificate validation is mandatory, and it implies
- * the level of verify-full.
+ * For auth method cert, client certificate validation is mandatory,
+ * and it implies the level of verify-full.
*/
parsedline->clientcert = clientCertFull;
}
@@ -2703,47 +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
- * up our current position in the parsed list every time.
+ * 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;
-
- /* Check to see if caller supports us returning a tuplestore */
- if (rsi == NULL || !IsA(rsi, ReturnSetInfo))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that cannot accept a set")));
- if (!(rsi->allowedModes & SFRM_Materialize))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- rsi->returnMode = SFRM_Materialize;
-
- /* Build a tuple descriptor for our result type */
- 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 */
- old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
-
- tuple_store =
- tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
- false, work_mem);
- rsi->setDesc = tupdesc;
- rsi->setResult = tuple_store;
-
- MemoryContextSwitchTo(old_cxt);
+ SetSingleFuncCall(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 5a68d6deadc..6f25b2c2ad5 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -930,34 +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;
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
/* Make sure we get consistent view of the workers. */
LWLockAcquire(LogicalRepWorkerLock, LW_SHARED);
@@ -1010,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 3bd770a3ba6..6058d36e0d5 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -142,25 +142,11 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
errmsg("options array must not be null")));
arr = PG_GETARG_ARRAYTYPE_P(3);
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
/* state to write output to */
p = palloc0(sizeof(DecodingOutputState));
p->binary_output = binary;
- /* Build a tuple descriptor for our result type */
- if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
@@ -203,10 +189,9 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
}
}
- p->tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = p->tupstore;
- rsinfo->setDesc = p->tupdesc;
+ SetSingleFuncCall(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 76055a8a036..0e38eff0f00 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -1482,40 +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);
- 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- if (tupdesc->natts != REPLICATION_ORIGIN_PROGRESS_COLS)
- elog(ERROR, "wrong function definition");
-
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
-
+ SetSingleFuncCall(fcinfo, 0);
/* prevent slots from being concurrently dropped */
LWLockAcquire(ReplicationOriginLock, LW_SHARED);
@@ -1565,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 886899afd22..ca945994ef0 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -233,42 +233,16 @@ 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;
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
/*
* We don't require any special permission to see this function's data
* because nothing should be sensitive. The most critical being the slot
* name, which shouldn't contain anything particularly sensitive.
*/
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
currlsn = GetXLogWriteRecPtr();
@@ -431,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 5a718b1fe9b..2d0292a092e 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -3403,37 +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;
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
/*
* Get the currently active synchronous standbys. This could be out of
@@ -3577,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 1f023a34604..c1279960cd0 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -537,39 +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];
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
LWLockAcquire(ShmemIndexLock, LW_SHARED);
@@ -585,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 */
@@ -593,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;
@@ -601,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 7926258c064..ba0ec35ac5d 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4786,9 +4786,6 @@ Datum
pg_timezone_names(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
- bool randomAccess;
- TupleDesc tupdesc;
- Tuplestorestate *tupstore;
pg_tzenum *tzenum;
pg_tz *tz;
Datum values[4];
@@ -4799,31 +4796,8 @@ pg_timezone_names(PG_FUNCTION_ARGS)
const char *tzn;
Interval *resInterval;
struct pg_tm itm;
- MemoryContext oldcontext;
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
- oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
-
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
- tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
/* initialize timezone scanning code */
tzenum = pg_tzenumerate_start();
@@ -4865,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 fe6863d8b44..1ed01620a1b 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -477,12 +477,8 @@ pg_ls_dir(PG_FUNCTION_ARGS)
char *location;
bool missing_ok = false;
bool include_dot_dirs = false;
- bool randomAccess;
- TupleDesc tupdesc;
- Tuplestorestate *tupstore;
DIR *dirdesc;
struct dirent *de;
- MemoryContext oldcontext;
location = convert_and_check_filename(PG_GETARG_TEXT_PP(0));
@@ -495,29 +491,7 @@ pg_ls_dir(PG_FUNCTION_ARGS)
include_dot_dirs = PG_GETARG_BOOL(2);
}
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* 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);
-
- randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
- tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, SRF_SINGLE_USE_EXPECTED);
dirdesc = AllocateDir(location);
if (!dirdesc)
@@ -541,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);
@@ -571,36 +546,10 @@ static Datum
pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
- bool randomAccess;
- TupleDesc tupdesc;
- Tuplestorestate *tupstore;
DIR *dirdesc;
struct dirent *de;
- MemoryContext oldcontext;
-
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
- oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
-
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
- tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
/*
* Now walk the directory. Note that we must do this within a single SRF
@@ -648,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 2457061f97e..29664aa6e40 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,30 +1923,7 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
funcname)));
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
-
- if (!rsi || !IsA(rsi, ReturnSetInfo))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that cannot accept a set")));
- if (!(rsi->allowedModes & SFRM_Materialize))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- rsi->returnMode = SFRM_Materialize;
-
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
-
- ret_tdesc = CreateTupleDescCopy(tupdesc);
- BlessTupleDesc(ret_tdesc);
- tuple_store =
- tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
- false, work_mem);
-
- MemoryContextSwitchTo(old_cxt);
+ SetSingleFuncCall(fcinfo, SRF_SINGLE_BLESS);
tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
"jsonb_each temporary cxt",
@@ -1964,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};
@@ -2001,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);
@@ -2013,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();
}
@@ -2027,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);
@@ -2037,30 +2003,9 @@ each_worker(FunctionCallInfo fcinfo, bool as_text)
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
- if (!rsi || !IsA(rsi, ReturnSetInfo))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that cannot accept a set")));
-
- if (!(rsi->allowedModes & SFRM_Materialize))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- rsi->returnMode = SFRM_Materialize;
-
- (void) get_call_result_type(fcinfo, NULL, &tupdesc);
-
- /* make these in a sufficiently long-lived memory context */
- old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
-
- state->ret_tdesc = CreateTupleDescCopy(tupdesc);
- BlessTupleDesc(state->ret_tdesc);
- state->tuple_store =
- tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
- false, work_mem);
-
- MemoryContextSwitchTo(old_cxt);
+ SetSingleFuncCall(fcinfo, SRF_SINGLE_BLESS);
+ state->tuple_store = rsi->setResult;
+ state->ret_tdesc = rsi->setDesc;
sem->semstate = (void *) state;
sem->array_start = each_array_start;
@@ -2079,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();
}
@@ -2206,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;
@@ -2227,31 +2166,8 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
- if (!rsi || !IsA(rsi, ReturnSetInfo))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that cannot accept a set")));
-
- if (!(rsi->allowedModes & SFRM_Materialize) ||
- rsi->expectedDesc == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- rsi->returnMode = SFRM_Materialize;
-
- /* it's a simple type, so don't use get_call_result_type() */
- tupdesc = rsi->expectedDesc;
-
- old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
-
- ret_tdesc = CreateTupleDescCopy(tupdesc);
- BlessTupleDesc(ret_tdesc);
- tuple_store =
- tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
- false, work_mem);
-
- MemoryContextSwitchTo(old_cxt);
+ SetSingleFuncCall(fcinfo,
+ SRF_SINGLE_USE_EXPECTED | SRF_SINGLE_BLESS);
tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
"jsonb_array_elements temporary cxt",
@@ -2265,7 +2181,6 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
if (r == WJB_ELEM)
{
- HeapTuple tuple;
Datum values[1];
bool nulls[1] = {false};
@@ -2291,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);
@@ -2303,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();
}
@@ -2330,41 +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));
+ SetSingleFuncCall(fcinfo, SRF_SINGLE_USE_EXPECTED | SRF_SINGLE_BLESS);
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
-
- if (!rsi || !IsA(rsi, ReturnSetInfo))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that cannot accept a set")));
-
- if (!(rsi->allowedModes & SFRM_Materialize) ||
- rsi->expectedDesc == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- rsi->returnMode = SFRM_Materialize;
-
- /* it's a simple type, so don't use get_call_result_type() */
- tupdesc = rsi->expectedDesc;
-
- /* make these in a sufficiently long-lived memory context */
- old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
-
- state->ret_tdesc = CreateTupleDescCopy(tupdesc);
- BlessTupleDesc(state->ret_tdesc);
- state->tuple_store =
- tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
- false, work_mem);
-
- MemoryContextSwitchTo(old_cxt);
+ state->tuple_store = rsi->setResult;
+ state->ret_tdesc = rsi->setDesc;
sem->semstate = (void *) state;
sem->object_start = elements_object_start;
@@ -2384,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 c7c95adf97d..bb7cc940249 100644
--- a/src/backend/utils/adt/mcxtfuncs.c
+++ b/src/backend/utils/adt/mcxtfuncs.c
@@ -120,36 +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;
-
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
-
- PutMemoryContextsStatsTupleStore(tupstore, tupdesc,
+
+ SetSingleFuncCall(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 e79eb6b4788..4568749d230 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -203,39 +203,11 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
{
Oid tablespaceOid = PG_GETARG_OID(0);
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
- bool randomAccess;
- TupleDesc tupdesc;
- Tuplestorestate *tupstore;
char *location;
DIR *dirdesc;
struct dirent *de;
- MemoryContext oldcontext;
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* 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);
-
- randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
- tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
-
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, SRF_SINGLE_USE_EXPECTED);
if (tablespaceOid == GLOBALTABLESPACE_OID)
{
@@ -291,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 fd993d0d5fb..eff45b16f2c 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -461,25 +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;
-
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
/* Translate command name into command type code. */
if (pg_strcasecmp(cmd, "VACUUM") == 0)
@@ -499,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 = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
/* 1-based index */
for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
@@ -552,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;
@@ -569,34 +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;
-
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
- /* Build a tuple descriptor for our result type */
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
/* 1-based index */
for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
@@ -629,7 +578,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[5] = false;
values[5] = CStringGetTextDatum("<backend information not available>");
- tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+ tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
continue;
}
@@ -943,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)
@@ -1866,36 +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;
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* Build a tuple descriptor for our result type */
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
/* request SLRU stats from the stat collector */
stats = pgstat_fetch_slru();
@@ -1927,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 b2003f5672e..22ab5a4329f 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -24,6 +24,7 @@
#include "common/hashfn.h"
#include "common/int.h"
#include "common/unicode_norm.h"
+#include "funcapi.h"
#include "lib/hyperloglog.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
@@ -4832,34 +4833,14 @@ text_to_table(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
SplitTextOutputData tstate;
- MemoryContext old_cxt;
-
- /* check to see if caller supports us returning a tuplestore */
- if (rsi == NULL || !IsA(rsi, ReturnSetInfo))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that cannot accept a set")));
- if (!(rsi->allowedModes & SFRM_Materialize) ||
- rsi->expectedDesc == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* OK, prepare tuplestore in per-query memory */
- old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
tstate.astate = NULL;
- tstate.tupdesc = CreateTupleDescCopy(rsi->expectedDesc);
- tstate.tupstore = tuplestore_begin_heap(true, false, work_mem);
-
- MemoryContextSwitchTo(old_cxt);
+ SetSingleFuncCall(fcinfo, SRF_SINGLE_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/README b/src/backend/utils/fmgr/README
index 1e4c4b94a95..9d8848106df 100644
--- a/src/backend/utils/fmgr/README
+++ b/src/backend/utils/fmgr/README
@@ -305,6 +305,10 @@ If available, the expected tuple descriptor is passed in ReturnSetInfo;
in other contexts the expectedDesc field will be NULL. The function need
not pay attention to expectedDesc, but it may be useful in special cases.
+SetSingleFuncCall() is a helper function able to setup the function's
+ReturnSetInfo for a single call, filling in the Tuplestore and the
+TupleDesc with the proper configuration for Materialize mode.
+
There is no support for functions accepting sets; instead, the function will
be called multiple times, once for each element of the input set.
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index 5d913ae08d8..d269662ad8e 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -19,6 +19,7 @@
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
+#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "utils/array.h"
#include "utils/builtins.h"
@@ -27,6 +28,7 @@
#include "utils/regproc.h"
#include "utils/rel.h"
#include "utils/syscache.h"
+#include "utils/tuplestore.h"
#include "utils/typcache.h"
@@ -55,6 +57,73 @@ static TypeFuncClass get_type_func_class(Oid typid, Oid *base_typeid);
/*
+ * SetSingleFuncCall
+ *
+ * Helper function to build the state of a set-returning function used
+ * in the context of a single call with materialize mode. This code
+ * includes sanity checks on ReturnSetInfo, creates the Tuplestore and
+ * the TupleDesc used with the function and stores them into the
+ * function's ReturnSetInfo.
+ *
+ * "flags" can be set to SRF_SINGLE_USE_EXPECTED, to use the tuple
+ * descriptor coming from expectedDesc, which is the tuple descriptor
+ * expected by the caller. SRF_SINGLE_BLESS can be set to complete the
+ * information associated to the tuple descriptor, which is necessary
+ * in some cases where the tuple descriptor comes from a transient
+ * RECORD datatype.
+ */
+void
+SetSingleFuncCall(FunctionCallInfo fcinfo, bits32 flags)
+{
+ bool random_access;
+ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ Tuplestorestate *tupstore;
+ MemoryContext old_context,
+ per_query_ctx;
+ TupleDesc stored_tupdesc;
+
+ /* 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) ||
+ ((flags & SRF_SINGLE_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")));
+
+ /*
+ * Store the tuplestore and the tuple descriptor in ReturnSetInfo. 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);
+
+ /* build a tuple descriptor for our result type */
+ if ((flags & SRF_SINGLE_USE_EXPECTED) != 0)
+ stored_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ else
+ {
+ if (get_call_result_type(fcinfo, NULL, &stored_tupdesc) != TYPEFUNC_COMPOSITE)
+ elog(ERROR, "return type must be a row type");
+ }
+
+ /* If requested, bless the tuple descriptor */
+ if ((flags & SRF_SINGLE_BLESS) != 0)
+ BlessTupleDesc(stored_tupdesc);
+
+ random_access = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
+
+ tupstore = tuplestore_begin_heap(random_access, false, work_mem);
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = stored_tupdesc;
+ MemoryContextSwitchTo(old_context);
+}
+
+
+/*
* init_MultiFuncCall
* Create an empty FuncCallContext data structure
* and do some other basic Multi-function call setup
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 1e3650184b1..6d11f9c71b9 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10157,41 +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;
-
- /* Check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
/* 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 = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- /* The rest can be done in short-lived context */
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
/* Process the results and create a tuplestore */
for (seqno = 1; conf != NULL; conf = conf->next, seqno++)
@@ -10239,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 e646a419106..d9e18caf448 100644
--- a/src/backend/utils/misc/pg_config.c
+++ b/src/backend/utils/misc/pg_config.c
@@ -25,35 +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;
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- 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);
-
- tupstore = tuplestore_begin_heap(true, false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- MemoryContextSwitchTo(oldcontext);
+ /* initialize our tuplestore */
+ SetSingleFuncCall(fcinfo, 0);
configdata = get_configdata(my_exec_path, &configdata_len);
for (i = 0; i < configdata_len; i++)
@@ -67,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 afc03682d9c..d549f66d4af 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -1132,43 +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;
- /* check to see if caller supports us 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))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
-
- /* need to build tuplestore in query context */
- per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
- oldcontext = MemoryContextSwitchTo(per_query_ctx);
-
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- elog(ERROR, "return type must be a row type");
-
/*
* 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 =
- tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
- false, work_mem);
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
- /* generate junk in short-term context */
- MemoryContextSwitchTo(oldcontext);
+ SetSingleFuncCall(fcinfo, 0);
hash_seq_init(&hash_seq, PortalHashTable);
while ((hentry = hash_seq_search(&hash_seq)) != NULL)
@@ -1190,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;
}
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index ba927c2f330..dc3d819a1c7 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -278,14 +278,20 @@ extern Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple);
* memory allocated in multi_call_memory_ctx, but holding file descriptors or
* other non-memory resources open across calls is a bug. SRFs that need
* such resources should not use these macros, but instead populate a
- * tuplestore during a single call, and return that using SFRM_Materialize
- * mode (see fmgr/README). Alternatively, set up a callback to release
- * resources at query shutdown, using RegisterExprContextCallback().
+ * tuplestore during a single call, as set up by SetSingleFuncCall() (see
+ * fmgr/README). Alternatively, set up a callback to release resources
+ * at query shutdown, using RegisterExprContextCallback().
*
*----------
*/
/* from funcapi.c */
+
+/* flag bits for SetSingleFuncCall() */
+#define SRF_SINGLE_USE_EXPECTED 0x01 /* use expectedDesc as tupdesc */
+#define SRF_SINGLE_BLESS 0x02 /* validate tuple for SRF */
+extern void SetSingleFuncCall(FunctionCallInfo fcinfo, bits32 flags);
+
extern FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS);
extern FuncCallContext *per_MultiFuncCall(PG_FUNCTION_ARGS);
extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx);