v5-0001-Add-helper-to-make-tuplestore.patch
text/x-patch
Filename: v5-0001-Add-helper-to-make-tuplestore.patch
Type: text/x-patch
Part: 0
Message:
Re: make tuplestore helper function
Patch
Format: format-patch
Series: patch v5-0001
Subject: Add helper to make tuplestore
| File | + | − |
|---|---|---|
| src/backend/access/transam/xlogfuncs.c | 1 | 15 |
| src/backend/commands/event_trigger.c | 2 | 30 |
| src/backend/commands/extension.c | 3 | 45 |
| src/backend/commands/prepare.c | 2 | 13 |
| src/backend/foreign/foreign.c | 21 | 30 |
| src/backend/libpq/hba.c | 1 | 18 |
| src/backend/replication/logical/launcher.c | 1 | 15 |
| src/backend/replication/logical/logicalfuncs.c | 1 | 17 |
| src/backend/replication/logical/origin.c | 4 | 15 |
| src/backend/replication/slotfuncs.c | 1 | 15 |
| src/backend/replication/walsender.c | 1 | 15 |
| src/backend/storage/ipc/shmem.c | 1 | 15 |
| src/backend/utils/adt/datetime.c | 1 | 16 |
| src/backend/utils/adt/genfile.c | 2 | 29 |
| src/backend/utils/adt/jsonfuncs.c | 24 | 60 |
| src/backend/utils/adt/mcxtfuncs.c | 1 | 15 |
| src/backend/utils/adt/misc.c | 1 | 13 |
| src/backend/utils/adt/pgstatfuncs.c | 3 | 45 |
| src/backend/utils/adt/varlena.c | 6 | 9 |
| src/backend/utils/fmgr/funcapi.c | 36 | 0 |
| src/backend/utils/misc/guc.c | 1 | 11 |
| src/backend/utils/misc/pg_config.c | 5 | 6 |
| src/backend/utils/mmgr/portalmem.c | 2 | 13 |
| src/include/funcapi.h | 2 | 0 |
From 8ea7f90162f73049541fb6f53e714298a5ecfc41 Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Tue, 2 Nov 2021 12:20:55 -0400
Subject: [PATCH v5] Add helper to make tuplestore
And use it to refactor out existing duplicate code.
Note that for func-api callers previously calling
tuplestore_begin_heap() with a constant value for the randomAccess
parameter, by using MakeFuncResultTuplestore(), they are now passing
true or false based on whether or not SFRM_Materialize_Random is set in
rsinfo->allowedModes.
This is consistent with the instructions in
src/backend/utils/fmgr/README, which state that tuplestores "must be
created with randomAccess = true if SFRM_Materialize_Random is set in
allowedModes, but it can (and preferably should) be created with
randomAccess = false if not".
Author: Melanie Plageman <melanieplageman@gmail.com>
Reviewed-by: Justin Pryzby <pryzby@telsasoft.com>
Discussion: https://www.postgresql.org/message-id/flat/CAAKRu_azyd1Z3W_r7Ou4sorTjRCs%2BPxeHw1CWJeXKofkE6TuZg%40mail.gmail.com
---
src/backend/access/transam/xlogfuncs.c | 16 +---
src/backend/commands/event_trigger.c | 32 +------
src/backend/commands/extension.c | 48 +----------
src/backend/commands/prepare.c | 15 +---
src/backend/foreign/foreign.c | 51 +++++------
src/backend/libpq/hba.c | 19 +----
src/backend/replication/logical/launcher.c | 16 +---
.../replication/logical/logicalfuncs.c | 18 +---
src/backend/replication/logical/origin.c | 19 +----
src/backend/replication/slotfuncs.c | 16 +---
src/backend/replication/walsender.c | 16 +---
src/backend/storage/ipc/shmem.c | 16 +---
src/backend/utils/adt/datetime.c | 17 +---
src/backend/utils/adt/genfile.c | 31 +------
src/backend/utils/adt/jsonfuncs.c | 84 ++++++-------------
src/backend/utils/adt/mcxtfuncs.c | 16 +---
src/backend/utils/adt/misc.c | 14 +---
src/backend/utils/adt/pgstatfuncs.c | 48 +----------
src/backend/utils/adt/varlena.c | 15 ++--
src/backend/utils/fmgr/funcapi.c | 36 ++++++++
src/backend/utils/misc/guc.c | 12 +--
src/backend/utils/misc/pg_config.c | 11 ++-
src/backend/utils/mmgr/portalmem.c | 15 +---
src/include/funcapi.h | 2 +
24 files changed, 123 insertions(+), 460 deletions(-)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index dd9a45c186..59d77adf6e 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -178,24 +178,10 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
- /* 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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index df264329d8..c20473cbb1 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -1306,25 +1306,11 @@ 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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
@@ -1864,25 +1850,11 @@ 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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index eaa76af47b..fe9bf52ca8 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1929,25 +1929,11 @@ pg_available_extensions(PG_FUNCTION_ARGS)
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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
@@ -2037,25 +2023,11 @@ pg_available_extension_versions(PG_FUNCTION_ARGS)
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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
@@ -2322,25 +2294,11 @@ 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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 5e03c7c5aa..32fc055792 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -22,6 +22,7 @@
#include "catalog/pg_type.h"
#include "commands/createas.h"
#include "commands/prepare.h"
+#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
@@ -706,16 +707,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
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")));
-
/* need to build tuplestore in query context */
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
@@ -744,9 +735,7 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
* 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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, NULL);
/* generate junk in short-term context */
MemoryContextSwitchTo(oldcontext);
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index e07cc57431..9bfc5f57f9 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"
@@ -499,30 +500,34 @@ IsImportableForeignTable(const char *tablename,
/*
- * deflist_to_tuplestore - Helper function to convert DefElem list to
- * tuplestore usable in SRF.
+ * Convert options array to name/value table. Useful for information
+ * schema and pg_dump.
*/
-static void
-deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
+Datum
+pg_options_to_table(PG_FUNCTION_ARGS)
{
+ Datum array = PG_GETARG_DATUM(0);
ListCell *cell;
+ List *options;
+
+ ReturnSetInfo *rsinfo;
TupleDesc tupdesc;
Tuplestorestate *tupstore;
- Datum values[2];
- bool nulls[2];
+
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)
+ Datum values[2];
+ bool nulls[2];
+
+ options = untransformRelOptions(array);
+ rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ if (!rsinfo->expectedDesc)
ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("materialize mode required, but it is not allowed in this context")));
+ (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+ errmsg("expected tuple format not specified as required for "
+ "set-returning function.")));
+
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
@@ -531,7 +536,7 @@ deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
* Now prepare the result set.
*/
tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
- tupstore = tuplestore_begin_heap(true, false, work_mem);
+ tupstore = MakeFuncResultTuplestore(fcinfo, NULL);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
@@ -559,20 +564,6 @@ deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
tuplestore_donestoring(tupstore);
MemoryContextSwitchTo(oldcontext);
-}
-
-
-/*
- * Convert options array to name/value table. Useful for information
- * schema and pg_dump.
- */
-Datum
-pg_options_to_table(PG_FUNCTION_ARGS)
-{
- Datum array = PG_GETARG_DATUM(0);
-
- deflist_to_tuplestore((ReturnSetInfo *) fcinfo->resultinfo,
- untransformRelOptions(array));
return (Datum) 0;
}
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 4328eb74fe..986f9be09d 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -2710,29 +2710,12 @@ pg_hba_file_rules(PG_FUNCTION_ARGS)
* 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);
+ tuple_store = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsi->setDesc = tupdesc;
rsi->setResult = tuple_store;
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 3fb4caa803..f1d2665dce 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -935,24 +935,10 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index 6cd2279a2e..662006e518 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -141,25 +141,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);
@@ -202,7 +188,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
}
}
- p->tupstore = tuplestore_begin_heap(true, false, work_mem);
+ p->tupstore = MakeFuncResultTuplestore(fcinfo, &p->tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = p->tupstore;
rsinfo->setDesc = p->tupdesc;
@@ -295,8 +281,6 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
CHECK_FOR_INTERRUPTS();
}
- tuplestore_donestoring(tupstore);
-
/*
* Logical decoding could have clobbered CurrentResourceOwner during
* transaction management, so restore the executor's value. (This is
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index 65dcd033fd..a88cdc2f17 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -1491,30 +1491,19 @@ pg_show_replication_origin_status(PG_FUNCTION_ARGS)
/* 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);
+ 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");
/* prevent slots from being concurrently dropped */
LWLockAcquire(ReplicationOriginLock, LW_SHARED);
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index d11daeb1fc..fb2123e789 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -239,20 +239,6 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
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
@@ -262,7 +248,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
- tupstore = tuplestore_begin_heap(true, false, work_mem);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 84915ed95b..cc3e6185df 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -3401,24 +3401,10 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 4425e99f17..ec4dd9caf8 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -547,24 +547,10 @@ pg_get_shmem_allocations(PG_FUNCTION_ARGS)
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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index cb3fa85892..83b6b2bb33 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4786,7 +4786,6 @@ Datum
pg_timezone_names(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
- bool randomAccess;
TupleDesc tupdesc;
Tuplestorestate *tupstore;
pg_tzenum *tzenum;
@@ -4801,24 +4800,10 @@ pg_timezone_names(PG_FUNCTION_ARGS)
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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 027ed86400..4b08e12527 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -483,7 +483,6 @@ 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;
@@ -501,24 +500,13 @@ 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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, NULL);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
@@ -577,31 +565,16 @@ 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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 6335845d08..d0f5e61c58 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -1926,30 +1926,20 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
funcname)));
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
-
- if (!rsi || !IsA(rsi, ReturnSetInfo) ||
- (rsi->allowedModes & SFRM_Materialize) == 0 ||
- rsi->expectedDesc == NULL)
+ if (!rsi->expectedDesc)
ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that "
- "cannot accept a set")));
+ (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+ errmsg("expected tuple format not specified as required for "
+ "set-returning function.")));
rsi->returnMode = SFRM_Materialize;
- if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("function returning record called in context "
- "that cannot accept type record")));
-
old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
+ tuple_store = MakeFuncResultTuplestore(fcinfo, &tupdesc);
+
ret_tdesc = CreateTupleDescCopy(tupdesc);
BlessTupleDesc(ret_tdesc);
- tuple_store =
- tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
- false, work_mem);
MemoryContextSwitchTo(old_cxt);
@@ -2038,27 +2028,21 @@ each_worker(FunctionCallInfo fcinfo, bool as_text)
sem = palloc0(sizeof(JsonSemAction));
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
-
- if (!rsi || !IsA(rsi, ReturnSetInfo) ||
- (rsi->allowedModes & SFRM_Materialize) == 0 ||
- rsi->expectedDesc == NULL)
+ if (!rsi->expectedDesc)
ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that "
- "cannot accept a set")));
+ (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+ errmsg("expected tuple format not specified as required for "
+ "set-returning function.")));
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->tuple_store = MakeFuncResultTuplestore(fcinfo, &tupdesc);
+
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);
@@ -2226,27 +2210,21 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
errmsg("cannot extract elements from an object")));
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
-
- if (!rsi || !IsA(rsi, ReturnSetInfo) ||
- (rsi->allowedModes & SFRM_Materialize) == 0 ||
- rsi->expectedDesc == NULL)
+ if (!rsi->expectedDesc)
ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that "
- "cannot accept a set")));
+ (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+ errmsg("expected tuple format not specified as required for "
+ "set-returning function.")));
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);
+ tuple_store = MakeFuncResultTuplestore(fcinfo, NULL);
MemoryContextSwitchTo(old_cxt);
@@ -2335,18 +2313,15 @@ elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
sem = palloc0(sizeof(JsonSemAction));
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
-
- if (!rsi || !IsA(rsi, ReturnSetInfo) ||
- (rsi->allowedModes & SFRM_Materialize) == 0 ||
- rsi->expectedDesc == NULL)
+ if (!rsi->expectedDesc)
ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that "
- "cannot accept a set")));
+ (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+ errmsg("expected tuple format not specified as required for "
+ "set-returning function.")));
+
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 */
@@ -2354,9 +2329,7 @@ elements_worker(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
state->ret_tdesc = CreateTupleDescCopy(tupdesc);
BlessTupleDesc(state->ret_tdesc);
- state->tuple_store =
- tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
- false, work_mem);
+ state->tuple_store = MakeFuncResultTuplestore(fcinfo, NULL);
MemoryContextSwitchTo(old_cxt);
@@ -3798,13 +3771,6 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
- if (!rsi || !IsA(rsi, ReturnSetInfo) ||
- (rsi->allowedModes & SFRM_Materialize) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-valued function called in context that "
- "cannot accept a set")));
-
rsi->returnMode = SFRM_Materialize;
/*
@@ -3871,9 +3837,7 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname,
/* make tuplestore in a sufficiently long-lived memory context */
old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
- state->tuple_store = tuplestore_begin_heap(rsi->allowedModes &
- SFRM_Materialize_Random,
- false, work_mem);
+ state->tuple_store = MakeFuncResultTuplestore(fcinfo, NULL);
MemoryContextSwitchTo(old_cxt);
state->function_name = funcname;
diff --git a/src/backend/utils/adt/mcxtfuncs.c b/src/backend/utils/adt/mcxtfuncs.c
index 6ddbf70b30..bc1ba622b0 100644
--- a/src/backend/utils/adt/mcxtfuncs.c
+++ b/src/backend/utils/adt/mcxtfuncs.c
@@ -125,24 +125,10 @@ pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)
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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 88faf4dfd7..8398657a93 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -203,7 +203,6 @@ 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;
@@ -211,16 +210,6 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
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);
@@ -228,8 +217,7 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, NULL);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index f529c1561a..37c5c9d765 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -467,20 +467,6 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
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)
cmdtype = PROGRESS_COMMAND_VACUUM;
@@ -502,7 +488,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
- tupstore = tuplestore_begin_heap(true, false, work_mem);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
@@ -577,24 +563,10 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
@@ -1879,24 +1851,10 @@ pg_stat_get_slru(PG_FUNCTION_ARGS)
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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, &tupdesc);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index bd3091bbfb..07cfae983d 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"
@@ -4844,22 +4845,18 @@ text_to_table(PG_FUNCTION_ARGS)
SplitTextOutputData tstate;
MemoryContext old_cxt;
- /* check to see if caller supports us returning a tuplestore */
- if (rsi == NULL || !IsA(rsi, ReturnSetInfo))
+ if (!rsi->expectedDesc)
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")));
+ (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+ errmsg("expected tuple format not specified as required for "
+ "set-returning function.")));
/* 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);
+ tstate.tupstore = MakeFuncResultTuplestore(fcinfo, NULL);
MemoryContextSwitchTo(old_cxt);
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index e94b8037ec..105219314c 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -13,6 +13,7 @@
*/
#include "postgres.h"
+#include "miscadmin.h"
#include "access/htup_details.h"
#include "access/relation.h"
#include "catalog/namespace.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"
@@ -1757,7 +1759,41 @@ build_function_result_tupdesc_d(char prokind,
return desc;
}
+/*
+ * Helper function to construct tuplestore
+ */
+Tuplestorestate *
+MakeFuncResultTuplestore(FunctionCallInfo fcinfo, TupleDesc *tupdesc)
+{
+ bool random_access;
+ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ Tuplestorestate *tupstore;
+
+ /* 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 */
+ 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 needed, build a tuple descriptor for our result type */
+ if (tupdesc)
+ {
+ if (get_call_result_type(fcinfo, NULL, 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);
+
+ return tupstore;
+}
/*
* RelationNameGetTupleDesc
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index f9504d3aec..b113870533 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10052,16 +10052,6 @@ show_all_file_settings(PG_FUNCTION_ARGS)
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")));
-
/* Scan the config files using current context as workspace */
conf = ProcessConfigFileInternal(PGC_SIGHUP, false, DEBUG3);
@@ -10087,7 +10077,7 @@ show_all_file_settings(PG_FUNCTION_ARGS)
TEXTOID, -1, 0);
/* Build a tuplestore to return our results in */
- tupstore = tuplestore_begin_heap(true, false, work_mem);
+ tupstore = MakeFuncResultTuplestore(fcinfo, NULL);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
diff --git a/src/backend/utils/misc/pg_config.c b/src/backend/utils/misc/pg_config.c
index 34d77db75a..6d75d3ebcb 100644
--- a/src/backend/utils/misc/pg_config.c
+++ b/src/backend/utils/misc/pg_config.c
@@ -36,12 +36,11 @@ pg_config(PG_FUNCTION_ARGS)
char *values[2];
int i = 0;
- /* check to see if caller supports us returning a tuplestore */
- if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
+ if (!rsinfo->expectedDesc)
ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("materialize mode required, but it is not "
- "allowed in this context")));
+ (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+ errmsg("expected tuple format not specified as required for "
+ "set-returning function.")));
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
@@ -67,7 +66,7 @@ pg_config(PG_FUNCTION_ARGS)
rsinfo->returnMode = SFRM_Materialize;
/* initialize our tuplestore */
- tupstore = tuplestore_begin_heap(true, false, work_mem);
+ tupstore = MakeFuncResultTuplestore(fcinfo, NULL);
configdata = get_configdata(my_exec_path, &configdata_len);
for (i = 0; i < configdata_len; i++)
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 58674d611d..c68317d038 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -21,6 +21,7 @@
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/portalcmds.h"
+#include "funcapi.h"
#include "miscadmin.h"
#include "storage/ipc.h"
#include "utils/builtins.h"
@@ -1138,16 +1139,6 @@ pg_cursor(PG_FUNCTION_ARGS)
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);
@@ -1174,9 +1165,7 @@ pg_cursor(PG_FUNCTION_ARGS)
* 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);
+ tupstore = MakeFuncResultTuplestore(fcinfo, NULL);
/* generate junk in short-term context */
MemoryContextSwitchTo(oldcontext);
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index f1304d47e3..09d8e8dd91 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -229,6 +229,8 @@ 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);
/*----------
--
2.30.2