-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 08/20/2015 07:54 AM, Joe Conway wrote: > On 08/20/2015 06:59 AM, Andrew Dunstan wrote: >> I was a bit interested in pg_config information, for this reason: >> I had a report of someone who had configured using --with-libxml >> but the xml tests actually returned the results that are expected >> without xml being configured. The regression tests thus passed, >> but should not have. It occurred to me that if we had a test >> like > >> select pg_config('configure') ~ '--with-libxml' as has_xml; > >> in the xml tests then this failure mode would be detected. > > I've found use for them both in the past. A fair amount of bit-rot > has set it no doubt, and these were quick and dirty to begin with, > but I have these hacks from a while back: > > https://github.com/jconway/pg_config
The attached implements pg_config as a backend SRF and a matching system view. A few notes: 1) The syntax is a bit different than what Andrew proposed: 8<---------------- select setting ~ '--with-libxml' as has_xml from pg_config where name = 'CONFIGURE'; has_xml - --------- t (1 row) 8<---------------- In particular note that the name values are all upper case to be consistent with pg_config, and at least currently there is no version of the function which accepts a name as an argument (didn't seem worthwhile to me). 2) No docs or related regression test yet. I will do that if there is enough interest in this getting committed. So far no one except Andrew and I have chimed in. 3) Requires a catalog version bump (not in posted diff) 4) The static function cleanup_path() was borrowed from src/bin/pg_config/pg_config.c It is a small and stable function (no change since 2010 AFAICS), so maybe not worth the effort, but I was wondering if it should be moved to src/common somewhere and shared. I will add this to the next commitfest. Comments/feedback encouraged. Joe - -- Crunchy Data - http://crunchydata.com PostgreSQL Support for Secure Enterprises Consulting, Training, & Open Source Development -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAEBAgAGBQJV2PykAAoJEDfy90M199hlQW0P/1fLCtFe50wFanleOxo41aki yR8uG5vUZCLosx7lYd4+LyeE2g+bfs+fK6XgL1qIafI0zyxQSAU8TtjsIPQjjsvU rNn1MWRrlOLEfOMMzbJPo01w5wzLhBvFzrYQ8vVtvf+T2PzjbU1hTMOcmaeXv6If jYv0KQDgPBk/VPZ0D7MI4nYXVzNSInDLD7TGEpoTQwZ0oqvZwScSXc933isoULB4 4isael+g6mQJNoPz+OQEhUSoC922mrGs12SarfHJiUqJs1/NleClRRZ/9llCBnb2 3+zW6cb4XNh8aVP33zTtCsbrio206VjumWUYMNs546+qChormBOnYtZiIVRNRnPk z4x/vxuhXVndDp1VnE5V5mRiW3B8ABliBf1Bcnf/Z+Gxi84LaZVtmL2hJrmn7voT EZsQn/gmpB6ThHKbOl3t060fGZ/RAPDUwOWoYUIVcohOQqxK/iIka0bFM5cnuXO0 8oJ7CFkPSW7kBPs3uPO4Psf/jzrfaK3b/ZfitoV77sMQiVCABlR3a8khw+cPBrok av/1afnGfz6qSxsV8sAyKUmRZkLDtmT01GUHCuujof1PQ3tD8zVsQWI3r51UcGB3 tFKvvy9koTHEunqkU6yQrCWNOEzHpGXEa1RIV33Ywgh0deKVEU5EbfJF5iIHBgOy dYf2PHbYW7F1RSqKnZIa =A2+X -----END PGP SIGNATURE-----
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index ccc030f..0d2e8f1 100644 *** a/src/backend/catalog/system_views.sql --- b/src/backend/catalog/system_views.sql *************** CREATE VIEW pg_timezone_abbrevs AS *** 425,430 **** --- 425,433 ---- CREATE VIEW pg_timezone_names AS SELECT * FROM pg_timezone_names(); + CREATE VIEW pg_config AS + SELECT * FROM pg_config(); + -- Statistics views CREATE VIEW pg_stat_all_tables AS diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile index 7889101..49c6f08 100644 *** a/src/backend/utils/misc/Makefile --- b/src/backend/utils/misc/Makefile *************** include $(top_builddir)/src/Makefile.glo *** 14,20 **** 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 # This location might depend on the installation directories. Therefore --- 14,33 ---- override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) ! # 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 = 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 diff --git a/src/backend/utils/misc/pg_config.c b/src/backend/utils/misc/pg_config.c index ...aa3349d . *** a/src/backend/utils/misc/pg_config.c --- b/src/backend/utils/misc/pg_config.c *************** *** 0 **** --- 1,312 ---- + /*------------------------------------------------------------------------- + * + * pg_config.c + * Expose same output as pg_config except as an SRF + * + * Copyright (c) 2015, PostgreSQL Global Development Group + * ALL RIGHTS RESERVED; + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without a written agreement + * is hereby granted, provided that the above copyright notice and this + * paragraph and the following two paragraphs appear in all copies. + * + * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING + * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS + * DOCUMENTATION, EVEN IF THE AUTHOR OR DISTRIBUTORS HAVE BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAS NO OBLIGATIONS TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + */ + + #include "postgres.h" + + #include "funcapi.h" + #include "miscadmin.h" + #include "catalog/pg_type.h" + #include "utils/elog.h" + #include "port.h" + + static void cleanup_path(char *path); + static void get_configdata(void); + + #ifdef PGDLLIMPORT + /* Postgres global */ + extern PGDLLIMPORT char my_exec_path[]; + #else + /* Postgres global */ + extern DLLIMPORT char my_exec_path[]; + #endif /* PGDLLIMPORT */ + + struct configdata + { + char *name; + char *setting; + }; + + static struct configdata ConfigData[] = + { + {"BINDIR", NULL}, + {"DOCDIR", NULL}, + {"HTMLDIR", NULL}, + {"INCLUDEDIR", NULL}, + {"PKGINCLUDEDIR", NULL}, + {"INCLUDEDIR-SERVER", NULL}, + {"LIBDIR", NULL}, + {"PKGLIBDIR", NULL}, + {"LOCALEDIR", NULL}, + {"MANDIR", NULL}, + {"SHAREDIR", NULL}, + {"SYSCONFDIR", NULL}, + {"PGXS", NULL}, + {"CONFIGURE", NULL}, + {"CC", NULL}, + {"CPPFLAGS", NULL}, + {"CFLAGS", NULL}, + {"CFLAGS_SL", NULL}, + {"LDFLAGS", NULL}, + {"LDFLAGS_EX", NULL}, + {"LDFLAGS_SL", NULL}, + {"LIBS", NULL}, + {"VERSION", NULL}, + {NULL, NULL} + }; + + static void get_configdata(void); + + Datum pg_config(PG_FUNCTION_ARGS); + + PG_FUNCTION_INFO_V1(pg_config); + 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; + 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); + + get_configdata(); + while (ConfigData[i].name) + { + values[0] = ConfigData[i].name; + values[1] = ConfigData[i].setting; + + tuple = BuildTupleFromCStrings(attinmeta, values); + tuplestore_puttuple(tupstore, tuple); + ++i; + } + + /* + * 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; + } + + + /* + * 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 + } + + static void + get_configdata(void) + { + char path[MAXPGPATH]; + char *lastsep; + + 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); + } diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index ddf7c67..e375059 100644 *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** DESCR("get an individual replication ori *** 5331,5336 **** --- 5331,5340 ---- DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ )); DESCR("get progress for all replication origins"); + /* pg_config */ + DATA(insert OID = 3300 ( pg_config PGNSP PGUID 12 1 1000 0 0 f f f f t t i 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/utils/builtins.h b/src/include/utils/builtins.h index fc1679e..edd69f8 100644 *** a/src/include/utils/builtins.h --- b/src/include/utils/builtins.h *************** extern Datum set_config_by_name(PG_FUNCT *** 1121,1126 **** --- 1121,1129 ---- 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/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 44c6740..b4e7511 100644 *** a/src/test/regress/expected/rules.out --- b/src/test/regress/expected/rules.out *************** pg_available_extensions| SELECT e.name, *** 1305,1310 **** --- 1305,1313 ---- 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,
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers