On 01/20/2016 08:08 PM, Michael Paquier wrote:
> On Wed, Jan 20, 2016 at 2:32 AM, Joe Conway <m...@joeconway.com> wrote:
>> The only things I know of still lacking is:
>> 1) Documentation

Done and included in the attached.

>> 2) Decision on REVOKE ... FROM PUBLIC
> 
> Yep, regarding 2) I am the only one actually making noise to protect
> this information by default, against at least 2 committers :)

I plan to commit this way -- if the decision is made to remove the two
REVOKEs it can always be done later, but I see no problem with it.

> +typedef struct configdata
> +{
> +       char       *name;
> +       char       *setting;
> +} configdata;
> For a better analogy to ControlFileData, this could be renamed ConfigData?

Well I was already using ConfigData as the variable name, but after some
review it seems better your way, so I made the struct ConfigData and the
variable configdata.

> The point of the move to src/common is to remove the duplication in
> src/bin/pg_config/Makefile.

check

> All the files in src/common should begin their include declarations with that:
> #ifndef FRONTEND
> #include "postgres.h"
> #else
> #include "postgres_fe.h"
> #endif

check

> +configdata *
> +get_configdata(char *my_exec_path, size_t *configdata_len)
> +{
> It may be good to mention that the result is palloc'd and that caller
> may need to free it if necessary. It does not matter in the two code
> paths of this patch, but it may matter for other users calling that.

check

I believe this takes care of all open issues with this, so I plan to
commit it as attached in a day or two. Thanks for your reviews and comments!

Joe

-- 
Crunchy Data - http://crunchydata.com
PostgreSQL Support for Secure Enterprises
Consulting, Training, & Open Source Development
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 412c845..6c50f79 100644
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 7350,7355 ****
--- 7350,7360 ----
       </row>
  
       <row>
+       <entry><link linkend="view-pg-config"><structname>pg_config</structname></link></entry>
+       <entry>compile-time configuration parameters</entry>
+      </row>
+ 
+      <row>
        <entry><link linkend="view-pg-cursors"><structname>pg_cursors</structname></link></entry>
        <entry>open cursors</entry>
       </row>
***************
*** 7609,7614 ****
--- 7614,7667 ----
    </para>
   </sect1>
  
+  <sect1 id="view-pg-config">
+   <title><structname>pg_config</structname></title>
+ 
+   <indexterm zone="view-pg-config">
+    <primary>pg_config</primary>
+   </indexterm>
+ 
+   <para>
+    The view <structname>pg_config</structname> 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 <xref linkend="app-pgconfig"> PostgreSQL Client
+    Application. There is a System Information Function
+    (<xref linkend="functions-info">) called <function>pg_config</function>
+    which underlies this view.
+   </para>
+ 
+   <table>
+    <title><structname>pg_config</> Columns</title>
+    <tgroup cols="3">
+     <thead>
+      <row>
+       <entry>Name</entry>
+       <entry>Type</entry>
+       <entry>Description</entry>
+      </row>
+     </thead>
+ 
+     <tbody>
+      <row>
+       <entry><structfield>name</structfield></entry>
+       <entry><type>text</type></entry>
+       <entry>The parameter name</entry>
+      </row>
+ 
+      <row>
+       <entry><structfield>setting</structfield></entry>
+       <entry><type>text</type></entry>
+       <entry>The parameter value</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+ 
+  </sect1>
+ 
   <sect1 id="view-pg-cursors">
    <title><structname>pg_cursors</structname></title>
  
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index f9eea76..29c36d2 100644
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
*************** SELECT * FROM pg_ls_dir('.') WITH ORDINA
*** 15003,15008 ****
--- 15003,15014 ----
        </row>
  
        <row>
+        <entry><literal><function>pg_config()</function></literal></entry>
+        <entry><type>setof record</type></entry>
+        <entry>get list of compile-time configure variable names and their values</entry>
+       </row>
+ 
+       <row>
         <entry><literal><function>pg_is_other_temp_schema(<type>oid</type>)</function></literal></entry>
         <entry><type>boolean</type></entry>
         <entry>is schema another session's temporary schema?</entry>
*************** SET search_path TO <replaceable>schema</
*** 15245,15250 ****
--- 15251,15273 ----
     </para>
  
     <indexterm>
+     <primary>pg_config</primary>
+    </indexterm>
+ 
+    <para>
+     <function>pg_config</function> returns a set of records describing 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. The
+     <structfield>name</> column contains the parameter name.
+     The <structfield>setting</> column contains the parameter value. It
+     provides the same basic information as the
+     <xref linkend="app-pgconfig"> PostgreSQL Client Application. There
+     is also a <xref linkend="view-pg-config"> system view.
+    </para>
+ 
+    <indexterm>
      <primary>version</primary>
     </indexterm>
  
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 923fe58..abf9a70 100644
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
*************** CREATE VIEW pg_timezone_abbrevs AS
*** 433,438 ****
--- 433,444 ----
  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 7889101..a0c82c1 100644
*** a/src/backend/utils/misc/Makefile
--- b/src/backend/utils/misc/Makefile
*************** include $(top_builddir)/src/Makefile.glo
*** 14,21 ****
  
  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
  # we can't subsitute it into pg_config.h.
--- 14,21 ----
  
  override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
  
! 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
index ...a74e97d .
*** a/src/backend/utils/misc/pg_config.c
--- b/src/backend/utils/misc/pg_config.c
***************
*** 0 ****
--- 1,102 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_config.c
+  *		Expose same output as pg_config except as an SRF
+  *
+  * Portions Copyright (c) 1996-2015, 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 812c4a1..26fbaad 100644
*** a/src/bin/pg_config/Makefile
--- b/src/bin/pg_config/Makefile
*************** include $(top_builddir)/src/Makefile.glo
*** 17,36 ****
  
  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
--- 17,22 ----
diff --git a/src/bin/pg_config/pg_config.c b/src/bin/pg_config/pg_config.c
index 4b14294..23c0495 100644
*** a/src/bin/pg_config/pg_config.c
--- b/src/bin/pg_config/pg_config.c
***************
*** 25,387 ****
  #include "postgres_fe.h"
  
  #include "port.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
--- 25,33 ----
  #include "postgres_fe.h"
  
  #include "port.h"
+ #include "common/config_info.h"
  
  static const char *progname;
  
  /*
   * Table of known information items
*************** show_version(bool all)
*** 391,423 ****
  typedef struct
  {
  	const char *switchname;
! 	void		(*show_func) (bool all);
  } 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},
  	{NULL, NULL}
  };
  
--- 37,69 ----
  typedef struct
  {
  	const char *switchname;
! 	const char *configname;
  } InfoItem;
  
  static const InfoItem info_items[] = {
! 	{"--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}
  };
  
*************** advice(void)
*** 466,487 ****
  }
  
  static void
! show_all(void)
  {
  	int			i;
  
! 	for (i = 0; info_items[i].switchname != NULL; i++)
  	{
! 		(*info_items[i].show_func) (true);
  	}
  }
  
  int
  main(int argc, char **argv)
  {
  	int			i;
  	int			j;
- 	int			ret;
  
  	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_config"));
  
--- 112,138 ----
  }
  
  static void
! show_item(const char *configname,
! 		  ConfigData *configdata,
! 		  size_t configdata_len)
  {
  	int			i;
  
! 	for (i = 0; i < configdata_len; i++)
  	{
! 		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;
  
  	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_config"));
  
*************** main(int argc, char **argv)
*** 497,524 ****
  		}
  	}
  
! 	ret = find_my_exec(argv[0], mypath);
! 
! 	if (ret)
  	{
  		fprintf(stderr, _("%s: could not find own program executable\n"), progname);
  		exit(1);
  	}
  
  	/* no arguments -> print everything */
  	if (argc < 2)
  	{
! 		show_all();
  		exit(0);
  	}
  
  	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);
  				break;
  			}
  		}
