Re: [Fwd: contrib/showguc (was Re: [HACKERS] revised sample

Started by Bruce Momjianover 23 years ago5 messages
#1Bruce Momjian
pgman@candle.pha.pa.us

Your patch has been added to the PostgreSQL unapplied patches list at:

http://candle.pha.pa.us/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------

Joe Conway wrote:

Tom Lane wrote:

Well, we're not doing that; and I see no good reason to make the thing
be a builtin function at all. Since it's just an example, it can very
well be a contrib item with a creation script. Probably *should* be,
in fact, because dynamically created functions are what other people are
going to be building; an example of how to do it as a builtin function
isn't as helpful.

Here is a patch for contrib/showguc. It can serve as a reference
implementation for a C function which returns setof composite. It
required some small changes in guc.c and guc.h so that the number of GUC
variables, and their values, could be accessed. Example usage as shown
below:

test=# select * from show_all_vars() where varname = 'wal_sync_method';
varname | varval
-----------------+-----------
wal_sync_method | fdatasync
(1 row)

test=# select show_var('wal_sync_method');
show_var
-----------
fdatasync
(1 row)

show_var() is neither composite nor set returning, but it seemed like a
worthwhile addition. Please apply if there are no objections.

Thanks,

Joe

Index: contrib/showguc/Makefile
===================================================================
RCS file: contrib/showguc/Makefile
diff -N contrib/showguc/Makefile
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- contrib/showguc/Makefile	27 May 2002 00:24:44 -0000
***************
*** 0 ****
--- 1,9 ----
+ subdir = contrib/showguc
+ top_builddir = ../..
+ include $(top_builddir)/src/Makefile.global
+ 
+ MODULES = showguc
+ DATA_built = showguc.sql
+ DOCS = README.showguc
+ 
+ include $(top_srcdir)/contrib/contrib-global.mk
Index: contrib/showguc/README.showguc
===================================================================
RCS file: contrib/showguc/README.showguc
diff -N contrib/showguc/README.showguc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- contrib/showguc/README.showguc	10 Jun 2002 00:16:48 -0000
***************
*** 0 ****
--- 1,105 ----
+ /*
+  * showguc
+  *
+  * Sample to demonstrate a C function which returns setof composite.
+  * Joe Conway <mail@joeconway.com>
+  *
+  * Copyright 2002 by PostgreSQL Global Development Group
+  *
+  * 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 AUTHORS 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 AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM 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.
+  *
+  */
+ Version 0.1 (9 June, 2002):
+   First release
+ 
+ Release Notes:
+ 
+   Version 0.1
+     - initial release    
+ 
+ Installation:
+   Place these files in a directory called 'showguc' under 'contrib' in the PostgreSQL source tree. Then run:
+ 
+     make
+     make install
+ 
+   You can use showguc.sql to create the functions in your database of choice, e.g.
+ 
+     psql -U postgres template1 < showguc.sql
+ 
+   installs following functions into database template1:
+ 
+      show_all_vars() - returns all GUC variables
+      show_var(text) - returns value of the requested GUC variable
+ 
+ Documentation
+ ==================================================================
+ Name
+ 
+ show_all_vars() - returns all GUC variables
+ 
+ Synopsis
+ 
+ show_all_vars()
+ 
+ Inputs
+ 
+   none
+ 
+ Outputs
+ 
+   Returns setof __gucvar, where __gucvar is (varname TEXT, varval TEXT). All
+     GUC variables displayed by SHOW ALL are returned as a set.
+ 
+ Example usage
+ 
+ test=# select * from show_all_vars() where varname = 'wal_sync_method';
+      varname     |  varval
+ -----------------+-----------
+  wal_sync_method | fdatasync
+ (1 row)
+ 
+ ==================================================================
+ Name
+ 
+ show_var(text varname) - returns value of GUC variable varname
+ 
+ Synopsis
+ 
+ show_var(varname)
+ 
+ Inputs
+ 
+   varname
+     The name of a GUC variable
+ 
+ Outputs
+ 
+   Returns the current value of varname.
+ 
+ Example usage
+ 
+ test=# select show_var('wal_sync_method');
+  show_var
+ -----------
+  fdatasync
+ (1 row)
+ 
+ ==================================================================
+ -- Joe Conway
+ 
Index: contrib/showguc/showguc.c
===================================================================
RCS file: contrib/showguc/showguc.c
diff -N contrib/showguc/showguc.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- contrib/showguc/showguc.c	10 Jun 2002 00:02:14 -0000
***************
*** 0 ****
--- 1,152 ----
+ /*
+  * showguc
+  *
+  * Sample to demonstrate a C function which returns setof composite.
+  * Joe Conway <mail@joeconway.com>
+  *
+  * Copyright 2002 by PostgreSQL Global Development Group
+  *
+  * 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 AUTHORS 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 AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM 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 "fmgr.h"
+ #include "funcapi.h"
+ #include "utils/builtins.h"
+ #include "utils/guc.h"
+ 
+ #include "showguc.h"
+ 
+ /*
+  * showguc_all - equiv to SHOW ALL command but implemented as
+  * an SRF.
+  */
+ PG_FUNCTION_INFO_V1(showguc_all);
+ Datum
+ showguc_all(PG_FUNCTION_ARGS)
+ {
+ 	FuncCallContext	   *funcctx;
+ 	TupleDesc			tupdesc;
+ 	int					call_cntr;
+ 	int					max_calls;
+ 	TupleTableSlot	   *slot;
+ 	AttInMetadata	   *attinmeta;
+ 
+ 	/* stuff done only on the first call of the function */
+  	if(SRF_IS_FIRSTPASS())
+  	{
+ 		/* create a function context for cross-call persistence */
+  		funcctx = SRF_FIRSTCALL_INIT();
+ 
+ 		/*
+ 		 * Build a tuple description for a pg__guc tuple
+ 		 */
+ 		tupdesc = RelationNameGetTupleDesc("__gucvar");
+ 
+ 		/* allocate a slot for a tuple with this tupdesc */
+ 		slot = TupleDescGetSlot(tupdesc);
+ 
+ 		/* assign slot to function context */
+ 		funcctx->slot = slot;
+ 
+ 		/*
+ 		 * Generate attribute metadata needed later to produce tuples from raw
+ 		 * C strings
+ 		 */
+ 		attinmeta = TupleDescGetAttInMetadata(tupdesc);
+ 		funcctx->attinmeta = attinmeta;
+ 
+ 		/* total number of tuples to be returned */
+ 		funcctx->max_calls = GetNumGUCConfigOptions();
+     }
+ 
+ 	/* stuff done on every call of the function */
+  	funcctx = SRF_PERCALL_SETUP(funcctx);
+ 
+ 	call_cntr = funcctx->call_cntr;
+ 	max_calls = funcctx->max_calls;
+ 	slot = funcctx->slot;
+ 	attinmeta = funcctx->attinmeta;
+  
+  	if (call_cntr < max_calls)	/* do when there is more left to send */
+  	{
+ 		char	   *varname;
+ 		char	   *varval;
+ 		char	   **values;
+ 		HeapTuple	tuple;
+ 		Datum		result;
+ 
+ 		/*
+ 		 * Get the next GUC variable name and value
+ 		 */
+ 		varval = GetGUCConfigOptionNum(call_cntr, &varname);
+ 
+ 		/*
+ 		 * Prepare a values array for storage in our slot.
+ 		 * This should be an array of C strings which will
+ 		 * be processed later by the appropriate "in" functions.
+ 		 */
+ 		values = (char **) palloc(2 * sizeof(char *));
+ 		values[0] = varname;
+ 		values[1] = varval;
+ 
+ 		/* build a tuple */
+ 		tuple = BuildTupleFromCStrings(attinmeta, values);
+ 
+ 		/* make the tuple into a datum */
+ 		result = TupleGetDatum(slot, tuple);
+ 
+ 		/* Clean up */
+ 		pfree(varname);
+ 		pfree(values);
+ 
+  		SRF_RETURN_NEXT(funcctx, result);
+  	}
+  	else	/* do when there is no more left */
+  	{
+  		SRF_RETURN_DONE(funcctx);
+  	}
+ }
+ 
+ 
+ /*
+  * showguc_name - equiv to SHOW X command but implemented as
+  * a function.
+  */
+ PG_FUNCTION_INFO_V1(showguc_name);
+ Datum
+ showguc_name(PG_FUNCTION_ARGS)
+ {
+ 	char   *varname;
+ 	char   *varval;
+ 	text   *result_text;
+ 
+ 	/* Get the GUC variable name */
+ 	varname = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
+ 
+ 	/* Get the value */
+ 	varval = GetGUCConfigOptionName(varname);
+ 
+ 	/* Convert to text */
+ 	result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(varval)));
+ 
+ 	/* return it */
+ 	PG_RETURN_TEXT_P(result_text);
+ }
+ 
Index: contrib/showguc/showguc.h
===================================================================
RCS file: contrib/showguc/showguc.h
diff -N contrib/showguc/showguc.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- contrib/showguc/showguc.h	10 Jun 2002 00:01:02 -0000
***************
*** 0 ****
--- 1,37 ----
+ /*
+  * showguc
+  *
+  * Sample to demonstrate a C function which returns setof composite.
+  * Joe Conway <mail@joeconway.com>
+  *
+  * Copyright 2002 by PostgreSQL Global Development Group
+  *
+  * 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 AUTHORS 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 AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM 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.
+  *
+  */
+ 
+ #ifndef SHOWGUC_H
+ #define SHOWGUC_H
+ 
+ /*
+  * External declarations
+  */
+ extern Datum showguc_all(PG_FUNCTION_ARGS);
+ extern Datum showguc_name(PG_FUNCTION_ARGS);
+ 
+ #endif   /* SHOWGUC_H */
Index: contrib/showguc/showguc.sql.in
===================================================================
RCS file: contrib/showguc/showguc.sql.in
diff -N contrib/showguc/showguc.sql.in
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- contrib/showguc/showguc.sql.in	10 Jun 2002 00:03:13 -0000
***************
*** 0 ****
--- 1,10 ----
+ CREATE VIEW __gucvar AS
+   SELECT
+     ''::TEXT AS varname,
+     ''::TEXT AS varval;
+ 
+ CREATE OR REPLACE FUNCTION show_all_vars() RETURNS setof __gucvar
+   AS 'MODULE_PATHNAME','showguc_all' LANGUAGE 'c' STABLE STRICT;
+ 
+ CREATE OR REPLACE FUNCTION show_var(text) RETURNS text
+   AS 'MODULE_PATHNAME','showguc_name' LANGUAGE 'c' STABLE STRICT;
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /opt/src/cvs/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.69
diff -c -r1.69 guc.c
*** src/backend/utils/misc/guc.c	17 May 2002 20:32:29 -0000	1.69
--- src/backend/utils/misc/guc.c	9 Jun 2002 22:51:45 -0000
***************
*** 824,830 ****

