summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Paquier2022-02-24 07:11:34 +0000
committerMichael Paquier2022-02-24 07:11:34 +0000
commitfcc28178c6943d7df72b484a87fdb7e06d0c1079 (patch)
tree29d84d92aa610c56a1c1c1a4089d9e5fd201e0ba
parent04e706d4238f98a98e1c0b1a02db9d4280b96f04 (diff)
Clean up and simplify code in a couple of set-returning functions
The following set-returning functions have their logic simplified, to be more consistent with other in-core areas: - pg_prepared_statement()'s tuple descriptor is now created with get_call_result_type() instead of being created from scratch, saving from some duplication with pg_proc.dat. - show_all_file_settings(), similarly, now uses get_call_result_type() to build its tuple descriptor instead of creating it from scratch. - pg_options_to_table() made use of a static routine called only once. This commit removes this internal routine to make the function easier to follow. - pg_config() was using a unique logic style, doing checks on the tuple descriptor passed down in expectedDesc, but it has no need to do so. This switches the function to use a tuplestore with a tuple descriptor retrieved from get_call_result_type(), instead. This simplifies an upcoming patch aimed at refactoring the way tuplestores are created and checked in set-returning functions, this change making sense as its own independent cleanup by shaving some code. Author: Melanie Plageman, Michael Paquier Reviewed-by: Justin Pryzby Discussion: https://postgr.es/m/CAAKRu_azyd1Z3W_r7Ou4sorTjRCs+PxeHw1CWJeXKofkE6TuZg@mail.gmail.com
-rw-r--r--src/backend/commands/prepare.c31
-rw-r--r--src/backend/foreign/foreign.c37
-rw-r--r--src/backend/utils/misc/guc.c20
-rw-r--r--src/backend/utils/misc/pg_config.c65
-rw-r--r--src/backend/utils/mmgr/portalmem.c23
5 files changed, 48 insertions, 128 deletions
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index e0c985ef8b0..dce30aed6c1 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"
@@ -716,37 +717,23 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
(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);
/*
- * build tupdesc for result tuples. This must match the definition of the
- * pg_prepared_statements view in system_views.sql
- */
- tupdesc = CreateTemplateTupleDesc(7);
- TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
- TEXTOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
- TEXTOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepare_time",
- TIMESTAMPTZOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 4, "parameter_types",
- REGTYPEARRAYOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql",
- BOOLOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 6, "generic_plans",
- INT8OID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 7, "custom_plans",
- INT8OID, -1, 0);
-
- /*
* 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);
@@ -778,10 +765,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
}
}
- rsinfo->returnMode = SFRM_Materialize;
- rsinfo->setResult = tupstore;
- rsinfo->setDesc = tupdesc;
-
return (Datum) 0;
}
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index d910bc2fbea..c3406c3b9d9 100644
--- a/src/backend/foreign/foreign.c
+++ b/src/backend/foreign/foreign.c
@@ -499,17 +499,19 @@ IsImportableForeignTable(const char *tablename,
/*
- * deflist_to_tuplestore - Helper function to convert DefElem list to
- * tuplestore usable in SRF.
+ * pg_options_to_table - Convert options array to name/value table
+ *
+ * This is useful to provide details 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 = (ReturnSetInfo *) fcinfo->resultinfo;
TupleDesc tupdesc;
Tuplestorestate *tupstore;
- Datum values[2];
- bool nulls[2];
MemoryContext per_query_ctx;
MemoryContext oldcontext;
@@ -524,6 +526,9 @@ deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
(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);
@@ -536,9 +541,13 @@ deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
+ MemoryContextSwitchTo(oldcontext);
+
foreach(cell, options)
{
DefElem *def = lfirst(cell);
+ Datum values[2];
+ bool nulls[2];
values[0] = CStringGetTextDatum(def->defname);
nulls[0] = false;
@@ -555,22 +564,6 @@ deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
- 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/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index bf7ec0d4666..1e3650184b1 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10174,6 +10174,9 @@ show_all_file_settings(PG_FUNCTION_ARGS)
(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);
@@ -10181,23 +10184,6 @@ show_all_file_settings(PG_FUNCTION_ARGS)
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
- /* Build a tuple descriptor for our result type */
- tupdesc = CreateTemplateTupleDesc(NUM_PG_FILE_SETTINGS_ATTS);
- TupleDescInitEntry(tupdesc, (AttrNumber) 1, "sourcefile",
- TEXTOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 2, "sourceline",
- INT4OID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 3, "seqno",
- INT4OID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 4, "name",
- TEXTOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 5, "setting",
- TEXTOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 6, "applied",
- BOOLOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 7, "error",
- TEXTOID, -1, 0);
-
/* Build a tuplestore to return our results in */
tupstore = tuplestore_begin_heap(true, false, work_mem);
rsinfo->returnMode = SFRM_Materialize;
diff --git a/src/backend/utils/misc/pg_config.c b/src/backend/utils/misc/pg_config.c
index 2dc875ebfbb..e646a419106 100644
--- a/src/backend/utils/misc/pg_config.c
+++ b/src/backend/utils/misc/pg_config.c
@@ -26,14 +26,10 @@ pg_config(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
Tuplestorestate *tupstore;
- HeapTuple tuple;
TupleDesc tupdesc;
- AttInMetadata *attinmeta;
- MemoryContext per_query_ctx;
MemoryContext oldcontext;
ConfigData *configdata;
size_t configdata_len;
- char *values[2];
int i = 0;
/* check to see if caller supports us returning a tuplestore */
@@ -41,65 +37,38 @@ pg_config(PG_FUNCTION_ARGS)
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)
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("materialize mode required, but it is not allowed in this 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");
- /* get the requested return tuple description */
- tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ /* Build tuplestore to hold the result rows */
+ oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
- /*
- * Check to make sure we have a reasonable tuple descriptor
- */
- if (tupdesc->natts != 2 ||
- TupleDescAttr(tupdesc, 0)->atttypid != TEXTOID ||
- TupleDescAttr(tupdesc, 1)->atttypid != TEXTOID)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("query-specified return tuple and "
- "function return type are not compatible")));
-
- /* OK to use it */
- attinmeta = TupleDescGetAttInMetadata(tupdesc);
-
- /* let the caller know we're sending back a tuplestore */
+ tupstore = tuplestore_begin_heap(true, false, work_mem);
rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
- /* initialize our tuplestore */
- tupstore = tuplestore_begin_heap(true, false, work_mem);
+ MemoryContextSwitchTo(oldcontext);
configdata = get_configdata(my_exec_path, &configdata_len);
for (i = 0; i < configdata_len; i++)
{
- values[0] = configdata[i].name;
- values[1] = configdata[i].setting;
-
- tuple = BuildTupleFromCStrings(attinmeta, values);
- tuplestore_puttuple(tupstore, tuple);
- }
+ Datum values[2];
+ bool nulls[2];
- /*
- * no longer need the tuple descriptor reference created by
- * TupleDescGetAttInMetadata()
- */
- ReleaseTupleDesc(tupdesc);
+ memset(values, 0, sizeof(values));
+ memset(nulls, 0, sizeof(nulls));
- rsinfo->setResult = tupstore;
+ values[0] = CStringGetTextDatum(configdata[i].name);
+ values[1] = CStringGetTextDatum(configdata[i].setting);
- /*
- * SFRM_Materialize mode expects us to return a NULL Datum. The actual
- * tuples are in our tuplestore and passed back through rsinfo->setResult.
- * rsinfo->setDesc is set to the tuple description that we actually used
- * to build our tuples with, so the caller can verify we did what it was
- * expecting.
- */
- rsinfo->setDesc = tupdesc;
- MemoryContextSwitchTo(oldcontext);
+ tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+ }
return (Datum) 0;
}
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 7885344164f..21ad87c0241 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"
@@ -1152,23 +1153,8 @@ pg_cursor(PG_FUNCTION_ARGS)
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
- /*
- * build tupdesc for result tuples. This must match the definition of the
- * pg_cursors view in system_views.sql
- */
- tupdesc = CreateTemplateTupleDesc(6);
- TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
- TEXTOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
- TEXTOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_holdable",
- BOOLOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_binary",
- BOOLOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_scrollable",
- BOOLOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 6, "creation_time",
- TIMESTAMPTZOID, -1, 0);
+ 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.
@@ -1177,6 +1163,9 @@ pg_cursor(PG_FUNCTION_ARGS)
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);