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