1 /*-------------------------------------------------------------------------
2 *
3 * pg_config.c
4 * Expose same output as pg_config except as an SRF
5 *
6 * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/backend/utils/misc/pg_config.c
11 *
12 *-------------------------------------------------------------------------
13 */
14
15 #include "postgres.h"
16
17 #include "catalog/pg_type.h"
18 #include "common/config_info.h"
19 #include "funcapi.h"
20 #include "miscadmin.h"
21 #include "port.h"
22 #include "utils/builtins.h"
23
24 Datum
pg_config(PG_FUNCTION_ARGS)25 pg_config(PG_FUNCTION_ARGS)
26 {
27 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
28 Tuplestorestate *tupstore;
29 HeapTuple tuple;
30 TupleDesc tupdesc;
31 AttInMetadata *attinmeta;
32 MemoryContext per_query_ctx;
33 MemoryContext oldcontext;
34 ConfigData *configdata;
35 size_t configdata_len;
36 char *values[2];
37 int i = 0;
38
39 /* check to see if caller supports us returning a tuplestore */
40 if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
41 ereport(ERROR,
42 (errcode(ERRCODE_SYNTAX_ERROR),
43 errmsg("materialize mode required, but it is not "
44 "allowed in this context")));
45
46 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
47 oldcontext = MemoryContextSwitchTo(per_query_ctx);
48
49 /* get the requested return tuple description */
50 tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
51
52 /*
53 * Check to make sure we have a reasonable tuple descriptor
54 */
55 if (tupdesc->natts != 2 ||
56 TupleDescAttr(tupdesc, 0)->atttypid != TEXTOID ||
57 TupleDescAttr(tupdesc, 1)->atttypid != TEXTOID)
58 ereport(ERROR,
59 (errcode(ERRCODE_SYNTAX_ERROR),
60 errmsg("query-specified return tuple and "
61 "function return type are not compatible")));
62
63 /* OK to use it */
64 attinmeta = TupleDescGetAttInMetadata(tupdesc);
65
66 /* let the caller know we're sending back a tuplestore */
67 rsinfo->returnMode = SFRM_Materialize;
68
69 /* initialize our tuplestore */
70 tupstore = tuplestore_begin_heap(true, false, work_mem);
71
72 configdata = get_configdata(my_exec_path, &configdata_len);
73 for (i = 0; i < configdata_len; i++)
74 {
75 values[0] = configdata[i].name;
76 values[1] = configdata[i].setting;
77
78 tuple = BuildTupleFromCStrings(attinmeta, values);
79 tuplestore_puttuple(tupstore, tuple);
80 }
81
82 /*
83 * no longer need the tuple descriptor reference created by
84 * TupleDescGetAttInMetadata()
85 */
86 ReleaseTupleDesc(tupdesc);
87
88 tuplestore_donestoring(tupstore);
89 rsinfo->setResult = tupstore;
90
91 /*
92 * SFRM_Materialize mode expects us to return a NULL Datum. The actual
93 * tuples are in our tuplestore and passed back through rsinfo->setResult.
94 * rsinfo->setDesc is set to the tuple description that we actually used
95 * to build our tuples with, so the caller can verify we did what it was
96 * expecting.
97 */
98 rsinfo->setDesc = tupdesc;
99 MemoryContextSwitchTo(oldcontext);
100
101 return (Datum) 0;
102 }
103