Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit fcc2817

Browse files
committed
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
1 parent 04e706d commit fcc2817

File tree

5 files changed

+48
-128
lines changed

5 files changed

+48
-128
lines changed

src/backend/commands/prepare.c

+7-24
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "catalog/pg_type.h"
2323
#include "commands/createas.h"
2424
#include "commands/prepare.h"
25+
#include "funcapi.h"
2526
#include "miscadmin.h"
2627
#include "nodes/nodeFuncs.h"
2728
#include "parser/analyze.h"
@@ -716,37 +717,23 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
716717
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
717718
errmsg("materialize mode required, but it is not allowed in this context")));
718719

720+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
721+
elog(ERROR, "return type must be a row type");
722+
719723
/* need to build tuplestore in query context */
720724
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
721725
oldcontext = MemoryContextSwitchTo(per_query_ctx);
722726

723-
/*
724-
* build tupdesc for result tuples. This must match the definition of the
725-
* pg_prepared_statements view in system_views.sql
726-
*/
727-
tupdesc = CreateTemplateTupleDesc(7);
728-
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
729-
TEXTOID, -1, 0);
730-
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
731-
TEXTOID, -1, 0);
732-
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepare_time",
733-
TIMESTAMPTZOID, -1, 0);
734-
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "parameter_types",
735-
REGTYPEARRAYOID, -1, 0);
736-
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql",
737-
BOOLOID, -1, 0);
738-
TupleDescInitEntry(tupdesc, (AttrNumber) 6, "generic_plans",
739-
INT8OID, -1, 0);
740-
TupleDescInitEntry(tupdesc, (AttrNumber) 7, "custom_plans",
741-
INT8OID, -1, 0);
742-
743727
/*
744728
* We put all the tuples into a tuplestore in one scan of the hashtable.
745729
* This avoids any issue of the hashtable possibly changing between calls.
746730
*/
747731
tupstore =
748732
tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
749733
false, work_mem);
734+
rsinfo->returnMode = SFRM_Materialize;
735+
rsinfo->setResult = tupstore;
736+
rsinfo->setDesc = tupdesc;
750737

751738
/* generate junk in short-term context */
752739
MemoryContextSwitchTo(oldcontext);
@@ -778,10 +765,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
778765
}
779766
}
780767

781-
rsinfo->returnMode = SFRM_Materialize;
782-
rsinfo->setResult = tupstore;
783-
rsinfo->setDesc = tupdesc;
784-
785768
return (Datum) 0;
786769
}
787770

src/backend/foreign/foreign.c

+15-22
Original file line numberDiff line numberDiff line change
@@ -499,17 +499,19 @@ IsImportableForeignTable(const char *tablename,
499499

500500

501501
/*
502-
* deflist_to_tuplestore - Helper function to convert DefElem list to
503-
* tuplestore usable in SRF.
502+
* pg_options_to_table - Convert options array to name/value table
503+
*
504+
* This is useful to provide details for information_schema and pg_dump.
504505
*/
505-
static void
506-
deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
506+
Datum
507+
pg_options_to_table(PG_FUNCTION_ARGS)
507508
{
509+
Datum array = PG_GETARG_DATUM(0);
508510
ListCell *cell;
511+
List *options;
512+
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
509513
TupleDesc tupdesc;
510514
Tuplestorestate *tupstore;
511-
Datum values[2];
512-
bool nulls[2];
513515
MemoryContext per_query_ctx;
514516
MemoryContext oldcontext;
515517

@@ -524,6 +526,9 @@ deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
524526
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
525527
errmsg("materialize mode required, but it is not allowed in this context")));
526528

529+
options = untransformRelOptions(array);
530+
rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
531+
527532
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
528533
oldcontext = MemoryContextSwitchTo(per_query_ctx);
529534

@@ -536,9 +541,13 @@ deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
536541
rsinfo->setResult = tupstore;
537542
rsinfo->setDesc = tupdesc;
538543

544+
MemoryContextSwitchTo(oldcontext);
545+
539546
foreach(cell, options)
540547
{
541548
DefElem *def = lfirst(cell);
549+
Datum values[2];
550+
bool nulls[2];
542551

543552
values[0] = CStringGetTextDatum(def->defname);
544553
nulls[0] = false;
@@ -555,22 +564,6 @@ deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
555564
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
556565
}
557566

