Skip to content

Commit 5b81703

Browse files
committed
Simplify SRFs using materialize mode in contrib/ modules
9e98583 introduced a helper to centralize building their needed state (tuplestore, tuple descriptors, etc.), checking for any errors. This commit updates all places of contrib/ that can be switched to use SetSingleFuncCall() as a drop-in replacement, resulting in the removal of a lot of boilerplate code in all the modules updated by this commit. Per analysis, some places remain as they are: - pg_logdir_ls() in adminpack/ uses historically TYPEFUNC_RECORD as return type, and I suspect that changing it may cause issues at run-time with some of its past versions, down to 1.0. - dblink/ uses a wrapper function doing exactly the work of SetSingleFuncCall(). Here the switch should be possible, but rather invasive so it does not seem the extra backpatch maintenance cost. - tablefunc/, similarly, uses multiple helper functions with portions of SetSingleFuncCall() spread across the code paths of this module. Author: Melanie Plageman Discussion: https://postgr.es/m/CAAKRu_bvDPJoL9mH6eYwvBpPtTGQwbDzfJbCM-OjkSZDu5yTPg@mail.gmail.com
1 parent d5ed9da commit 5b81703

File tree

8 files changed

+32
-301
lines changed

8 files changed

+32
-301
lines changed

contrib/amcheck/verify_heapam.c

Lines changed: 4 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ static bool check_tuple_visibility(HeapCheckContext *ctx);
165165
static void report_corruption(HeapCheckContext *ctx, char *msg);
166166
static void report_toast_corruption(HeapCheckContext *ctx,
167167
ToastedAttribute *ta, char *msg);
168-
static TupleDesc verify_heapam_tupdesc(void);
169168
static FullTransactionId FullTransactionIdFromXidAndCtx(TransactionId xid,
170169
const HeapCheckContext *ctx);
171170
static void update_cached_xid_range(HeapCheckContext *ctx);
@@ -214,8 +213,6 @@ Datum
214213
verify_heapam(PG_FUNCTION_ARGS)
215214
{
216215
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
217-
MemoryContext old_context;
218-
bool random_access;
219216
HeapCheckContext ctx;
220217
Buffer vmbuffer = InvalidBuffer;
221218
Oid relid;
@@ -227,16 +224,6 @@ verify_heapam(PG_FUNCTION_ARGS)
227224
BlockNumber nblocks;
228225
const char *skip;
229226

230-
/* Check to see if caller supports us returning a tuplestore */
231-
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
232-
ereport(ERROR,
233-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
234-
errmsg("set-valued function called in context that cannot accept a set")));
235-
if (!(rsinfo->allowedModes & SFRM_Materialize))
236-
ereport(ERROR,
237-
(errcode(ERRCODE_SYNTAX_ERROR),
238-
errmsg("materialize mode required, but it is not allowed in this context")));
239-
240227
/* Check supplied arguments */
241228
if (PG_ARGISNULL(0))
242229
ereport(ERROR,
@@ -290,15 +277,10 @@ verify_heapam(PG_FUNCTION_ARGS)
290277
*/
291278
ctx.attnum = -1;
292279

293-
/* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
294-
old_context = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
295-
random_access = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
296-
ctx.tupdesc = verify_heapam_tupdesc();
297-
ctx.tupstore = tuplestore_begin_heap(random_access, false, work_mem);
298-
rsinfo->returnMode = SFRM_Materialize;
299-
rsinfo->setResult = ctx.tupstore;
300-
rsinfo->setDesc = ctx.tupdesc;
301-
MemoryContextSwitchTo(old_context);
280+
/* Construct the tuplestore and tuple descriptor */
281+
SetSingleFuncCall(fcinfo, 0);
282+
ctx.tupdesc = rsinfo->setDesc;
283+
ctx.tupstore = rsinfo->setResult;
302284

303285
/* Open relation, check relkind and access method */
304286
ctx.rel = relation_open(relid, AccessShareLock);
@@ -630,26 +612,6 @@ report_toast_corruption(HeapCheckContext *ctx, ToastedAttribute *ta,
630612
ctx->is_corrupt = true;
631613
}
632614

633-
/*
634-
* Construct the TupleDesc used to report messages about corruptions found
635-
* while scanning the heap.
636-
*/
637-
static TupleDesc
638-
verify_heapam_tupdesc(void)
639-
{
640-
TupleDesc tupdesc;
641-
AttrNumber a = 0;
642-
643-
tupdesc = CreateTemplateTupleDesc(HEAPCHECK_RELATION_COLS);
644-
TupleDescInitEntry(tupdesc, ++a, "blkno", INT8OID, -1, 0);
645-
TupleDescInitEntry(tupdesc, ++a, "offnum", INT4OID, -1, 0);
646-
TupleDescInitEntry(tupdesc, ++a, "attnum", INT4OID, -1, 0);
647-
TupleDescInitEntry(tupdesc, ++a, "msg", TEXTOID, -1, 0);
648-
Assert(a == HEAPCHECK_RELATION_COLS);
649-
650-
return BlessTupleDesc(tupdesc);
651-
}
652-
653615
/*
654616
* Check for tuple header corruption.
655617
*

contrib/dblink/dblink.c

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,36 +1928,14 @@ dblink_get_notify(PG_FUNCTION_ARGS)
19281928
PGconn *conn;
19291929
PGnotify *notify;
19301930
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1931-
TupleDesc tupdesc;
1932-
Tuplestorestate *tupstore;
1933-
MemoryContext per_query_ctx;
1934-
MemoryContext oldcontext;
1935-
1936-
prepTuplestoreResult(fcinfo);
19371931

19381932
dblink_init();
19391933
if (PG_NARGS() == 1)
19401934
conn = dblink_get_named_conn(text_to_cstring(PG_GETARG_TEXT_PP(0)));
19411935
else
19421936
conn = pconn->conn;
19431937

1944-
/* create the tuplestore in per-query memory */
1945-
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1946-
oldcontext = MemoryContextSwitchTo(per_query_ctx);
1947-
1948-
tupdesc = CreateTemplateTupleDesc(DBLINK_NOTIFY_COLS);
1949-
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "notify_name",
1950-
TEXTOID, -1, 0);
1951-
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "be_pid",
1952-
INT4OID, -1, 0);
1953-
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "extra",
1954-
TEXTOID, -1, 0);
1955-
1956-
tupstore = tuplestore_begin_heap(true, false, work_mem);
1957-
rsinfo->setResult = tupstore;
1958-
rsinfo->setDesc = tupdesc;
1959-
1960-
MemoryContextSwitchTo(oldcontext);
1938+
SetSingleFuncCall(fcinfo, 0);
19611939

