2016-02-17 18:12:06 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* pg_config.c
|
|
|
|
* Expose same output as pg_config except as an SRF
|
|
|
|
*
|
|
|
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/backend/utils/misc/pg_config.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "funcapi.h"
|
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "common/config_info.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/elog.h"
|
|
|
|
#include "port.h"
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_config(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2016-06-10 00:02:36 +02:00
|
|
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
Tuplestorestate *tupstore;
|
|
|
|
HeapTuple tuple;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
AttInMetadata *attinmeta;
|
|
|
|
MemoryContext per_query_ctx;
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
ConfigData *configdata;
|
|
|
|
size_t configdata_len;
|
|
|
|
char *values[2];
|
|
|
|
int i = 0;
|
2016-02-17 18:12:06 +01:00
|
|
|
|
|
|
|
/* check to see if caller supports us returning a tuplestore */
|
|
|
|
if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("materialize mode required, but it is not "
|
|
|
|
"allowed in this context")));
|
|
|
|
|
|
|
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
|
|
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
|
|
|
|
|
|
|
/* get the requested return tuple description */
|
|
|
|
tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to make sure we have a reasonable tuple descriptor
|
|
|
|
*/
|
|
|
|
if (tupdesc->natts != 2 ||
|
|
|
|
tupdesc->attrs[0]->atttypid != TEXTOID ||
|
|
|
|
tupdesc->attrs[1]->atttypid != TEXTOID)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("query-specified return tuple and "
|
|
|
|
"function return type are not compatible")));
|
|
|
|
|
|
|
|
/* OK to use it */
|
|
|
|
attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
|
|
|
|
|
|
|
/* let the caller know we're sending back a tuplestore */
|
|
|
|
rsinfo->returnMode = SFRM_Materialize;
|
|
|
|
|
|
|
|
/* initialize our tuplestore */
|
|
|
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
|
|
|
|
|
|
|
configdata = get_configdata(my_exec_path, &configdata_len);
|
|
|
|
for (i = 0; i < configdata_len; i++)
|
|
|
|
{
|
|
|
|
values[0] = configdata[i].name;
|
|
|
|
values[1] = configdata[i].setting;
|
|
|
|
|
|
|
|
tuple = BuildTupleFromCStrings(attinmeta, values);
|
|
|
|
tuplestore_puttuple(tupstore, tuple);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* no longer need the tuple descriptor reference created by
|
|
|
|
* TupleDescGetAttInMetadata()
|
|
|
|
*/
|
|
|
|
ReleaseTupleDesc(tupdesc);
|
|
|
|
|
|
|
|
tuplestore_donestoring(tupstore);
|
|
|
|
rsinfo->setResult = tupstore;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
|
2016-06-10 00:02:36 +02:00
|
|
|
* tuples are in our tuplestore and passed back through rsinfo->setResult.
|
|
|
|
* rsinfo->setDesc is set to the tuple description that we actually used
|
|
|
|
* to build our tuples with, so the caller can verify we did what it was
|
|
|
|
* expecting.
|
2016-02-17 18:12:06 +01:00
|
|
|
*/
|
|
|
|
rsinfo->setDesc = tupdesc;
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
return (Datum) 0;
|
|
|
|
}
|