558-
MemoryContextSwitchTo(oldcontext);
559-
}
560-
561-
562-
/*
563-
* Convert options array to name/value table. Useful for information
564-
* schema and pg_dump.
565-
*/
566-
Datum
567-
pg_options_to_table(PG_FUNCTION_ARGS)
568-
{
569-
Datum array = PG_GETARG_DATUM(0);
570-
571-
deflist_to_tuplestore((ReturnSetInfo *) fcinfo->resultinfo,
572-
untransformRelOptions(array));
573-
574567
return (Datum) 0;
575568
}
576569

src/backend/utils/misc/guc.c

+3-17
Original file line numberDiff line numberDiff line change
@@ -10174,30 +10174,16 @@ show_all_file_settings(PG_FUNCTION_ARGS)
1017410174
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1017510175
errmsg("materialize mode required, but it is not allowed in this context")));
1017610176

10177+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
10178+
elog(ERROR, "return type must be a row type");
10179+
1017710180
/* Scan the config files using current context as workspace */
1017810181
conf = ProcessConfigFileInternal(PGC_SIGHUP, false, DEBUG3);
1017910182

1018010183
/* Switch into long-lived context to construct returned data structures */
1018110184
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1018210185
oldcontext = MemoryContextSwitchTo(per_query_ctx);
1018310186

10184-
/* Build a tuple descriptor for our result type */
10185-
tupdesc = CreateTemplateTupleDesc(NUM_PG_FILE_SETTINGS_ATTS);
10186-
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "sourcefile",
10187-
TEXTOID, -1, 0);
10188-
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "sourceline",
10189-
INT4OID, -1, 0);
10190-
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "seqno",
10191-
INT4OID, -1, 0);
10192-
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "name",
10193-
TEXTOID, -1, 0);
10194-
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "setting",
10195-
TEXTOID, -1, 0);
10196-
TupleDescInitEntry(tupdesc, (AttrNumber) 6, "applied",
10197-
BOOLOID, -1, 0);
10198-
TupleDescInitEntry(tupdesc, (AttrNumber) 7, "error",
10199-
TEXTOID, -1, 0);
10200-
1020110187
/* Build a tuplestore to return our results in */
1020210188
tupstore = tuplestore_begin_heap(true, false, work_mem);
1020310189
rsinfo->returnMode = SFRM_Materialize;

src/backend/utils/misc/pg_config.c

+17-48
Original file line numberDiff line numberDiff line change
@@ -26,80 +26,49 @@ pg_config(PG_FUNCTION_ARGS)
2626
{
2727
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2828
Tuplestorestate *tupstore;
29-
HeapTuple tuple;
3029
TupleDesc tupdesc;
31-
AttInMetadata *attinmeta;
32-
MemoryContext per_query_ctx;
3330
MemoryContext oldcontext;
3431
ConfigData *configdata;
3532
size_t configdata_len;
36-
char *values[2];
3733
int i = 0;
3834

3935
/* check to see if caller supports us returning a tuplestore */
4036
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
4137
ereport(ERROR,
4238
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4339
errmsg("set-valued function called in context that cannot accept a set")));
44-
if (!(rsinfo->allowedModes & SFRM_Materialize) ||
45-
rsinfo->expectedDesc == NULL)
40+
if (!(rsinfo->allowedModes & SFRM_Materialize))
4641
ereport(ERROR,
4742
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4843
errmsg("materialize mode required, but it is not allowed in this context")));
4944

50-
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
51-
oldcontext = MemoryContextSwitchTo(per_query_ctx);
45+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
46+
elog(ERROR, "return type must be a row type");
5247

53-
/* get the requested return tuple description */
54-
tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
48+
/* Build tuplestore to hold the result rows */
49+
oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
5550

