Joe Conway wrote:
> Here is a revised patch for a sample C function returning setof 
> composite. (Same comments as last time -- It is a clone of SHOW ALL as 
> an SRF. For the moment, the function is implemented as contrib/showguc, 
> although a few minor changes to guc.c and guc.h were required to support 
> it.)
> 
> This version includes pieces that may be appropriate for fmgr.c and 
> fmgr.h, to hide some of the ugliness and facilitate writing C functions 
> which return setof composite. The API is something like this:
> 

Sorry -- I was a bit too quick with the last patch :-(. It generates a 
"Cache reference leak" warning. This one is better.

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      26 May 2002 05:46:57 -0000
***************
*** 0 ****
--- 1,77 ----
+ /*
+  * showguc
+  *
+  * Sample function to demonstrate a C function which returns setof composite.
+  *
+  * Copyright 2002 by PostgreSQL Global Development Group
+  * Cloned from src/backend/utils/misc/guc.c which was written by Peter Eisentraut
+  * <[EMAIL PROTECTED]>, and modified to suit.
+  *
+  * 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 (25 May, 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:
+ 
+      showvars() - returns all GUC variables
+ 
+ Documentation
+ ==================================================================
+ Name
+ 
+ showvars() - returns all GUC variables
+ 
+ Synopsis
+ 
+ showvars()
+ 
+ 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
+ 
+   select showvars();
+ 
+ ==================================================================
+ -- 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   27 May 2002 02:03:19 -0000
***************
*** 0 ****
--- 1,726 ----
+ /*--------------------------------------------------------------------
+  * showguc.c
+  *
+  * Sample function to demonstrate a C function which returns setof composite.
+  *
+  * Copyright 2002 by PostgreSQL Global Development Group
+  * Cloned from src/backend/utils/misc/guc.c which was written by Peter Eisentraut
+  * <[EMAIL PROTECTED]>, and modified to suit.
+  *--------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ 
+ #include <errno.h>
+ #include <float.h>
+ #include <limits.h>
+ #include <unistd.h>
+ 
+ #include "fmgr.h"
+ #include "showguc.h"
+ 
+ #include "utils/guc.h"
+ #include "access/xlog.h"
+ #include "access/heapam.h"
+ #include "catalog/namespace.h"
+ #include "catalog/pg_type.h"
+ #include "commands/async.h"
+ #include "commands/variable.h"
+ #include "executor/executor.h"
+ #include "libpq/auth.h"
+ #include "libpq/pqcomm.h"
+ #include "miscadmin.h"
+ #include "optimizer/cost.h"
+ #include "optimizer/geqo.h"
+ #include "optimizer/paths.h"
+ #include "optimizer/planmain.h"
+ #include "parser/parse_expr.h"
+ #include "parser/parse_type.h"
+ #include "storage/fd.h"
+ #include "storage/freespace.h"
+ #include "storage/lock.h"
+ #include "storage/proc.h"
+ #include "tcop/tcopprot.h"
+ #include "utils/array.h"
+ #include "utils/builtins.h"
+ #include "utils/datetime.h"
+ #include "utils/elog.h"
+ #include "utils/pg_locale.h"
+ #include "utils/syscache.h"
+ #include "pgstat.h"
+ 
+ 
+ /* XXX these should be in other modules' header files */
+ extern bool Log_connections;
+ extern int    PreAuthDelay;
+ extern int    AuthenticationTimeout;
+ extern int    CheckPointTimeout;
+ extern int    CommitDelay;
+ extern int    CommitSiblings;
+ extern bool FixBTree;
+ 
+ #ifdef HAVE_SYSLOG
+ extern char *Syslog_facility;
+ extern char *Syslog_ident;
+ 
+ #endif
+ 
+ /*
+  * Debugging options
+  */
+ #ifdef USE_ASSERT_CHECKING
+ bool          assert_enabled = true;
+ #endif
+ bool          Debug_print_query = false;
+ bool          Debug_print_plan = false;
+ bool          Debug_print_parse = false;
+ bool          Debug_print_rewritten = false;
+ bool          Debug_pretty_print = false;
+ 
+ bool          Show_parser_stats = false;
+ bool          Show_planner_stats = false;
+ bool          Show_executor_stats = false;
+ bool          Show_query_stats = false;       /* this is sort of all three above
+                                                                                * 
+together */
+ bool          Show_btree_build_stats = false;
+ 
+ bool          Explain_pretty_print = true;
+ 
+ bool          SQL_inheritance = true;
+ 
+ bool          Australian_timezones = false;
+ 
+ bool          Password_encryption = false;
+ 
+ #ifndef PG_KRB_SRVTAB
+ #define PG_KRB_SRVTAB ""
+ #endif
+ 
+ /*
+  * Declarations for GUC tables
+  *
+  * See src/backend/utils/misc/README for design notes.
+  */
+ enum config_type
+ {
+       PGC_BOOL,
+       PGC_INT,
+       PGC_REAL,
+       PGC_STRING
+ };
+ 
+ /* Generic fields applicable to all types of variables */
+ struct config_generic
+ {
+       /* constant fields, must be set correctly in initial value: */
+       const char *name;                       /* name of variable - MUST BE FIRST */
+       GucContext      context;                /* context required to set the 
+variable */
+       int                     flags;                  /* flag bits, see below */
+       /* variable fields, initialized at runtime: */
+       enum config_type vartype;       /* type of variable (set only at startup) */
+       int                     status;                 /* status bits, see below */
+       GucSource       reset_source;   /* source of the reset_value */
+       GucSource       session_source; /* source of the session_value */
+       GucSource       tentative_source; /* source of the tentative_value */
+       GucSource       source;                 /* source of the current actual value 
+*/
+ };
+ 
+ /* bit values in flags field */
+ #define GUC_LIST_INPUT                0x0001  /* input can be list format */
+ #define GUC_LIST_QUOTE                0x0002  /* double-quote list elements */
+ #define GUC_NO_SHOW_ALL               0x0004  /* exclude from SHOW ALL */
+ #define GUC_NO_RESET_ALL      0x0008  /* exclude from RESET ALL */
+ 
+ /* bit values in status field */
+ #define GUC_HAVE_TENTATIVE    0x0001  /* tentative value is defined */
+ #define GUC_HAVE_LOCAL                0x0002  /* a SET LOCAL has been executed */
+ 
+ 
+ /* GUC records for specific variable types */
+ 
+ struct config_bool
+ {
+       struct config_generic gen;
+       /* these fields must be set correctly in initial value: */
+       /* (all but reset_val are constants) */
+       bool       *variable;
+       bool            reset_val;
+       bool            (*assign_hook) (bool newval, bool doit, bool interactive);
+       const char *(*show_hook) (void);
+       /* variable fields, initialized at runtime: */
+       bool            session_val;
+       bool            tentative_val;
+ };
+ 
+ struct config_int
+ {
+       struct config_generic gen;
+       /* these fields must be set correctly in initial value: */
+       /* (all but reset_val are constants) */
+       int                *variable;
+       int                     reset_val;
+       int                     min;
+       int                     max;
+       bool            (*assign_hook) (int newval, bool doit, bool interactive);
+       const char *(*show_hook) (void);
+       /* variable fields, initialized at runtime: */
+       int                     session_val;
+       int                     tentative_val;
+ };
+ 
+ struct config_real
+ {
+       struct config_generic gen;
+       /* these fields must be set correctly in initial value: */
+       /* (all but reset_val are constants) */
+       double     *variable;
+       double          reset_val;
+       double          min;
+       double          max;
+       bool            (*assign_hook) (double newval, bool doit, bool interactive);
+       const char *(*show_hook) (void);
+       /* variable fields, initialized at runtime: */
+       double          session_val;
+       double          tentative_val;
+ };
+ 
+ struct config_string
+ {
+       struct config_generic gen;
+       /* these fields must be set correctly in initial value: */
+       /* (all are constants) */
+       char      **variable;
+       const char *boot_val;
+       const char *(*assign_hook) (const char *newval, bool doit, bool interactive);
+       const char *(*show_hook) (void);
+       /* variable fields, initialized at runtime: */
+       char       *reset_val;
+       char       *session_val;
+       char       *tentative_val;
+ };
+ 
+ /* Macros for freeing malloc'd pointers only if appropriate to do so */
+ /* Some of these tests are probably redundant, but be safe ... */
+ #define SET_STRING_VARIABLE(rec, newval) \
+       do { \
+               if (*(rec)->variable && \
+                       *(rec)->variable != (rec)->reset_val && \
+                       *(rec)->variable != (rec)->session_val && \
+                       *(rec)->variable != (rec)->tentative_val) \
+                       free(*(rec)->variable); \
+               *(rec)->variable = (newval); \
+       } while (0)
+ #define SET_STRING_RESET_VAL(rec, newval) \
+       do { \
+               if ((rec)->reset_val && \
+                       (rec)->reset_val != *(rec)->variable && \
+                       (rec)->reset_val != (rec)->session_val && \
+                       (rec)->reset_val != (rec)->tentative_val) \
+                       free((rec)->reset_val); \
+               (rec)->reset_val = (newval); \
+       } while (0)
+ #define SET_STRING_SESSION_VAL(rec, newval) \
+       do { \
+               if ((rec)->session_val && \
+                       (rec)->session_val != *(rec)->variable && \
+                       (rec)->session_val != (rec)->reset_val && \
+                       (rec)->session_val != (rec)->tentative_val) \
+                       free((rec)->session_val); \
+               (rec)->session_val = (newval); \
+       } while (0)
+ #define SET_STRING_TENTATIVE_VAL(rec, newval) \
+       do { \
+               if ((rec)->tentative_val && \
+                       (rec)->tentative_val != *(rec)->variable && \
+                       (rec)->tentative_val != (rec)->reset_val && \
+                       (rec)->tentative_val != (rec)->session_val) \
+                       free((rec)->tentative_val); \
+               (rec)->tentative_val = (newval); \
+       } while (0)
+ 
+ 
+ /*
+  * This struct holds function context.
+  * Use fn_extra to hold a pointer to it across calls
+  */
+ typedef struct
+ {
+       /* Number of times we've been called before */
+       uint                    call_cntr;
+ 
+       /* Maximum number of calls */
+       uint                    max_calls;
+ 
+       /* pointer to result slot */
+       TupleTableSlot *slot;
+ 
+       /* pointer to misc context info */
+       void               *fctx;
+ 
+       /* pointer to array of attribute "type"in finfo */
+       FmgrInfo           *att_in_funcinfo;
+ 
+       /* pointer to array of attribute type typelem */
+       Oid                        *elements;
+ 
+       /* memory context used to initialize structure */
+       MemoryContext   fmctx;
+ 
+ }     FuncCallContext;
+ 
+ static char *GetNextGUCConfig(struct config_generic **guc_variables,
+                                                               uint varnum, char 
+**varname);
+ static char *_GetOption(struct config_generic *record);
+ static TupleTableSlot *first_pass_setup(char *relname, FuncCallContext *funcctx);
+ static TupleTableSlot *store_slot(char **values, FuncCallContext *funcctx);
+ static FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS);
+ static void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *fctx);
+ static Oid get_type_element(Oid type);
+ static Oid get_type_infunc(Type typ);
+ 
+ /*
+  * The following macros are candidates to go into fmgr.h
+  */
+ #define  FUNC_MULTIPLE_RESULT(_funcctx, _relname, _max_calls, _fctx) \
+       do { \
+               _funcctx = init_MultiFuncCall(fcinfo); \
+               if (_funcctx->call_cntr == 0) \
+               { \
+                       _funcctx->max_calls = _max_calls; \
+                       _funcctx->slot = first_pass_setup(_relname, _funcctx); \
+                       _funcctx->fctx = _fctx; \
+               } \
+               else \
+                       ExecClearTuple(_funcctx->slot); \
+       } while (0)
+ 
+ #define  FUNC_BUILD_SLOT(_values, _funcctx) \
+       do { \
+               _funcctx->slot = store_slot(_values, _funcctx); \
+       } while (0)
+ 
+ #define  FUNC_RETURN_NEXT(_funcctx) \
+       do { \
+               ReturnSetInfo      *rsi; \
+               _funcctx->call_cntr++; \
+               rsi = (ReturnSetInfo *) fcinfo->resultinfo; \
+               rsi->isDone = ExprMultipleResult; \
+               PG_RETURN_POINTER(_funcctx->slot); \
+       } while (0)
+ 
+ 
+ #define  FUNC_RETURN_DONE(_funcctx) \
+       do { \
+               ReturnSetInfo      *rsi; \
+               end_MultiFuncCall(fcinfo, _funcctx); \
+               rsi = (ReturnSetInfo *) fcinfo->resultinfo; \
+               rsi->isDone = ExprEndResult; \
+               _funcctx->slot = NULL; \
+               PG_RETURN_POINTER(_funcctx->slot); \
+       } while (0)
+ 
+ /*
+  * SHOW command
+  */
+ PG_FUNCTION_INFO_V1(showguc);
+ 
+ Datum
+ showguc(PG_FUNCTION_ARGS)
+ {
+       FuncCallContext    *funcctx;
+       char                       *relname = "__gucvar";
+       char                       *varname = NULL;
+       char                       *varval;
+       char                       **values;
+       uint                            call_cntr;
+       uint                            max_calls;
+       struct config_generic **fctx;
+ 
+       /*
+        * Setup the function context for multiple calls
+        */
+       FUNC_MULTIPLE_RESULT(funcctx, relname, get_num_guc_variables(), 
+get_guc_variables());
+ 
+       /*
+        * All set up now, so use what we've got
+        */
+       call_cntr = funcctx->call_cntr;
+       max_calls = funcctx->max_calls;
+       fctx = (struct config_generic **) funcctx->fctx;
+ 
+       /*
+        * Are there any more results to send?
+        */
+       if (call_cntr < max_calls)
+       {
+               /*
+                * Get the next GUC variable name and value
+                */
+               varval = GetNextGUCConfig(fctx, 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;
+ 
+               /* Store the values */
+               FUNC_BUILD_SLOT(values, funcctx);
+ 
+               /* Clean up */
+               pfree(varname);
+               pfree(values);
+ 
+               FUNC_RETURN_NEXT(funcctx);
+       }
+       else
+       {
+               /* All done! */
+               FUNC_RETURN_DONE(funcctx);
+       }
+ }
+ 
+ /* internal functions */
+ 
+ /*
+  * SHOW ALL command
+  */
+ static char *
+ GetNextGUCConfig(struct config_generic **guc_variables, uint varnum, char **varname)
+ {
+       struct config_generic *conf = guc_variables[varnum];
+ 
+       *varname = pstrdup(conf->name);
+ 
+       if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
+               return _GetOption(conf);
+       else
+               return NULL;
+ 
+ }
+ 
+ static char *
+ _GetOption(struct config_generic *record)
+ {
+       char            buffer[256];
+       const char *val;
+       char       *retval;
+ 
+       switch (record->vartype)
+       {
+               case PGC_BOOL:
+                       {
+                               struct config_bool *conf = (struct config_bool *) 
+record;
+ 
+                               if (conf->show_hook)
+                                       val = (*conf->show_hook) ();
+                               else
+                                       val = *conf->variable ? "on" : "off";
+                       }
+                       break;
+ 
+               case PGC_INT:
+                       {
+                               struct config_int *conf = (struct config_int *) record;
+ 
+                               if (conf->show_hook)
+                                       val = (*conf->show_hook) ();
+                               else
+                               {
+                                       snprintf(buffer, sizeof(buffer), "%d",
+                                                        *conf->variable);
+                                       val = buffer;
+                               }
+                       }
+                       break;
+ 
+               case PGC_REAL:
+                       {
+                               struct config_real *conf = (struct config_real *) 
+record;
+ 
+                               if (conf->show_hook)
+                                       val = (*conf->show_hook) ();
+                               else
+                               {
+                                       snprintf(buffer, sizeof(buffer), "%g",
+                                                        *conf->variable);
+                                       val = buffer;
+                               }
+                       }
+                       break;
+ 
+               case PGC_STRING:
+                       {
+                               struct config_string *conf = (struct config_string *) 
+record;
+ 
+                               if (conf->show_hook)
+                                       val = (*conf->show_hook) ();
+                               else if (*conf->variable && **conf->variable)
+                                       val = *conf->variable;
+                               else
+                                       val = "unset";
+                       }
+                       break;
+ 
+               default:
+                       /* just to keep compiler quiet */
+                       val = "???";
+                       break;
+       }
+       retval = pstrdup(val);
+ 
+       return retval;
+ }
+ 
+ /*
+  * The following functions are candidates to go into fmgr.c
+  */
+ static TupleTableSlot *
+ first_pass_setup(char *relname, FuncCallContext *funcctx)
+ {
+       TupleTableSlot     *slot;
+       Oid                                     relid;
+       Relation                        rel;
+       TupleDesc                       tupdesc;
+       int                                     natts;
+       int                                     i;
+       Type                            att_type;
+       Oid                                     att_in_funcoid;
+       FmgrInfo                   *att_in_funcinfo;
+       Oid                                *elements;
+ 
+       /*
+        * Make a standalone slot
+        */
+       slot = MakeTupleTableSlot();
+ 
+       /*
+        * Open relation and get the tuple description
+        */
+       relid = RelnameGetRelid(relname);
+       rel = relation_open(relid, AccessShareLock);
+       tupdesc = CreateTupleDescCopy(rel->rd_att);
+       relation_close(rel, AccessShareLock);
+       natts = tupdesc->natts;
+ 
+       /*
+        * Bind the tuple description to the slot
+        */
+       ExecSetSlotDescriptor(slot, tupdesc, true);
+ 
+       /*
+        * Gather info needed later to call the "in" function for each attribute
+        */
+       att_in_funcinfo = (FmgrInfo *) palloc(natts * sizeof(FmgrInfo));
+       elements = (Oid *) palloc(natts * sizeof(Oid));
+ 
+       for (i = 0; i < natts; i++)
+       {
+               att_type = typeidType(tupdesc->attrs[i]->atttypid);
+               att_in_funcoid = get_type_infunc(att_type);
+               fmgr_info(att_in_funcoid, &att_in_funcinfo[i]); 
+               elements[i] = get_type_element(tupdesc->attrs[i]->atttypid);
+               ReleaseSysCache(att_type);
+       }
+ 
+       funcctx->att_in_funcinfo = att_in_funcinfo;
+       funcctx->elements = elements;
+ 
+       /*
+        * Return the slot!
+        */
+       return slot;
+ }
+ 
+ static TupleTableSlot *
+ store_slot(char **values, FuncCallContext *funcctx)
+ {
+       TupleTableSlot     *slot = funcctx->slot;
+       TupleDesc                       tupdesc;
+       int                                     natts;
+       HeapTuple                       tuple;
+       char                       *nulls;
+       int                                     i;
+       Datum                      *dvalues;
+       FmgrInfo                        att_in_funcinfo;
+       Oid                                     element;
+ 
+       /*
+        * Get the tuple description
+        */
+       tupdesc = slot->ttc_tupleDescriptor;
+       natts = tupdesc->natts;
+ 
+       dvalues = (Datum *) palloc(natts * sizeof(Datum));
+       /*
+        * Call the "in" function for each attribute
+        */
+       for (i = 0; i < natts; i++)
+       {
+               if (values[i] != NULL)
+               {
+                       att_in_funcinfo = funcctx->att_in_funcinfo[i];
+                       element = funcctx->elements[i];
+ 
+                       dvalues[i] = FunctionCall3(&att_in_funcinfo, 
+CStringGetDatum(values[i]),
+                                                                               
+ObjectIdGetDatum(element),
+                                                                               
+Int32GetDatum(tupdesc->attrs[i]->atttypmod));
+               }
+               else
+                       dvalues[i] = PointerGetDatum(NULL);
+       }
+ 
+       /*
+        * Form a tuple
+        */
+       nulls = (char *) palloc(natts * sizeof(char));
+       for (i = 0; i < natts; i++)
+       {
+               if (DatumGetPointer(dvalues[i]) != NULL)
+                       nulls[i] = ' ';
+               else
+                       nulls[i] = 'n';
+       }
+       tuple = heap_formtuple(tupdesc, dvalues, nulls);
+ 
+       /*
+        * Save the tuple in the tuple slot
+        */
+       slot = ExecStoreTuple(tuple,                    /* tuple to store */
+                                                 slot,                         /* 
+slot to store in */
+                                                 InvalidBuffer,        /* buffer 
+associated with
+                                                                                      
+  * this tuple */
+                                                 true);                        /* 
+pfree this pointer */
+ 
+       /*
+        * Clean up
+        */
+       pfree(nulls);
+       pfree(dvalues);
+ 
+       /*
+        * Return the slot!
+        */
+       return slot;
+ }
+ 
+ 
+ /*
+  * init_MultiFuncCall
+  * Create an empty FuncCallContext data structure
+  * and do some other basic Multi-function call setup
+  * and error checking
+  */
+ FuncCallContext *
+ init_MultiFuncCall(PG_FUNCTION_ARGS)
+ {
+       FuncCallContext *retval;
+ 
+       /*
+        * Bail if we're called in the wrong context
+        */
+       if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
+               elog(ERROR, "function called in context that does not accept a set 
+result");
+ 
+       if (fcinfo->flinfo->fn_extra == NULL)
+       {
+               /*
+                * First call
+                */
+               MemoryContext oldcontext;
+ 
+               /* switch to the appropriate memory context */
+               oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
+ 
+               /*
+                * allocate space and zero it
+                */
+               retval = (FuncCallContext *) palloc(sizeof(FuncCallContext));
+               MemSet(retval, 0, sizeof(FuncCallContext));
+ 
+               /*
+                * initialize the elements
+                */
+               retval->call_cntr = 0;
+               retval->max_calls = 0;
+               retval->slot = NULL;
+               retval->fctx = NULL;
+               retval->att_in_funcinfo = NULL;
+               retval->elements = NULL;
+               retval->fmctx = fcinfo->flinfo->fn_mcxt;
+ 
+               /*
+                * save the pointer for cross-call use
+                */
+               fcinfo->flinfo->fn_extra = retval;
+ 
+               /* back to the original memory context */
+               MemoryContextSwitchTo(oldcontext);
+       }
+       else    /* second and subsequent calls */
+               retval = fcinfo->flinfo->fn_extra;
+ 
+       return retval;
+ }
+ 
+ 
+ /*
+  * end_MultiFuncCall
+  * Clean up
+  */
+ void
+ end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
+ {
+       MemoryContext oldcontext;
+ 
+       /* unbind from fcinfo */
+       fcinfo->flinfo->fn_extra = NULL;
+ 
+       /*
+        * Caller is responsible to free up memory for individual
+        * struct elements other than att_in_funcinfo and elements.
+        */
+       oldcontext = MemoryContextSwitchTo(funcctx->fmctx);
+ 
+       if (funcctx->att_in_funcinfo != NULL)
+               pfree(funcctx->att_in_funcinfo);
+ 
+       if (funcctx->elements != NULL)
+               pfree(funcctx->elements);
+ 
+       pfree(funcctx);
+ 
+       MemoryContextSwitchTo(oldcontext);
+ }
+ 
+ 
+ static Oid
+ get_type_element(Oid type)
+ {
+       HeapTuple       typeTuple;
+       Oid                     result;
+ 
+       typeTuple = SearchSysCache(TYPEOID,
+                                                          ObjectIdGetDatum(type),
+                                                          0, 0, 0);
+       if (!HeapTupleIsValid(typeTuple))
+               elog(ERROR, "get_type_element: Cache lookup of type %u failed", type);
+       result = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
+       ReleaseSysCache(typeTuple);
+       return result;
+ }
+ 
+ 
+ static Oid
+ get_type_infunc(Type typ)
+ {
+       Form_pg_type typtup;
+ 
+       typtup = (Form_pg_type) GETSTRUCT(typ);
+ 
+       return typtup->typinput;
+ }
+ 
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   26 May 2002 02:06:52 -0000
***************
*** 0 ****
--- 1,15 ----
+ /*
+  * showguc.c
+  *
+  * Sample function to demonstrate a C function which returns setof composite.
+  *
+  * Copyright 2002 by PostgreSQL Global Development Group
+  * Cloned from src/backend/utils/misc/guc.c which was written by Peter Eisentraut
+  * <[EMAIL PROTECTED]>, and modified to suit.
+  */
+ #ifndef SHOWGUC_H
+ #define SHOWGUC_H
+ 
+ extern Datum showguc(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      26 May 2002 05:36:18 -0000
***************
*** 0 ****
--- 1,7 ----
+ CREATE TABLE __gucvar(
+   varname TEXT,
+   varval TEXT
+ );
+ 
+ CREATE FUNCTION showvars() RETURNS setof __gucvar
+   AS 'MODULE_PATHNAME','showguc' 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        26 May 2002 02:20:26 -0000
***************
*** 2539,2541 ****
--- 2539,2554 ----
  
        return newarray;
  }
+ 
+ struct config_generic **
+ get_guc_variables(void)
+ {
+       return guc_variables;
+ }
+ 
+ int
+ get_num_guc_variables(void)
+ {
+       return num_guc_variables;
+ }
+ 
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     26 May 2002 02:21:00 -0000
***************
*** 97,102 ****
--- 97,105 ----
  extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value);
  extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
  
+ extern struct config_generic **get_guc_variables(void);
+ extern int get_num_guc_variables(void);
+ 
  extern bool Debug_print_query;
  extern bool Debug_print_plan;
  extern bool Debug_print_parse;

---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster

Reply via email to