1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

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
This commit is contained in:
Michael Paquier
2022-03-08 10:12:22 +09:00
parent d5ed9da41d
commit 5b81703787
8 changed files with 32 additions and 301 deletions

View File

@ -491,15 +491,9 @@ xpath_table(PG_FUNCTION_ARGS)
HeapTuple spi_tuple;
TupleDesc spi_tupdesc;
/* Output tuple (tuplestore) support */
Tuplestorestate *tupstore = NULL;
TupleDesc ret_tupdesc;
HeapTuple ret_tuple;
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
AttInMetadata *attinmeta;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
char **values;
xmlChar **xpaths;
@ -517,48 +511,10 @@ xpath_table(PG_FUNCTION_ARGS)
PgXmlErrorContext *xmlerrcxt;
volatile xmlDocPtr doctree = NULL;
/* We only have a valid tuple description in table function mode */
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->expectedDesc == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("xpath_table must be called as a table function")));
/*
* We want to materialise because it means that we don't have to carry
* libxml2 parser state between invocations of this function
*/
if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("xpath_table requires Materialize mode, but it is not "
"allowed in this context")));
/*
* The tuplestore must exist in a higher context than this function call
* (per_query_ctx is used)
*/
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
/*
* Create the tuplestore - work_mem is the max in-memory size before a
* file is created on disk to hold it.
*/
tupstore =
tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
false, work_mem);
MemoryContextSwitchTo(oldcontext);
/* get the requested return tuple description */
ret_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
SetSingleFuncCall(fcinfo, SRF_SINGLE_USE_EXPECTED);
/* must have at least one output column (for the pkey) */
if (ret_tupdesc->natts < 1)
if (rsinfo->setDesc->natts < 1)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("xpath_table must have at least one output column")));
@ -571,14 +527,10 @@ xpath_table(PG_FUNCTION_ARGS)
* representation.
*/
attinmeta = TupleDescGetAttInMetadata(ret_tupdesc);
attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc);
/* Set return mode and allocate value space. */
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setDesc = ret_tupdesc;
values = (char **) palloc(ret_tupdesc->natts * sizeof(char *));
xpaths = (xmlChar **) palloc(ret_tupdesc->natts * sizeof(xmlChar *));
values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *));
xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *));
/*
* Split XPaths. xpathset is a writable CString.
@ -587,7 +539,7 @@ xpath_table(PG_FUNCTION_ARGS)
*/
numpaths = 0;
pos = xpathset;
while (numpaths < (ret_tupdesc->natts - 1))
while (numpaths < (rsinfo->setDesc->natts - 1))
{
xpaths[numpaths++] = (xmlChar *) pos;
pos = strstr(pos, pathsep);
@ -621,9 +573,6 @@ xpath_table(PG_FUNCTION_ARGS)
tuptable = SPI_tuptable;
spi_tupdesc = tuptable->tupdesc;
/* Switch out of SPI context */
MemoryContextSwitchTo(oldcontext);
/*
* Check that SPI returned correct result. If you put a comma into one of
* the function parameters, this will catch it when the SPI query returns
@ -655,6 +604,7 @@ xpath_table(PG_FUNCTION_ARGS)
xmlXPathObjectPtr res;
xmlChar *resstr;
xmlXPathCompExprPtr comppath;
HeapTuple ret_tuple;
/* Extract the row data as C Strings */
spi_tuple = tuptable->vals[i];
@ -666,7 +616,7 @@ xpath_table(PG_FUNCTION_ARGS)
* return NULL in all columns. Note that this also means that
* spare columns will be NULL.
*/
for (j = 0; j < ret_tupdesc->natts; j++)
for (j = 0; j < rsinfo->setDesc->natts; j++)
values[j] = NULL;
/* Insert primary key */
@ -682,7 +632,7 @@ xpath_table(PG_FUNCTION_ARGS)
{
/* not well-formed, so output all-NULL tuple */
ret_tuple = BuildTupleFromCStrings(attinmeta, values);
tuplestore_puttuple(tupstore, ret_tuple);
tuplestore_puttuple(rsinfo->setResult, ret_tuple);
heap_freetuple(ret_tuple);
}
else
@ -749,7 +699,7 @@ xpath_table(PG_FUNCTION_ARGS)
if (had_values)
{
ret_tuple = BuildTupleFromCStrings(attinmeta, values);
tuplestore_puttuple(tupstore, ret_tuple);
tuplestore_puttuple(rsinfo->setResult, ret_tuple);
heap_freetuple(ret_tuple);
}
@ -785,8 +735,6 @@ xpath_table(PG_FUNCTION_ARGS)
SPI_finish();
rsinfo->setResult = tupstore;
/*
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
* tuples are in our tuplestore and passed back through rsinfo->setResult.