19621940
PQconsumeInput(conn);
19631941
while ((notify = PQnotifies(conn)) != NULL)
@@ -1980,7 +1958,7 @@ dblink_get_notify(PG_FUNCTION_ARGS)
19801958
else
19811959
nulls[2] = true;
19821960

1983-
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1961+
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
19841962

19851963
PQfreemem(notify);
19861964
PQconsumeInput(conn);

contrib/pageinspect/brinfuncs.c

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ brin_page_items(PG_FUNCTION_ARGS)
126126
bytea *raw_page = PG_GETARG_BYTEA_P(0);
127127
Oid indexRelid = PG_GETARG_OID(1);
128128
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
129-
TupleDesc tupdesc;
130-
MemoryContext oldcontext;
131-
Tuplestorestate *tupstore;
132129
Relation indexRel;
133130
brin_column_state **columns;
134131
BrinDesc *bdesc;
@@ -143,29 +140,7 @@ brin_page_items(PG_FUNCTION_ARGS)
143140
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
144141
errmsg("must be superuser to use raw page functions")));
145142

146-
/* check to see if caller supports us returning a tuplestore */
147-
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
148-
ereport(ERROR,
149-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
150-
errmsg("set-valued function called in context that cannot accept a set")));
151-
if (!(rsinfo->allowedModes & SFRM_Materialize))
152-
ereport(ERROR,
153-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
154-
errmsg("materialize mode required, but it is not allowed in this context")));
155-
156-
/* Build a tuple descriptor for our result type */
157-
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
158-
elog(ERROR, "return type must be a row type");
159-
160-
/* Build tuplestore to hold the result rows */
161-
oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
162-
163-
tupstore = tuplestore_begin_heap(true, false, work_mem);
164-
rsinfo->returnMode = SFRM_Materialize;
165-
rsinfo->setResult = tupstore;
166-
rsinfo->setDesc = tupdesc;
167-
168-
MemoryContextSwitchTo(oldcontext);
143+
SetSingleFuncCall(fcinfo, 0);
169144

