-----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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers