From a5c43b886942e96ec5c745041f2d6a50c3205147 Mon Sep 17 00:00:00 2001 From: Joe Conway Date: Wed, 17 Feb 2016 09:12:06 -0800 Subject: [PATCH] Add new system view, pg_config 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. --- doc/src/sgml/catalogs.sgml | 52 ++++ src/backend/catalog/system_views.sql | 6 + src/backend/utils/misc/Makefile | 4 +- src/backend/utils/misc/pg_config.c | 103 +++++++ src/bin/pg_config/Makefile | 14 - src/bin/pg_config/pg_config.c | 429 +++------------------------ src/common/Makefile | 19 +- src/common/config_info.c | 206 +++++++++++++ src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_proc.h | 4 + src/include/common/config_info.h | 21 ++ src/include/port.h | 1 + src/include/utils/builtins.h | 3 + src/port/path.c | 30 ++ src/test/regress/expected/rules.out | 3 + src/tools/msvc/Mkvcbuild.pm | 4 +- 16 files changed, 491 insertions(+), 410 deletions(-) create mode 100644 src/backend/utils/misc/pg_config.c create mode 100644 src/common/config_info.c create mode 100644 src/include/common/config_info.h diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 412c8450ba..d77e99988f 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -7349,6 +7349,11 @@ available versions of extensions + + pg_config + compile-time configuration parameters + + pg_cursors open cursors @@ -7609,6 +7614,53 @@ + + <structname>pg_config</structname> + + + pg_config + + + + The view pg_config describes the + compile-time configuration parameters of the currently installed + version of PostgreSQL. It is intended, for example, to + be used by software packages that want to interface to + PostgreSQL to facilitate finding the required header + files and libraries. It provides the same basic information as the + PostgreSQL Client + Application. + + + + <structname>pg_config</> Columns + + + + Name + Type + Description + + + + + + name + text + The parameter name + + + + setting + text + The parameter value + + + +
+ +
+ <structname>pg_cursors</structname> diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 923fe589d5..abf9a7007c 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -433,6 +433,12 @@ CREATE VIEW pg_timezone_abbrevs AS CREATE VIEW pg_timezone_names AS SELECT * FROM pg_timezone_names(); +CREATE VIEW pg_config AS + SELECT * FROM pg_config(); + +REVOKE ALL on pg_config FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pg_config() FROM PUBLIC; + -- Statistics views CREATE VIEW pg_stat_all_tables AS diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile index 788910157d..a0c82c1743 100644 --- a/src/backend/utils/misc/Makefile +++ b/src/backend/utils/misc/Makefile @@ -14,8 +14,8 @@ include $(top_builddir)/src/Makefile.global override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) -OBJS = guc.o help_config.o pg_rusage.o ps_status.o rls.o \ - sampling.o superuser.o timeout.o tzparser.o +OBJS = guc.o help_config.o pg_config.o pg_rusage.o \ + ps_status.o rls.o sampling.o superuser.o timeout.o tzparser.o # This location might depend on the installation directories. Therefore # we can't subsitute it into pg_config.h. diff --git a/src/backend/utils/misc/pg_config.c b/src/backend/utils/misc/pg_config.c new file mode 100644 index 0000000000..3d6b9f27c0 --- /dev/null +++ b/src/backend/utils/misc/pg_config.c @@ -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; +} diff --git a/src/bin/pg_config/Makefile b/src/bin/pg_config/Makefile index 812c4a1875..26fbaadadd 100644 --- a/src/bin/pg_config/Makefile +++ b/src/bin/pg_config/Makefile @@ -17,20 +17,6 @@ include $(top_builddir)/src/Makefile.global OBJS= pg_config.o $(WIN32RES) -# don't include subdirectory-path-dependent -I and -L switches -STD_CPPFLAGS := $(filter-out -I$(top_srcdir)/src/include -I$(top_builddir)/src/include,$(CPPFLAGS)) -STD_LDFLAGS := $(filter-out -L$(top_builddir)/src/port,$(LDFLAGS)) - -override CPPFLAGS += -DVAL_CONFIGURE="\"$(configure_args)\"" -override CPPFLAGS += -DVAL_CC="\"$(CC)\"" -override CPPFLAGS += -DVAL_CPPFLAGS="\"$(STD_CPPFLAGS)\"" -override CPPFLAGS += -DVAL_CFLAGS="\"$(CFLAGS)\"" -override CPPFLAGS += -DVAL_CFLAGS_SL="\"$(CFLAGS_SL)\"" -override CPPFLAGS += -DVAL_LDFLAGS="\"$(STD_LDFLAGS)\"" -override CPPFLAGS += -DVAL_LDFLAGS_EX="\"$(LDFLAGS_EX)\"" -override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\"" -override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\"" - all: pg_config pg_config: $(OBJS) | submake-libpgport diff --git a/src/bin/pg_config/pg_config.c b/src/bin/pg_config/pg_config.c index 4b1429405c..23c04957be 100644 --- a/src/bin/pg_config/pg_config.c +++ b/src/bin/pg_config/pg_config.c @@ -25,363 +25,9 @@ #include "postgres_fe.h" #include "port.h" +#include "common/config_info.h" static const char *progname; -static char mypath[MAXPGPATH]; - - -/* - * This function cleans up the paths for use with either cmd.exe or Msys - * on Windows. We need them to use filenames without spaces, for which a - * short filename is the safest equivalent, eg: - * C:/Progra~1/ - */ -static void -cleanup_path(char *path) -{ -#ifdef WIN32 - char *ptr; - - /* - * GetShortPathName() will fail if the path does not exist, or short names - * are disabled on this file system. In both cases, we just return the - * original path. This is particularly useful for --sysconfdir, which - * might not exist. - */ - GetShortPathName(path, path, MAXPGPATH - 1); - - /* Replace '\' with '/' */ - for (ptr = path; *ptr; ptr++) - { - if (*ptr == '\\') - *ptr = '/'; - } -#endif -} - - -/* - * For each piece of information known to pg_config, we define a subroutine - * to print it. This is probably overkill, but it avoids code duplication - * and accidentally omitting items from the "all" display. - */ - -static void -show_bindir(bool all) -{ - char path[MAXPGPATH]; - char *lastsep; - - if (all) - printf("BINDIR = "); - /* assume we are located in the bindir */ - strcpy(path, mypath); - lastsep = strrchr(path, '/'); - - if (lastsep) - *lastsep = '\0'; - - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_docdir(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("DOCDIR = "); - get_doc_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_htmldir(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("HTMLDIR = "); - get_html_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_includedir(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("INCLUDEDIR = "); - get_include_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_pkgincludedir(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("PKGINCLUDEDIR = "); - get_pkginclude_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_includedir_server(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("INCLUDEDIR-SERVER = "); - get_includeserver_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_libdir(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("LIBDIR = "); - get_lib_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_pkglibdir(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("PKGLIBDIR = "); - get_pkglib_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_localedir(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("LOCALEDIR = "); - get_locale_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_mandir(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("MANDIR = "); - get_man_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_sharedir(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("SHAREDIR = "); - get_share_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_sysconfdir(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("SYSCONFDIR = "); - get_etc_path(mypath, path); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_pgxs(bool all) -{ - char path[MAXPGPATH]; - - if (all) - printf("PGXS = "); - get_pkglib_path(mypath, path); - strlcat(path, "/pgxs/src/makefiles/pgxs.mk", sizeof(path)); - cleanup_path(path); - printf("%s\n", path); -} - -static void -show_configure(bool all) -{ -#ifdef VAL_CONFIGURE - if (all) - printf("CONFIGURE = "); - printf("%s\n", VAL_CONFIGURE); -#else - if (!all) - { - fprintf(stderr, _("not recorded\n")); - exit(1); - } -#endif -} - -static void -show_cc(bool all) -{ -#ifdef VAL_CC - if (all) - printf("CC = "); - printf("%s\n", VAL_CC); -#else - if (!all) - { - fprintf(stderr, _("not recorded\n")); - exit(1); - } -#endif -} - -static void -show_cppflags(bool all) -{ -#ifdef VAL_CPPFLAGS - if (all) - printf("CPPFLAGS = "); - printf("%s\n", VAL_CPPFLAGS); -#else - if (!all) - { - fprintf(stderr, _("not recorded\n")); - exit(1); - } -#endif -} - -static void -show_cflags(bool all) -{ -#ifdef VAL_CFLAGS - if (all) - printf("CFLAGS = "); - printf("%s\n", VAL_CFLAGS); -#else - if (!all) - { - fprintf(stderr, _("not recorded\n")); - exit(1); - } -#endif -} - -static void -show_cflags_sl(bool all) -{ -#ifdef VAL_CFLAGS_SL - if (all) - printf("CFLAGS_SL = "); - printf("%s\n", VAL_CFLAGS_SL); -#else - if (!all) - { - fprintf(stderr, _("not recorded\n")); - exit(1); - } -#endif -} - -static void -show_ldflags(bool all) -{ -#ifdef VAL_LDFLAGS - if (all) - printf("LDFLAGS = "); - printf("%s\n", VAL_LDFLAGS); -#else - if (!all) - { - fprintf(stderr, _("not recorded\n")); - exit(1); - } -#endif -} - -static void -show_ldflags_ex(bool all) -{ -#ifdef VAL_LDFLAGS_EX - if (all) - printf("LDFLAGS_EX = "); - printf("%s\n", VAL_LDFLAGS_EX); -#else - if (!all) - { - fprintf(stderr, _("not recorded\n")); - exit(1); - } -#endif -} - -static void -show_ldflags_sl(bool all) -{ -#ifdef VAL_LDFLAGS_SL - if (all) - printf("LDFLAGS_SL = "); - printf("%s\n", VAL_LDFLAGS_SL); -#else - if (!all) - { - fprintf(stderr, _("not recorded\n")); - exit(1); - } -#endif -} - -static void -show_libs(bool all) -{ -#ifdef VAL_LIBS - if (all) - printf("LIBS = "); - printf("%s\n", VAL_LIBS); -#else - if (!all) - { - fprintf(stderr, _("not recorded\n")); - exit(1); - } -#endif -} - -static void -show_version(bool all) -{ - if (all) - printf("VERSION = "); - printf("PostgreSQL " PG_VERSION "\n"); -} - /* * Table of known information items @@ -391,33 +37,33 @@ show_version(bool all) typedef struct { const char *switchname; - void (*show_func) (bool all); + const char *configname; } InfoItem; static const InfoItem info_items[] = { - {"--bindir", show_bindir}, - {"--docdir", show_docdir}, - {"--htmldir", show_htmldir}, - {"--includedir", show_includedir}, - {"--pkgincludedir", show_pkgincludedir}, - {"--includedir-server", show_includedir_server}, - {"--libdir", show_libdir}, - {"--pkglibdir", show_pkglibdir}, - {"--localedir", show_localedir}, - {"--mandir", show_mandir}, - {"--sharedir", show_sharedir}, - {"--sysconfdir", show_sysconfdir}, - {"--pgxs", show_pgxs}, - {"--configure", show_configure}, - {"--cc", show_cc}, - {"--cppflags", show_cppflags}, - {"--cflags", show_cflags}, - {"--cflags_sl", show_cflags_sl}, - {"--ldflags", show_ldflags}, - {"--ldflags_ex", show_ldflags_ex}, - {"--ldflags_sl", show_ldflags_sl}, - {"--libs", show_libs}, - {"--version", show_version}, + {"--bindir", "BINDIR"}, + {"--docdir", "DOCDIR"}, + {"--htmldir", "HTMLDIR"}, + {"--includedir", "INCLUDEDIR"}, + {"--pkgincludedir", "PKGINCLUDEDIR"}, + {"--includedir-server", "INCLUDEDIR-SERVER"}, + {"--libdir", "LIBDIR"}, + {"--pkglibdir", "PKGLIBDIR"}, + {"--localedir", "LOCALEDIR"}, + {"--mandir", "MANDIR"}, + {"--sharedir", "SHAREDIR"}, + {"--sysconfdir", "SYSCONFDIR"}, + {"--pgxs", "PGXS"}, + {"--configure", "CONFIGURE"}, + {"--cc", "CC"}, + {"--cppflags", "CPPFLAGS"}, + {"--cflags", "CFLAGS"}, + {"--cflags_sl", "CFLAGS_SL"}, + {"--ldflags", "LDFLAGS"}, + {"--ldflags_ex", "LDFLAGS_EX"}, + {"--ldflags_sl", "LDFLAGS_SL"}, + {"--libs", "LIBS"}, + {"--version", "VERSION"}, {NULL, NULL} }; @@ -466,22 +112,27 @@ advice(void) } static void -show_all(void) +show_item(const char *configname, + ConfigData *configdata, + size_t configdata_len) { int i; - for (i = 0; info_items[i].switchname != NULL; i++) + for (i = 0; i < configdata_len; i++) { - (*info_items[i].show_func) (true); + if (strcmp(configname, configdata[i].name) == 0) + printf("%s = %s\n", configdata[i].name, configdata[i].setting); } } int main(int argc, char **argv) { + ConfigData *configdata; + size_t configdata_len; + char my_exec_path[MAXPGPATH]; int i; int j; - int ret; set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_config")); @@ -497,28 +148,30 @@ main(int argc, char **argv) } } - ret = find_my_exec(argv[0], mypath); - - if (ret) + if (find_my_exec(argv[0], my_exec_path) < 0) { fprintf(stderr, _("%s: could not find own program executable\n"), progname); exit(1); } + configdata = get_configdata(my_exec_path, &configdata_len); /* no arguments -> print everything */ if (argc < 2) { - show_all(); + for (i = 0; i < configdata_len; i++) + printf("%s = %s\n", configdata[i].name, configdata[i].setting); exit(0); } + /* otherwise print requested items */ for (i = 1; i < argc; i++) { for (j = 0; info_items[j].switchname != NULL; j++) { if (strcmp(argv[i], info_items[j].switchname) == 0) { - (*info_items[j].show_func) (false); + show_item(info_items[j].configname, + configdata, configdata_len); break; } } diff --git a/src/common/Makefile b/src/common/Makefile index c47445e768..bde4fc2597 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -23,8 +23,21 @@ include $(top_builddir)/src/Makefile.global override CPPFLAGS := -DFRONTEND $(CPPFLAGS) LIBS += $(PTHREAD_LIBS) -OBJS_COMMON = exec.o pg_lzcompress.o pgfnames.o psprintf.o relpath.o \ - rmtree.o string.o username.o wait_error.o +# don't include subdirectory-path-dependent -I and -L switches +STD_CPPFLAGS := $(filter-out -I$(top_srcdir)/src/include -I$(top_builddir)/src/include,$(CPPFLAGS)) +STD_LDFLAGS := $(filter-out -L$(top_builddir)/src/port,$(LDFLAGS)) +override CPPFLAGS += -DVAL_CONFIGURE="\"$(configure_args)\"" +override CPPFLAGS += -DVAL_CC="\"$(CC)\"" +override CPPFLAGS += -DVAL_CPPFLAGS="\"$(STD_CPPFLAGS)\"" +override CPPFLAGS += -DVAL_CFLAGS="\"$(CFLAGS)\"" +override CPPFLAGS += -DVAL_CFLAGS_SL="\"$(CFLAGS_SL)\"" +override CPPFLAGS += -DVAL_LDFLAGS="\"$(STD_LDFLAGS)\"" +override CPPFLAGS += -DVAL_LDFLAGS_EX="\"$(LDFLAGS_EX)\"" +override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\"" +override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\"" + +OBJS_COMMON = config_info.o exec.o pg_lzcompress.o pgfnames.o psprintf.o \ + relpath.o rmtree.o string.o username.o wait_error.o OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o restricted_token.o @@ -61,7 +74,7 @@ libpgcommon_srv.a: $(OBJS_SRV) # a hack that might fail someday if there is a *_srv.o without a # corresponding *.o, but it works for now. %_srv.o: %.c %.o - $(CC) $(CFLAGS) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@ + $(CC) $(CFLAGS) $(subst -DFRONTEND ,, $(CPPFLAGS)) -c $< -o $@ $(OBJS_SRV): | submake-errcodes diff --git a/src/common/config_info.c b/src/common/config_info.c new file mode 100644 index 0000000000..9053a8cbe4 --- /dev/null +++ b/src/common/config_info.c @@ -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; +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 378c40f44d..b4131f9eb4 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201602071 +#define CATALOG_VERSION_NO 201602171 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index b24e434f2c..2222e8fdf1 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -5208,6 +5208,10 @@ DESCR("row security for current context active on table by table oid"); DATA(insert OID = 3299 ( row_security_active PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 16 "25" _null_ _null_ _null_ _null_ _null_ row_security_active_name _null_ _null_ _null_ )); DESCR("row security for current context active on table by table name"); +/* pg_config */ +DATA(insert OID = 3400 ( pg_config PGNSP PGUID 12 1 23 0 0 f f f f t t i r 0 0 2249 "" "{25,25}" "{o,o}" "{name,setting}" _null_ _null_ pg_config _null_ _null_ _null_ )); +DESCR("pg_config binary as a function"); + /* * Symbolic values for provolatile column: these indicate whether the result * of a function is dependent *only* on the values of its explicit arguments, diff --git a/src/include/common/config_info.h b/src/include/common/config_info.h new file mode 100644 index 0000000000..649ef5cf4b --- /dev/null +++ b/src/include/common/config_info.h @@ -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 */ diff --git a/src/include/port.h b/src/include/port.h index 9fc79f413e..cb13dd80c7 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -42,6 +42,7 @@ extern void join_path_components(char *ret_path, const char *head, const char *tail); extern void canonicalize_path(char *path); extern void make_native_path(char *path); +extern void cleanup_path(char *path); extern bool path_contains_parent_reference(const char *path); extern bool path_is_relative_and_below_cwd(const char *path); extern bool path_is_prefix_of_path(const char *path1, const char *path2); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index affcc01a40..a784de9d28 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -1147,6 +1147,9 @@ extern Datum set_config_by_name(PG_FUNCTION_ARGS); extern Datum show_all_settings(PG_FUNCTION_ARGS); extern Datum show_all_file_settings(PG_FUNCTION_ARGS); +/* pg_config.c */ +extern Datum pg_config(PG_FUNCTION_ARGS); + /* rls.c */ extern Datum row_security_active(PG_FUNCTION_ARGS); extern Datum row_security_active_name(PG_FUNCTION_ARGS); diff --git a/src/port/path.c b/src/port/path.c index a418f93896..5c9de0cd33 100644 --- a/src/port/path.c +++ b/src/port/path.c @@ -171,6 +171,36 @@ make_native_path(char *filename) } +/* + * This function cleans up the paths for use with either cmd.exe or Msys + * on Windows. We need them to use filenames without spaces, for which a + * short filename is the safest equivalent, eg: + * C:/Progra~1/ + */ +void +cleanup_path(char *path) +{ +#ifdef WIN32 + char *ptr; + + /* + * GetShortPathName() will fail if the path does not exist, or short names + * are disabled on this file system. In both cases, we just return the + * original path. This is particularly useful for --sysconfdir, which + * might not exist. + */ + GetShortPathName(path, path, MAXPGPATH - 1); + + /* Replace '\' with '/' */ + for (ptr = path; *ptr; ptr++) + { + if (*ptr == '\\') + *ptr = '/'; + } +#endif +} + + /* * join_path_components - join two path components, inserting a slash * diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 2bdba2d1a1..81bc5c9504 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1305,6 +1305,9 @@ pg_available_extensions| SELECT e.name, e.comment FROM (pg_available_extensions() e(name, default_version, comment) LEFT JOIN pg_extension x ON ((e.name = x.extname))); +pg_config| SELECT pg_config.name, + pg_config.setting + FROM pg_config() pg_config(name, setting); pg_cursors| SELECT c.name, c.statement, c.is_holdable, diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 1dba7d9662..e4fb44e639 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -106,8 +106,8 @@ sub mkvcbuild } our @pgcommonallfiles = qw( - exec.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c - string.c username.c wait_error.c); + config_info.c exec.c pg_lzcompress.c pgfnames.c psprintf.c + relpath.c rmtree.c string.c username.c wait_error.c); our @pgcommonfrontendfiles = ( @pgcommonallfiles, qw(fe_memutils.c -- 2.40.0