static int guc_var_compare(const void *a, const void *b);
! static void _ShowOption(struct config_generic *record);

/*
--- 824,830 ----

static int guc_var_compare(const void *a, const void *b);
! static char *_ShowOption(struct config_generic *record);

/*
***************
*** 2204,2215 ****
ShowGUCConfigOption(const char *name)
{
struct config_generic *record;

record = find_option(name);
if (record == NULL)
elog(ERROR, "Option '%s' is not recognized", name);

! _ShowOption(record);
}

/*
--- 2204,2221 ----
ShowGUCConfigOption(const char *name)
{
struct config_generic *record;
+ 	char *val;

record = find_option(name);
if (record == NULL)
elog(ERROR, "Option '%s' is not recognized", name);

! val = _ShowOption(record);
! if(val != NULL)
! {
! elog(INFO, "%s is %s", record->name, val);
! pfree(val);
! }
}

/*
***************
*** 2219,2239 ****
ShowAllGUCConfig(void)
{
int i;

for (i = 0; i < num_guc_variables; i++)
{
struct config_generic *conf = guc_variables[i];

if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
! _ShowOption(conf);
}
}

! static void
_ShowOption(struct config_generic *record)
{
char buffer[256];
const char *val;

switch (record->vartype)
{
--- 2225,2295 ----
ShowAllGUCConfig(void)
{
int			i;
+ 	char	   *val;

for (i = 0; i < num_guc_variables; i++)
{
struct config_generic *conf = guc_variables[i];

if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
! {
! val = _ShowOption(conf);
! if(val != NULL)
! {
! elog(INFO, "%s is %s", conf->name, val);
! pfree(val);
! }
! }
}
}

! /*
! * Return GUC variable value by name
! */
! char *
! GetGUCConfigOptionName(const char *name)
! {
! struct config_generic *record;
!
! record = find_option(name);
! if (record == NULL)
! elog(ERROR, "Option '%s' is not recognized", name);
!
! return _ShowOption(record);
! }
!
! /*
! * Return GUC variable value and set varname for a specific
! * variable by number.
! */
! char *
! GetGUCConfigOptionNum(int varnum, char **varname)
! {
! struct config_generic *conf = guc_variables[varnum];
!
! *varname = pstrdup(conf->name);
!
! if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
! return _ShowOption(conf);
! else
! return NULL;
! }
!
! /*
! * Return the total number of GUC variables
! */
! int
! GetNumGUCConfigOptions(void)
! {
! return num_guc_variables;
! }
!
! static char *
_ShowOption(struct config_generic *record)
{
char buffer[256];
const char *val;
+ char *retval;

switch (record->vartype)
{
***************
*** 2297,2303 ****
break;
}

! elog(INFO, "%s is %s", record->name, val);
}