--- 148,177 ----
  		}
  	}
  
! 	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)
  	{
! 		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)
  			{
! 				show_item(info_items[j].configname,
! 						  configdata, configdata_len);
  				break;
  			}
  		}
diff --git a/src/common/Makefile b/src/common/Makefile
index c47445e..ab183cf 100644
*** a/src/common/Makefile
--- b/src/common/Makefile
*************** include $(top_builddir)/src/Makefile.glo
*** 23,30 ****
  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
  
  OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o restricted_token.o
  
--- 23,43 ----
  override CPPFLAGS := -DFRONTEND $(CPPFLAGS)
  LIBS += $(PTHREAD_LIBS)
  
! # 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 = exec.o config_info.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
  
*************** libpgcommon_srv.a: $(OBJS_SRV)
*** 61,67 ****
  # 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 $@
  
  $(OBJS_SRV): | submake-errcodes
  
--- 74,80 ----
  # 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 $@
  
  $(OBJS_SRV): | submake-errcodes
  
diff --git a/src/common/config_info.c b/src/common/config_info.c
index ...1e3c6db .
*** a/src/common/config_info.c
--- b/src/common/config_info.c
***************
*** 0 ****
--- 1,206 ----
+ /*-------------------------------------------------------------------------
+  *
+  * config_info.c
+  *		Common code for pg_config output
+  *
+  *
+  * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *	  src/common/controldata_utils.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/pg_proc.h b/src/include/catalog/pg_proc.h
index 1c0ef9a..f4c9572 100644
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("get an individual replication ori
*** 5202,5207 ****
--- 5202,5210 ----
  DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v r 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 = 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
diff --git a/src/include/common/config_info.h b/src/include/common/config_info.h
index ...488fcf1 .
*** a/src/include/common/config_info.h
--- b/src/include/common/config_info.h
***************
*** 0 ****
--- 1,21 ----
+ /*
+  * controldata_utils.h
+  *		Common code for pg_controldata output
+  *
+  *	Copyright (c) 2016, PostgreSQL Global Development Group
+  *
+  *	src/include/common/controldata_utils.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 9fc79f4..cb13dd8 100644
*** a/src/include/port.h
--- b/src/include/port.h
*************** extern void join_path_components(char *r
*** 42,47 ****
--- 42,48 ----
  					 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 affcc01..a784de9 100644
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
*************** extern Datum set_config_by_name(PG_FUNCT
*** 1147,1152 ****
--- 1147,1155 ----
  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 a418f93..5c9de0c 100644
*** a/src/port/path.c
--- b/src/port/path.c
*************** make_native_path(char *filename)
*** 172,177 ****
--- 172,207 ----
  
  
  /*
+  * 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
   *
   * We omit the slash if either given component is empty.
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 2bdba2d..81bc5c9 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,
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 1dba7d9..cc0dcb3 100644
*** a/src/tools/msvc/Mkvcbuild.pm
--- b/src/tools/msvc/Mkvcbuild.pm
*************** sub mkvcbuild
*** 106,113 ****
  	}
  
  	our @pgcommonallfiles = qw(
! 	  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
--- 106,113 ----
  	}
  
  	our @pgcommonallfiles = qw(
! 	  exec.c config_info.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

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to