mirror of https://github.com/postgres/postgres
Move and refactor the underlying code for the pg_config client application to src/common in support of sharing it with a new system information SRF called pg_config() which makes the same information available via SQL. Additionally wrap the SRF with a new system view, as called pg_config. Patch by me with extensive input and review by Michael Paquier and additional review by Alvaro Herrera.pull/10/merge
parent
f1f5ec1efa
commit
a5c43b8869
@ -0,0 +1,103 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* 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) |
||||||
|
{ |
||||||
|
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; |
||||||
|
|
||||||
|
/* 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 |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
rsinfo->setDesc = tupdesc; |
||||||
|
MemoryContextSwitchTo(oldcontext); |
||||||
|
|
||||||
|
return (Datum) 0; |
||||||
|
} |
@ -0,0 +1,206 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* config_info.c |
||||||
|
* Common code for pg_config output |
||||||
|
* |
||||||
|
* |
||||||
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California |
||||||
|
* |
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* src/common/config_info.c |
||||||
|
* |
||||||
|
*------------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef FRONTEND |
||||||
|
#include "postgres.h" |
||||||
|
#else |
||||||
|
#include "postgres_fe.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "miscadmin.h" |
||||||
|
#include "common/config_info.h" |
||||||
|
|
||||||
|
static size_t configdata_names_len(void); |
||||||
|
|
||||||
|
static const char *const configdata_names[] = |
||||||
|
{ |
||||||
|
"BINDIR", |
||||||
|
"DOCDIR", |
||||||
|
"HTMLDIR", |
||||||
|
"INCLUDEDIR", |
||||||
|
"PKGINCLUDEDIR", |
||||||
|
"INCLUDEDIR-SERVER", |
||||||
|
"LIBDIR", |
||||||
|
"PKGLIBDIR", |
||||||
|
"LOCALEDIR", |
||||||
|
"MANDIR", |
||||||
|
"SHAREDIR", |
||||||
|
"SYSCONFDIR", |
||||||
|
"PGXS", |
||||||
|
"CONFIGURE", |
||||||
|
"CC", |
||||||
|
"CPPFLAGS", |
||||||
|
"CFLAGS", |
||||||
|
"CFLAGS_SL", |
||||||
|
"LDFLAGS", |
||||||
|
"LDFLAGS_EX", |
||||||
|
"LDFLAGS_SL", |
||||||
|
"LIBS", |
||||||
|
"VERSION", |
||||||
|
NULL |
||||||
|
}; |
||||||
|
|
||||||
|
static size_t |
||||||
|
configdata_names_len(void) |
||||||
|
{ |
||||||
|
size_t i = 0; |
||||||
|
|
||||||
|
while (configdata_names[i]) |
||||||
|
i++; |
||||||
|
|
||||||
|
return i; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* get_configdata(char *my_exec_path, size_t *configdata_len) |
||||||
|
* |
||||||
|
* Get configure-time constants. The caller is responsible |
||||||
|
* for pfreeing the result. |
||||||
|
*/ |
||||||
|
ConfigData * |
||||||
|
get_configdata(char *my_exec_path, size_t *configdata_len) |
||||||
|
{ |
||||||
|
ConfigData *configdata; |
||||||
|
char path[MAXPGPATH]; |
||||||
|
char *lastsep; |
||||||
|
int i; |
||||||
|
|
||||||
|
*configdata_len = configdata_names_len(); |
||||||
|
configdata = palloc(*configdata_len * sizeof(ConfigData)); |
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize configdata names |
||||||
|
* |
||||||
|
* These better be in sync with the settings manually |
||||||
|
* defined below. |
||||||
|
*/ |
||||||
|
for (i = 0; i < *configdata_len; i++) |
||||||
|
configdata[i].name = pstrdup(configdata_names[i]); |
||||||
|
|
||||||
|
strcpy(path, my_exec_path); |
||||||
|
lastsep = strrchr(path, '/'); |
||||||
|
if (lastsep) |
||||||
|
*lastsep = '\0'; |
||||||
|
cleanup_path(path); |
||||||
|
configdata[0].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_doc_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[1].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_html_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[2].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_include_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[3].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_pkginclude_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[4].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_includeserver_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[5].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_lib_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[6].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_pkglib_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[7].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_locale_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[8].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_man_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[9].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_share_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[10].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_etc_path(my_exec_path, path); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[11].setting = pstrdup(path); |
||||||
|
|
||||||
|
get_pkglib_path(my_exec_path, path); |
||||||
|
strlcat(path, "/pgxs/src/makefiles/pgxs.mk", sizeof(path)); |
||||||
|
cleanup_path(path); |
||||||
|
configdata[12].setting = pstrdup(path); |
||||||
|
|
||||||
|
#ifdef VAL_CONFIGURE |
||||||
|
configdata[13].setting = pstrdup(VAL_CONFIGURE); |
||||||
|
#else |
||||||
|
configdata[13].setting = pstrdup(_("not recorded")); |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef VAL_CC |
||||||
|
configdata[14].setting = pstrdup(VAL_CC); |
||||||
|
#else |
||||||
|
configdata[14].setting = pstrdup(_("not recorded")); |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef VAL_CPPFLAGS |
||||||
|
configdata[15].setting = pstrdup(VAL_CPPFLAGS); |
||||||
|
#else |
||||||
|
configdata[15].setting = pstrdup(_("not recorded")); |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef VAL_CFLAGS |
||||||
|
configdata[16].setting = pstrdup(VAL_CFLAGS); |
||||||
|
#else |
||||||
|
configdata[16].setting = pstrdup(_("not recorded")); |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef VAL_CFLAGS_SL |
||||||
|
configdata[17].setting = pstrdup(VAL_CFLAGS_SL); |
||||||
|
#else |
||||||
|
configdata[17].setting = pstrdup(_("not recorded")); |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef VAL_LDFLAGS |
||||||
|
configdata[18].setting = pstrdup(VAL_LDFLAGS); |
||||||
|
#else |
||||||
|
configdata[18].setting = pstrdup(_("not recorded")); |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef VAL_LDFLAGS_EX |
||||||
|
configdata[19].setting = pstrdup(VAL_LDFLAGS_EX); |
||||||
|
#else |
||||||
|
configdata[19].setting = pstrdup(_("not recorded")); |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef VAL_LDFLAGS_SL |
||||||
|
configdata[20].setting = pstrdup(VAL_LDFLAGS_SL); |
||||||
|
#else |
||||||
|
configdata[20].setting = pstrdup(_("not recorded")); |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef VAL_LIBS |
||||||
|
configdata[21].setting = pstrdup(VAL_LIBS); |
||||||
|
#else |
||||||
|
configdata[21].setting = pstrdup(_("not recorded")); |
||||||
|
#endif |
||||||
|
|
||||||
|
configdata[22].setting = pstrdup("PostgreSQL " PG_VERSION); |
||||||
|
|
||||||
|
return configdata; |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
/*
|
||||||
|
* config_info.h |
||||||
|
* Common code for pg_config output |
||||||
|
* |
||||||
|
* Copyright (c) 2016, PostgreSQL Global Development Group |
||||||
|
* |
||||||
|
* src/include/common/config_info.h |
||||||
|
*/ |
||||||
|
#ifndef COMMON_CONFIG_INFO_H |
||||||
|
#define COMMON_CONFIG_INFO_H |
||||||
|
|
||||||
|
typedef struct ConfigData |
||||||
|
{ |
||||||
|
char *name; |
||||||
|
char *setting; |
||||||
|
} ConfigData; |
||||||
|
|
||||||
|
extern ConfigData *get_configdata(char *my_exec_path, |
||||||
|
size_t *configdata_len); |
||||||
|
|
||||||
|
#endif /* COMMON_CONFIG_INFO_H */ |
Loading…
Reference in new issue