--- 2353,2361 ----
break;
}

! retval = pstrdup(val);
!
! return retval;
}

Index: src/include/utils/guc.h
===================================================================
RCS file: /opt/src/cvs/pgsql/src/include/utils/guc.h,v
retrieving revision 1.17
diff -c -r1.17 guc.h
*** src/include/utils/guc.h	17 May 2002 01:19:19 -0000	1.17
--- src/include/utils/guc.h	9 Jun 2002 22:45:20 -0000
***************
*** 86,91 ****
--- 86,94 ----
bool isLocal, bool DoIt);
extern void ShowGUCConfigOption(const char *name);
extern void ShowAllGUCConfig(void);
+ extern char *GetGUCConfigOptionName(const char *name);
+ extern char *GetGUCConfigOptionNum(int varnum, char **varname);
+ extern int GetNumGUCConfigOptions(void);

extern void SetPGVariable(const char *name, List *args, bool is_local);
extern void GetPGVariable(const char *name);

---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

http://www.postgresql.org/users-lounge/docs/faq.html

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
#2Peter Eisentraut
peter_e@gmx.net
In reply to: Bruce Momjian (#1)

OK, I've been looking at this package for some time through various
iterations and I have my doubts about it.

What's going to happen to this when SHOW ALL is changed to return a query
result? If you want to provide an example of a set-returning function,
use something of lasting value, maybe generate some mathematic sequence.

Also, the first place this sort of material should go is the
documentation, not hidden somewhere in contrib.

In any case, please don't expose the name "GUC" to user space.

Bruce Momjian writes:

Your patch has been added to the PostgreSQL unapplied patches list at:

http://candle.pha.pa.us/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------

Joe Conway wrote:

Tom Lane wrote:

Well, we're not doing that; and I see no good reason to make the thing
be a builtin function at all. Since it's just an example, it can very
well be a contrib item with a creation script. Probably *should* be,
in fact, because dynamically created functions are what other people are
going to be building; an example of how to do it as a builtin function
isn't as helpful.

Here is a patch for contrib/showguc. It can serve as a reference
implementation for a C function which returns setof composite. It
required some small changes in guc.c and guc.h so that the number of GUC
variables, and their values, could be accessed. Example usage as shown
below:

test=# select * from show_all_vars() where varname = 'wal_sync_method';
varname | varval
-----------------+-----------
wal_sync_method | fdatasync
(1 row)

test=# select show_var('wal_sync_method');
show_var
-----------
fdatasync
(1 row)

show_var() is neither composite nor set returning, but it seemed like a
worthwhile addition. Please apply if there are no objections.

Thanks,

Joe

Index: contrib/showguc/Makefile
===================================================================
RCS file: contrib/showguc/Makefile
diff -N contrib/showguc/Makefile
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- contrib/showguc/Makefile	27 May 2002 00:24:44 -0000
***************
*** 0 ****
--- 1,9 ----
+ subdir = contrib/showguc
+ top_builddir = ../..
+ include $(top_builddir)/src/Makefile.global
+
+ MODULES = showguc
+ DATA_built = showguc.sql
+ DOCS = README.showguc
+
+ include $(top_srcdir)/contrib/contrib-global.mk
Index: contrib/showguc/README.showguc
===================================================================
RCS file: contrib/showguc/README.showguc
diff -N contrib/showguc/README.showguc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- contrib/showguc/README.showguc	10 Jun 2002 00:16:48 -0000
***************
*** 0 ****
--- 1,105 ----
+ /*
+  * showguc
+  *
+  * Sample to demonstrate a C function which returns setof composite.
+  * Joe Conway <mail@joeconway.com>
+  *
+  * Copyright 2002 by PostgreSQL Global Development Group
+  *
+  * 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 AUTHORS 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 AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM 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.
+  *
+  */
+ Version 0.1 (9 June, 2002):
+   First release
+
+ Release Notes:
+
+   Version 0.1
+     - initial release
+
+ Installation:
+   Place these files in a directory called 'showguc' under 'contrib' in the PostgreSQL source tree. Then run:
+
+     make
+     make install
+
+   You can use showguc.sql to create the functions in your database of choice, e.g.
+
+     psql -U postgres template1 < showguc.sql
+
+   installs following functions into database template1:
+
+      show_all_vars() - returns all GUC variables
+      show_var(text) - returns value of the requested GUC variable
+
+ Documentation
+ ==================================================================
+ Name
+
+ show_all_vars() - returns all GUC variables
+
+ Synopsis
+
+ show_all_vars()
+
+ Inputs
+
+   none
+
+ Outputs
+
+   Returns setof __gucvar, where __gucvar is (varname TEXT, varval TEXT). All
+     GUC variables displayed by SHOW ALL are returned as a set.
+
+ Example usage
+
+ test=# select * from show_all_vars() where varname = 'wal_sync_method';
+      varname     |  varval
+ -----------------+-----------
+  wal_sync_method | fdatasync
+ (1 row)
+
+ ==================================================================
+ Name
+
+ show_var(text varname) - returns value of GUC variable varname
+
+ Synopsis
+
+ show_var(varname)
+
+ Inputs
+
+   varname
+     The name of a GUC variable
+
+ Outputs
+
+   Returns the current value of varname.
+
+ Example usage
+
+ test=# select show_var('wal_sync_method');
+  show_var
+ -----------
+  fdatasync
+ (1 row)
+
+ ==================================================================
+ -- Joe Conway
+
Index: contrib/showguc/showguc.c
===================================================================
RCS file: contrib/showguc/showguc.c
diff -N contrib/showguc/showguc.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- contrib/showguc/showguc.c	10 Jun 2002 00:02:14 -0000
***************
*** 0 ****
--- 1,152 ----
+ /*
+  * showguc
+  *
+  * Sample to demonstrate a C function which returns setof composite.
+  * Joe Conway <mail@joeconway.com>
+  *
+  * Copyright 2002 by PostgreSQL Global Development Group
+  *
+  * 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 AUTHORS 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 AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM 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 "fmgr.h"
+ #include "funcapi.h"
+ #include "utils/builtins.h"
+ #include "utils/guc.h"
+
+ #include "showguc.h"
+
+ /*
+  * showguc_all - equiv to SHOW ALL command but implemented as
+  * an SRF.
+  */
+ PG_FUNCTION_INFO_V1(showguc_all);
+ Datum
+ showguc_all(PG_FUNCTION_ARGS)
+ {
+ 	FuncCallContext	   *funcctx;
+ 	TupleDesc			tupdesc;
+ 	int					call_cntr;
+ 	int					max_calls;
+ 	TupleTableSlot	   *slot;
+ 	AttInMetadata	   *attinmeta;
+
+ 	/* stuff done only on the first call of the function */
+  	if(SRF_IS_FIRSTPASS())
+  	{
+ 		/* create a function context for cross-call persistence */
+  		funcctx = SRF_FIRSTCALL_INIT();
+
+ 		/*
+ 		 * Build a tuple description for a pg__guc tuple
+ 		 */
+ 		tupdesc = RelationNameGetTupleDesc("__gucvar");
+
+ 		/* allocate a slot for a tuple with this tupdesc */
+ 		slot = TupleDescGetSlot(tupdesc);
+
+ 		/* assign slot to function context */
+ 		funcctx->slot = slot;
+
+ 		/*
+ 		 * Generate attribute metadata needed later to produce tuples from raw
+ 		 * C strings
+ 		 */
+ 		attinmeta = TupleDescGetAttInMetadata(tupdesc);
+ 		funcctx->attinmeta = attinmeta;
+
+ 		/* total number of tuples to be returned */
+ 		funcctx->max_calls = GetNumGUCConfigOptions();
+     }
+
+ 	/* stuff done on every call of the function */
+  	funcctx = SRF_PERCALL_SETUP(funcctx);
+
+ 	call_cntr = funcctx->call_cntr;
+ 	max_calls = funcctx->max_calls;
+ 	slot = funcctx->slot;
+ 	attinmeta = funcctx->attinmeta;
+
+  	if (call_cntr < max_calls)	/* do when there is more left to send */
+  	{
+ 		char	   *varname;
+ 		char	   *varval;
+ 		char	   **values;
+ 		HeapTuple	tuple;
+ 		Datum		result;
+
+ 		/*
+ 		 * Get the next GUC variable name and value
+ 		 */
+ 		varval = GetGUCConfigOptionNum(call_cntr, &varname);
+
+ 		/*
+ 		 * Prepare a values array for storage in our slot.
+ 		 * This should be an array of C strings which will
+ 		 * be processed later by the appropriate "in" functions.
+ 		 */
+ 		values = (char **) palloc(2 * sizeof(char *));
+ 		values[0] = varname;
+ 		values[1] = varval;
+
+ 		/* build a tuple */
+ 		tuple = BuildTupleFromCStrings(attinmeta, values);
+
+ 		/* make the tuple into a datum */
+ 		result = TupleGetDatum(slot, tuple);
+
+ 		/* Clean up */
+ 		pfree(varname);
+ 		pfree(values);
+
+  		SRF_RETURN_NEXT(funcctx, result);
+  	}
+  	else	/* do when there is no more left */
+  	{
+  		SRF_RETURN_DONE(funcctx);
+  	}
+ }
+
+
+ /*
+  * showguc_name - equiv to SHOW X command but implemented as
+  * a function.
+  */
+ PG_FUNCTION_INFO_V1(showguc_name);
+ Datum
+ showguc_name(PG_FUNCTION_ARGS)
+ {
+ 	char   *varname;
+ 	char   *varval;
+ 	text   *result_text;
+
+ 	/* Get the GUC variable name */
+ 	varname = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
+
+ 	/* Get the value */
+ 	varval = GetGUCConfigOptionName(varname);
+
+ 	/* Convert to text */
+ 	result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(varval)));
+
+ 	/* return it */
+ 	PG_RETURN_TEXT_P(result_text);
+ }
+
Index: contrib/showguc/showguc.h
===================================================================
RCS file: contrib/showguc/showguc.h
diff -N contrib/showguc/showguc.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- contrib/showguc/showguc.h	10 Jun 2002 00:01:02 -0000
***************
*** 0 ****
--- 1,37 ----
+ /*
+  * showguc
+  *
+  * Sample to demonstrate a C function which returns setof composite.
+  * Joe Conway <mail@joeconway.com>
+  *
+  * Copyright 2002 by PostgreSQL Global Development Group
+  *
+  * 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 AUTHORS 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 AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM 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.
+  *
+  */
+
+ #ifndef SHOWGUC_H
+ #define SHOWGUC_H
+
+ /*
+  * External declarations
+  */
+ extern Datum showguc_all(PG_FUNCTION_ARGS);
+ extern Datum showguc_name(PG_FUNCTION_ARGS);
+
+ #endif   /* SHOWGUC_H */
Index: contrib/showguc/showguc.sql.in
===================================================================
RCS file: contrib/showguc/showguc.sql.in
diff -N contrib/showguc/showguc.sql.in
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- contrib/showguc/showguc.sql.in	10 Jun 2002 00:03:13 -0000
***************
*** 0 ****
--- 1,10 ----
+ CREATE VIEW __gucvar AS
+   SELECT
+     ''::TEXT AS varname,
+     ''::TEXT AS varval;
+
+ CREATE OR REPLACE FUNCTION show_all_vars() RETURNS setof __gucvar
+   AS 'MODULE_PATHNAME','showguc_all' LANGUAGE 'c' STABLE STRICT;
+
+ CREATE OR REPLACE FUNCTION show_var(text) RETURNS text
+   AS 'MODULE_PATHNAME','showguc_name' LANGUAGE 'c' STABLE STRICT;
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /opt/src/cvs/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.69
diff -c -r1.69 guc.c
*** src/backend/utils/misc/guc.c	17 May 2002 20:32:29 -0000	1.69
--- src/backend/utils/misc/guc.c	9 Jun 2002 22:51:45 -0000
***************
*** 824,830 ****