56-
/*
57-
* Check to make sure we have a reasonable tuple descriptor
58-
*/
59-
if (tupdesc->natts != 2 ||
60-
TupleDescAttr(tupdesc, 0)->atttypid != TEXTOID ||
61-
TupleDescAttr(tupdesc, 1)->atttypid != TEXTOID)
62-
ereport(ERROR,
63-
(errcode(ERRCODE_SYNTAX_ERROR),
64-
errmsg("query-specified return tuple and "
65-
"function return type are not compatible")));
66-
67-
/* OK to use it */
68-
attinmeta = TupleDescGetAttInMetadata(tupdesc);
69-
70-
/* let the caller know we're sending back a tuplestore */
51+
tupstore = tuplestore_begin_heap(true, false, work_mem);
7152
rsinfo->returnMode = SFRM_Materialize;
53+
rsinfo->setResult = tupstore;
54+
rsinfo->setDesc = tupdesc;
7255

73-
/* initialize our tuplestore */
74-
tupstore = tuplestore_begin_heap(true, false, work_mem);
56+
MemoryContextSwitchTo(oldcontext);
7557

7658
configdata = get_configdata(my_exec_path, &configdata_len);
7759
for (i = 0; i < configdata_len; i++)
7860
{
79-
values[0] = configdata[i].name;
80-
values[1] = configdata[i].setting;
81-
82-
tuple = BuildTupleFromCStrings(attinmeta, values);
83-
tuplestore_puttuple(tupstore, tuple);
84-
}
61+
Datum values[2];
62+
bool nulls[2];
8563

86-
/*
87-
* no longer need the tuple descriptor reference created by
88-
* TupleDescGetAttInMetadata()
89-
*/
90-
ReleaseTupleDesc(tupdesc);
64+
memset(values, 0, sizeof(values));
65+
memset(nulls, 0, sizeof(nulls));
9166

92-
rsinfo->setResult = tupstore;
67+
values[0] = CStringGetTextDatum(configdata[i].name);
68+
values[1] = CStringGetTextDatum(configdata[i].setting);
9369

94-
/*
95-
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
96-
* tuples are in our tuplestore and passed back through rsinfo->setResult.
97-
* rsinfo->setDesc is set to the tuple description that we actually used
98-
* to build our tuples with, so the caller can verify we did what it was
99-
* expecting.
100-
*/
101-
rsinfo->setDesc = tupdesc;
102-
MemoryContextSwitchTo(oldcontext);
70+
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
71+
}
10372

10473
return (Datum) 0;
10574
}

src/backend/utils/mmgr/portalmem.c

+6-17
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "access/xact.h"
2222
#include "catalog/pg_type.h"
2323
#include "commands/portalcmds.h"
24+
#include "funcapi.h"
2425
#include "miscadmin.h"
2526
#include "storage/ipc.h"
2627
#include "utils/builtins.h"
@@ -1152,23 +1153,8 @@ pg_cursor(PG_FUNCTION_ARGS)
11521153
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
11531154
oldcontext = MemoryContextSwitchTo(per_query_ctx);
11541155

1155-
/*
1156-
* build tupdesc for result tuples. This must match the definition of the
1157-
* pg_cursors view in system_views.sql
1158-
*/
1159-
tupdesc = CreateTemplateTupleDesc(6);
1160-
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
1161-
TEXTOID, -1, 0);
1162-
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
1163-
TEXTOID, -1, 0);
1164-
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_holdable",
1165-
BOOLOID, -1, 0);
1166-
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_binary",
1167-
BOOLOID, -1, 0);
1168-
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_scrollable",
1169-
BOOLOID, -1, 0);
1170-
TupleDescInitEntry(tupdesc, (AttrNumber) 6, "creation_time",
1171-
TIMESTAMPTZOID, -1, 0);
1156+
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1157+
elog(ERROR, "return type must be a row type");
11721158

11731159
/*
11741160
* We put all the tuples into a tuplestore in one scan of the hashtable.
@@ -1177,6 +1163,9 @@ pg_cursor(PG_FUNCTION_ARGS)
11771163
tupstore =
11781164
tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
11791165
false, work_mem);
1166+
rsinfo->returnMode = SFRM_Materialize;
1167+
rsinfo->setResult = tupstore;
1168+
rsinfo->setDesc = tupdesc;
11801169

11811170
/* generate junk in short-term context */
11821171
MemoryContextSwitchTo(oldcontext);

0 commit comments

Comments
 (0)