170145
indexRel = index_open(indexRelid, AccessShareLock);
171146
bdesc = brin_build_desc(indexRel);
@@ -251,7 +226,7 @@ brin_page_items(PG_FUNCTION_ARGS)
251226
int att = attno - 1;
252227

253228
values[0] = UInt16GetDatum(offset);
254-
switch (TupleDescAttr(tupdesc, 1)->atttypid)
229+
switch (TupleDescAttr(rsinfo->setDesc, 1)->atttypid)
255230
{
256231
case INT8OID:
257232
values[1] = Int64GetDatum((int64) dtup->bt_blkno);
@@ -301,7 +276,7 @@ brin_page_items(PG_FUNCTION_ARGS)
301276
}
302277
}
303278

304-
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
279+
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
305280

306281
/*
307282
* If the item was unused, jump straight to the next one; otherwise,

contrib/pageinspect/gistfuncs.c

Lines changed: 4 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ gist_page_items_bytea(PG_FUNCTION_ARGS)
9797
{
9898
bytea *raw_page = PG_GETARG_BYTEA_P(0);
9999
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
100-
bool randomAccess;
101-
TupleDesc tupdesc;
102-
Tuplestorestate *tupstore;
103-
MemoryContext oldcontext;
104100
Page page;
105101
OffsetNumber offset;
106102
OffsetNumber maxoff = InvalidOffsetNumber;
@@ -110,29 +106,7 @@ gist_page_items_bytea(PG_FUNCTION_ARGS)
110106
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
111107
errmsg("must be superuser to use raw page functions")));
112108

113-
/* check to see if caller supports us returning a tuplestore */
114-
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
115-
ereport(ERROR,
116-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
117-
errmsg("set-valued function called in context that cannot accept a set")));
118-
if (!(rsinfo->allowedModes & SFRM_Materialize))
119-
ereport(ERROR,
120-
(errcode(ERRCODE_SYNTAX_ERROR),
121-
errmsg("materialize mode required, but it is not allowed in this context")));
122-
123-
/* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
124-
oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
125-
126-
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
127-
elog(ERROR, "return type must be a row type");
128-
129-
randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
130-
tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
131-
rsinfo->returnMode = SFRM_Materialize;
132-
rsinfo->setResult = tupstore;
133-
rsinfo->setDesc = tupdesc;
134-
135-
MemoryContextSwitchTo(oldcontext);
109+
SetSingleFuncCall(fcinfo, 0);
136110

137111
page = get_page_from_raw(raw_page);
138112

@@ -173,7 +147,7 @@ gist_page_items_bytea(PG_FUNCTION_ARGS)
173147
values[3] = BoolGetDatum(ItemIdIsDead(id));
174148
values[4] = PointerGetDatum(tuple_bytea);
175149

176-
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
150+
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
177151
}
178152

179153
return (Datum) 0;
@@ -185,11 +159,7 @@ gist_page_items(PG_FUNCTION_ARGS)
185159
bytea *raw_page = PG_GETARG_BYTEA_P(0);
186160
Oid indexRelid = PG_GETARG_OID(1);
187161
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
188-
bool randomAccess;
189162
Relation indexRel;
190-
TupleDesc tupdesc;
191-
Tuplestorestate *tupstore;
192-
MemoryContext oldcontext;
193163
Page page;
194164
OffsetNumber offset;
195165
OffsetNumber maxoff = InvalidOffsetNumber;
@@ -199,29 +169,7 @@ gist_page_items(PG_FUNCTION_ARGS)
199169
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
200170
errmsg("must be superuser to use raw page functions")));
201171

202-
/* check to see if caller supports us returning a tuplestore */
203-
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
204-
ereport(ERROR,
205-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
206-
errmsg("set-valued function called in context that cannot accept a set")));
207-
if (!(rsinfo->allowedModes & SFRM_Materialize))
208-
ereport(ERROR,
209-
(errcode(ERRCODE_SYNTAX_ERROR),
210-
errmsg("materialize mode required, but it is not allowed in this context")));
211-
212-
/* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
213-
oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
214-
215-
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
216-
elog(ERROR, "return type must be a row type");
217-
218-
randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
219-
tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
220-
rsinfo->returnMode = SFRM_Materialize;
221-
rsinfo->setResult = tupstore;
222-
rsinfo->setDesc = tupdesc;
223-
224-
MemoryContextSwitchTo(oldcontext);
172+
SetSingleFuncCall(fcinfo, 0);
225173

226174
/* Open the relation */
227175
indexRel = index_open(indexRelid, AccessShareLock);
@@ -272,7 +220,7 @@ gist_page_items(PG_FUNCTION_ARGS)
272220
nulls[4] = true;
273221
}
274222