static int guc_var_compare(const void *a, const void *b);
! static void _ShowOption(struct config_generic *record);

/*
--- 824,830 ----

static int guc_var_compare(const void *a, const void *b);
! static char *_ShowOption(struct config_generic *record);

/*
***************
*** 2204,2215 ****
ShowGUCConfigOption(const char *name)
{
struct config_generic *record;

record = find_option(name);
if (record == NULL)
elog(ERROR, "Option '%s' is not recognized", name);

! _ShowOption(record);
}

/*
--- 2204,2221 ----
ShowGUCConfigOption(const char *name)
{
struct config_generic *record;
+ 	char *val;

record = find_option(name);
if (record == NULL)
elog(ERROR, "Option '%s' is not recognized", name);

! val = _ShowOption(record);
! if(val != NULL)
! {
! elog(INFO, "%s is %s", record->name, val);
! pfree(val);
! }
}

/*
***************
*** 2219,2239 ****
ShowAllGUCConfig(void)
{
int i;

for (i = 0; i < num_guc_variables; i++)
{
struct config_generic *conf = guc_variables[i];

if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
! _ShowOption(conf);
}
}

! static void
_ShowOption(struct config_generic *record)
{
char buffer[256];
const char *val;

switch (record->vartype)
{
--- 2225,2295 ----
ShowAllGUCConfig(void)
{
int			i;
+ 	char	   *val;

for (i = 0; i < num_guc_variables; i++)
{
struct config_generic *conf = guc_variables[i];

if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
! {
! val = _ShowOption(conf);
! if(val != NULL)
! {
! elog(INFO, "%s is %s", conf->name, val);
! pfree(val);
! }
! }
}
}

! /*
! * Return GUC variable value by name
! */
! char *
! GetGUCConfigOptionName(const char *name)
! {
! struct config_generic *record;
!
! record = find_option(name);
! if (record == NULL)
! elog(ERROR, "Option '%s' is not recognized", name);
!
! return _ShowOption(record);
! }
!
! /*
! * Return GUC variable value and set varname for a specific
! * variable by number.
! */
! char *
! GetGUCConfigOptionNum(int varnum, char **varname)
! {
! struct config_generic *conf = guc_variables[varnum];
!
! *varname = pstrdup(conf->name);
!
! if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
! return _ShowOption(conf);
! else
! return NULL;
! }
!
! /*
! * Return the total number of GUC variables
! */
! int
! GetNumGUCConfigOptions(void)
! {
! return num_guc_variables;
! }
!
! static char *
_ShowOption(struct config_generic *record)
{
char buffer[256];
const char *val;
+ char *retval;

switch (record->vartype)
{
***************
*** 2297,2303 ****
break;
}

! elog(INFO, "%s is %s", record->name, val);
}

