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