Line data Source code
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
26 1 : pg_config(PG_FUNCTION_ARGS)
27 : {
28 1 : 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 1 : int i = 0;
39 :
40 : /* check to see if caller supports us returning a tuplestore */
41 1 : if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
42 0 : ereport(ERROR,
43 : (errcode(ERRCODE_SYNTAX_ERROR),
44 : errmsg("materialize mode required, but it is not "
45 : "allowed in this context")));
46 :
47 1 : per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
48 1 : oldcontext = MemoryContextSwitchTo(per_query_ctx);
49 :
50 : /* get the requested return tuple description */
51 1 : tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
52 :
53 : /*
54 : * Check to make sure we have a reasonable tuple descriptor
55 : */
56 2 : if (tupdesc->natts != 2 ||
57 2 : TupleDescAttr(tupdesc, 0)->atttypid != TEXTOID ||
58 1 : TupleDescAttr(tupdesc, 1)->atttypid != TEXTOID)
59 0 : 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 1 : attinmeta = TupleDescGetAttInMetadata(tupdesc);
66 :
67 : /* let the caller know we're sending back a tuplestore */
68 1 : rsinfo->returnMode = SFRM_Materialize;
69 :
70 : /* initialize our tuplestore */
71 1 : tupstore = tuplestore_begin_heap(true, false, work_mem);
72 :
73 1 : configdata = get_configdata(my_exec_path, &configdata_len);
74 24 : for (i = 0; i < configdata_len; i++)
75 : {
76 23 : values[0] = configdata[i].name;
77 23 : values[1] = configdata[i].setting;
78 :
79 23 : tuple = BuildTupleFromCStrings(attinmeta, values);
80 23 : tuplestore_puttuple(tupstore, tuple);
81 : }
82 :
83 : /*
84 : * no longer need the tuple descriptor reference created by
85 : * TupleDescGetAttInMetadata()
86 : */
87 1 : ReleaseTupleDesc(tupdesc);
88 :
89 : tuplestore_donestoring(tupstore);
90 1 : 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 1 : rsinfo->setDesc = tupdesc;
100 1 : MemoryContextSwitchTo(oldcontext);
101 :
102 1 : return (Datum) 0;
103 : }
|