--- 2353,2361 ----
break;
}

! retval = pstrdup(val);
!
! return retval;
}

Index: src/include/utils/guc.h
===================================================================
RCS file: /opt/src/cvs/pgsql/src/include/utils/guc.h,v
retrieving revision 1.17
diff -c -r1.17 guc.h
*** src/include/utils/guc.h	17 May 2002 01:19:19 -0000	1.17
--- src/include/utils/guc.h	9 Jun 2002 22:45:20 -0000
***************
*** 86,91 ****
--- 86,94 ----
bool isLocal, bool DoIt);
extern void ShowGUCConfigOption(const char *name);
extern void ShowAllGUCConfig(void);
+ extern char *GetGUCConfigOptionName(const char *name);
+ extern char *GetGUCConfigOptionNum(int varnum, char **varname);
+ extern int GetNumGUCConfigOptions(void);

extern void SetPGVariable(const char *name, List *args, bool is_local);
extern void GetPGVariable(const char *name);

---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

http://www.postgresql.org/users-lounge/docs/faq.html

--
Peter Eisentraut peter_e@gmx.net

#3Joe Conway
mail@joeconway.com
In reply to: Peter Eisentraut (#2)
Re: [Fwd: [PATCHES] contrib/showguc (was Re: revised sample

<moving back to HACKERS for the discussion>

Peter Eisentraut wrote:

OK, I've been looking at this package for some time through various
iterations and I have my doubts about it.

What's going to happen to this when SHOW ALL is changed to return a query
result? If you want to provide an example of a set-returning function,
use something of lasting value, maybe generate some mathematic sequence.

Well, I wanted to implement this as a functional equivalent of SHOW ALL,
in the backend, but there was no way to bootstrap a builtin SRF that
wasn't also too ugly to be acceptable (at least that I could come up
with -- any suggestions?).

And while SHOW ALL *could* be implemented in a similar fashion to
EXPLAIN, with that approach you could not use a WHERE clause, or join
the results with any other data. IMHO that significantly reduces the
utility of returning SHOW ALL results as a query in the first place.

I'd be happy to produce a different function as a reference
implementation, but it seemed that there was sufficient demand in the
past that this was a useful example. If the consensus is that
contrib/showguc (renamed, see below) is a bad idea, then I'll come up
with something else.

Also, the first place this sort of material should go is the
documentation, not hidden somewhere in contrib.

No doubt, and there *will* be documentation. I was waiting for the API
and example to stabilize a bit first. There is no sense in documenting a
moving target.

In any case, please don't expose the name "GUC" to user space.

OK. If I replace user space references to GUC with something more
palatable, are the guc.c and guc.h changes at least acceptable? With
them, user functions can at least read configuration variables. GUC
variables are inaccessible otherwise.

Please let me know the desired direction for this, and I'll adjust
accordingly.

Thanks,

Joe

#4Peter Eisentraut
peter_e@gmx.net
In reply to: Joe Conway (#3)
Re: [Fwd: [PATCHES] contrib/showguc (was Re: revised sample

Joe Conway writes:

Well, I wanted to implement this as a functional equivalent of SHOW ALL,
in the backend, but there was no way to bootstrap a builtin SRF that
wasn't also too ugly to be acceptable (at least that I could come up
with -- any suggestions?).

Well, if you want to provide a really simple example (which might not be a
bad idea), just return N random numbers, where N is passed as an argument.
If you want to add some substance, generate those numbers yourself using
some algorithm to achieve a certain kind of distribution. (This might
require you to keep some state between calls, which would be interesting
to see.)

As far as returning composite types, that's really a separate thing, so
there ought to be a separate example.

And while SHOW ALL *could* be implemented in a similar fashion to
EXPLAIN, with that approach you could not use a WHERE clause, or join
the results with any other data. IMHO that significantly reduces the
utility of returning SHOW ALL results as a query in the first place.

SHOW ALL is a red herring. What we need is simple SHOW to return a query
result. Or we need a simple function that takes one argument of type text
(or name) and returns one datum of type text with the value of the
parameter. If, as you say, you'd like to join the results with other
computations, the latter would be for you.

A random observation: Your SRF API seems to require that you determine
the maximum number of calls ahead of time. Is this necessary? It might
be interesting, for instance, to create mathematical sequences and have it
terminate at some condition. Instead of the max_calls and call counter
you could provide some space for free use.

--
Peter Eisentraut peter_e@gmx.net

#5Joe Conway
mail@joeconway.com
In reply to: Peter Eisentraut (#4)
Re: [Fwd: [PATCHES] contrib/showguc (was Re: revised sample

Peter Eisentraut wrote:

Well, if you want to provide a really simple example (which might not be a
bad idea), just return N random numbers, where N is passed as an argument.
If you want to add some substance, generate those numbers yourself using
some algorithm to achieve a certain kind of distribution. (This might
require you to keep some state between calls, which would be interesting
to see.)

As far as returning composite types, that's really a separate thing, so
there ought to be a separate example.

OK. I'll create a simpler example of both returning composite and
returning a set.

SHOW ALL is a red herring. What we need is simple SHOW to return a query
result. Or we need a simple function that takes one argument of type text
(or name) and returns one datum of type text with the value of the
parameter. If, as you say, you'd like to join the results with other
computations, the latter would be for you.

Fair enough. There was already a function in the submitted contrib which
did just that. I'll rework it into a backend function and resubmit.

A random observation: Your SRF API seems to require that you determine
the maximum number of calls ahead of time. Is this necessary? It might
be interesting, for instance, to create mathematical sequences and have it
terminate at some condition.

The max calls is a purely optional part of the API. If a different way
of determining when you're "done" exists for a particular application,
that should be used instead. I will make sure this fact is prominent in
the documentation.

Instead of the max_calls and call counter you could provide some space
for free use.

Well, that was the idea with:
/* pointer to misc context info */
void *fctx;
You can use this to keep track of any context info you want. I suppose
call_cntr and max_calls could be part of the user provided context, but
since they will be used frequently (at least in my experience so far
they have been needed each time), I thought making them part of the
structure for the sake of convenience was worth it.

Thank you for the feedback!

Joe