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