275-
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
223+
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
276224
}
277225

278226
relation_close(indexRel, AccessShareLock);

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,10 +1494,6 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
14941494
bool showtext)
14951495
{
14961496
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1497-
TupleDesc tupdesc;
1498-
Tuplestorestate *tupstore;
1499-
MemoryContext per_query_ctx;
1500-
MemoryContext oldcontext;
15011497
Oid userid = GetUserId();
15021498
bool is_allowed_role = false;
15031499
char *qbuffer = NULL;
@@ -1516,30 +1512,14 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
15161512
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
15171513
errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
15181514

1519-
/* check to see if caller supports us returning a tuplestore */
1520-
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1521-
ereport(ERROR,
1522-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1523-
errmsg("set-valued function called in context that cannot accept a set")));
1524-
if (!(rsinfo->allowedModes & SFRM_Materialize))
1525-
ereport(ERROR,
1526-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1527-
errmsg("materialize mode required, but it is not allowed in this context")));
1528-
1529-
/* Switch into long-lived context to construct returned data structures */
1530-
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1531-
oldcontext = MemoryContextSwitchTo(per_query_ctx);
1532-
1533-
/* Build a tuple descriptor for our result type */
1534-
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1535-
elog(ERROR, "return type must be a row type");
1515+
SetSingleFuncCall(fcinfo, 0);
15361516

15371517
/*
15381518
* Check we have the expected number of output arguments. Aside from
15391519
* being a good safety check, we need a kluge here to detect API version
15401520
* 1.1, which was wedged into the code in an ill-considered way.
15411521
*/
1542-
switch (tupdesc->natts)
1522+
switch (rsinfo->setDesc->natts)
15431523
{
15441524
case PG_STAT_STATEMENTS_COLS_V1_0:
15451525
if (api_version != PGSS_V1_0)
@@ -1571,13 +1551,6 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
15711551
elog(ERROR, "incorrect number of output arguments");
15721552
}
15731553

1574-
tupstore = tuplestore_begin_heap(true, false, work_mem);
1575-
rsinfo->returnMode = SFRM_Materialize;
1576-
rsinfo->setResult = tupstore;
1577-
rsinfo->setDesc = tupdesc;
1578-
1579-
MemoryContextSwitchTo(oldcontext);
1580-
15811554
/*
15821555
* We'd like to load the query text file (if needed) while not holding any
15831556
* lock on pgss->lock. In the worst case we'll have to do this again
@@ -1800,7 +1773,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
18001773
api_version == PGSS_V1_9 ? PG_STAT_STATEMENTS_COLS_V1_9 :
18011774
-1 /* fail if you forget to update this assert */ ));
18021775

1803-
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1776+
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
18041777
}
18051778

18061779
LWLockRelease(pgss->lock);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy