Patch applied.  Thanks.

As far as the documentation issues, these are all C interface issues, so
we usually just add comments into the C code for plugin developers to
use.  Feel free to submit those if they are not already there.

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


Thomas Hallgren wrote:
> Same patch as before but I added a small change to the gram.y enabling 
> SET command to use qualified names.
> 
> - thomas

> Index: doc/src/sgml/runtime.sgml
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/runtime.sgml,v
> retrieving revision 1.263
> diff -u -r1.263 runtime.sgml
> --- doc/src/sgml/runtime.sgml 29 Apr 2004 04:37:09 -0000      1.263
> +++ doc/src/sgml/runtime.sgml 19 May 2004 21:01:40 -0000
> @@ -2924,6 +2924,60 @@
>      </variablelist>
>     </sect2>
>  
> +   <sect2 id="runtime-config-custom">
> +    <title>Customized Options</title>
> +
> +    <para>
> +     The following was designed to allow options not normally known to
> +     <productname>PostgreSQL</productname> to be declared in the posgresql.conf
> +     file and/or manipulated using the <command>SET</command> in a controlled
> +     manner so that add-on modules to the postgres proper (such as lanugage
> +     mappings for triggers and functions) can be configured in a unified way.
> +    </para>
> +
> +    <variablelist>
> +
> +     <varlistentry id="guc-custom_variable_classes" 
> xreflabel="custom_variable_classes">
> +      <term><varname>custom_variable_classes</varname> (<type>string</type>)</term>
> +      <indexterm><primary>custom_variable_classes</></>
> +      <listitem>
> +       <para>
> +        This variable specifies one or several classes to be used for custom
> +        variables. A custom variable is a variable not normally known to
> +        the <productname>PostgreSQL</productname> proper but used by some add
> +        on module.
> +       </para>
> +
> +       <para>
> +        Aribtrary variables can be defined for each class specified here. Those
> +        variables will be treated as placeholders and have no meaning until the
> +        module that defines them is loaded. When a module for a specific class is
> +        loaded, it will add the proper variable definitions for the class
> +        associated with it, convert any placeholder values according to those
> +        definitions, and issue warnings for any placeholders that then remains.
> +       </para>
> +       
> +       <para>
> +        Here is an example what custom variables might look like:
> +
> +<programlisting>
> +custom_variable_class = 'plr,pljava'
> +plr.foo = '/usr/lib/R'
> +pljava.baz = 1
> +plruby.var = true        <== this one would generate an error
> +</programlisting>
> +       </para>
> +
> +       <para>
> +        This option can only be set at server start or in the
> +        <filename>postgresql.conf</filename> configuration file.
> +       </para>
> +
> +      </listitem>
> +     </varlistentry>
> +    </variablelist>
> +     </sect2>
> +
>     <sect2 id="runtime-config-developer">
>      <title>Developer Options</title>
>  
> Index: src/backend/parser/gram.y
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/gram.y,v
> retrieving revision 2.454
> diff -u -r2.454 gram.y
> --- src/backend/parser/gram.y 10 May 2004 22:44:45 -0000      2.454
> +++ src/backend/parser/gram.y 19 May 2004 21:01:43 -0000
> @@ -309,7 +309,7 @@
>  %type <str>          Sconst comment_text
>  %type <str>          UserId opt_boolean ColId_or_Sconst
>  %type <list> var_list var_list_or_default
> -%type <str>          ColId ColLabel type_name param_name
> +%type <str>          ColId ColLabel var_name type_name param_name
>  %type <node> var_value zone_value
>  
>  %type <keyword> unreserved_keyword func_name_keyword
> @@ -857,14 +857,14 @@
>                               }
>               ;
>  
> -set_rest:  ColId TO var_list_or_default
> +set_rest:  var_name TO var_list_or_default
>                               {
>                                       VariableSetStmt *n = makeNode(VariableSetStmt);
>                                       n->name = $1;
>                                       n->args = $3;
>                                       $$ = n;
>                               }
> -                     | ColId '=' var_list_or_default
> +                     | var_name '=' var_list_or_default
>                               {
>                                       VariableSetStmt *n = makeNode(VariableSetStmt);
>                                       n->name = $1;
> @@ -914,6 +914,19 @@
>                                       n->name = "session_authorization";
>                                       n->args = NIL;
>                                       $$ = n;
> +                             }
> +             ;
> +
> +var_name:
> +                     ColId                                                          
>  { $$ = $1; }
> +                     | var_name '.' ColId
> +                             {
> +                                     int qLen = strlen($1);
> +                                     char* qualName = palloc(qLen + strlen($3) + 2);
> +                                     strcpy(qualName, $1);
> +                                     qualName[qLen] = '.';
> +                                     strcpy(qualName + qLen + 1, $3);
> +                                     $$ = qualName;
>                               }
>               ;
>  
> Index: src/backend/utils/misc/guc-file.l
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/misc/guc-file.l,v
> retrieving revision 1.21
> diff -u -r1.21 guc-file.l
> --- src/backend/utils/misc/guc-file.l 24 Feb 2004 22:06:32 -0000      1.21
> +++ src/backend/utils/misc/guc-file.l 19 May 2004 21:01:43 -0000
> @@ -34,6 +34,7 @@
>       GUC_REAL = 4,
>       GUC_EQUALS = 5,
>       GUC_UNQUOTED_STRING = 6,
> +     GUC_QUALIFIED_ID = 7,
>       GUC_EOL = 99,
>       GUC_ERROR = 100
>  };
> @@ -65,6 +66,7 @@
>  LETTER_OR_DIGIT [A-Za-z_0-9\200-\377]
>  
>  ID              {LETTER}{LETTER_OR_DIGIT}*
> +QUALIFIED_ID    {ID}"."{ID}
>  
>  UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
>  STRING          \'([^'\n]|\\.)*\'
> @@ -76,6 +78,7 @@
>  #.*$            /* eat comment */
>  
>  {ID}            return GUC_ID;
> +{QUALIFIED_ID}  return GUC_QUALIFIED_ID;
>  {STRING}        return GUC_STRING;
>  {UNQUOTED_STRING} return GUC_UNQUOTED_STRING;
>  {INTEGER}       return GUC_INTEGER;
> @@ -180,7 +183,7 @@
>              case 0: /* no previous input */
>                  if (token == GUC_EOL) /* empty line */
>                      continue;
> -                if (token != GUC_ID)
> +                if (token != GUC_ID && token != GUC_QUALIFIED_ID)
>                      goto parse_error;
>                  opt_name = strdup(yytext);
>                               if (opt_name == NULL)
> @@ -216,6 +219,24 @@
>              case 2: /* now we'd like an end of line */
>                               if (token != GUC_EOL)
>                                       goto parse_error;
> +
> +                             if (strcmp(opt_name, "custom_variable_classes") == 0)
> +                             {
> +                                     /* This variable must be added first as it 
> controls the validity
> +                                      * of other variables
> +                                      */
> +                                     if (!set_config_option(opt_name, opt_value, 
> context,
> +                                                                                
> PGC_S_FILE, false, true))
> +                                     {
> +                                             FreeFile(fp);
> +                                             free(filename);
> +                                             goto cleanup_exit;
> +                                     }
> +
> +                                     /* Don't include in list */
> +                                     parse_state = 0;
> +                                     break;
> +                             }
>  
>                               /* append to list */
>                               item = malloc(sizeof *item);
> Index: src/backend/utils/misc/guc.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v
> retrieving revision 1.205
> diff -u -r1.205 guc.c
> --- src/backend/utils/misc/guc.c      8 May 2004 02:11:46 -0000       1.205
> +++ src/backend/utils/misc/guc.c      19 May 2004 21:01:44 -0000
> @@ -20,6 +20,7 @@
>  #include <float.h>
>  #include <limits.h>
>  #include <unistd.h>
> +#include <ctype.h>
>  
>  #include "utils/guc.h"
>  #include "utils/guc_tables.h"
> @@ -103,6 +104,8 @@
>  static const char *assign_log_stmtlvl(int *var, const char *newval,
>                                                  bool doit, GucSource source);
>  static bool assign_phony_autocommit(bool newval, bool doit, GucSource source);
> +static const char *assign_custom_variable_classes(const char *newval, bool doit,
> +                                                GucSource source);
>  static bool assign_stage_log_stats(bool newval, bool doit, GucSource source);
>  static bool assign_log_stats(bool newval, bool doit, GucSource source);
>  
> @@ -167,6 +170,7 @@
>  static char *session_authorization_string;
>  static char *timezone_string;
>  static char *XactIsoLevel_string;
> +static char *custom_variable_classes;
>  static int   max_function_args;
>  static int   max_index_keys;
>  static int   max_identifier_length;
> @@ -1728,6 +1732,16 @@
>               XLOG_sync_method_default, assign_xlog_sync_method, NULL
>       },
>  
> +     {
> +             {"custom_variable_classes", PGC_POSTMASTER, RESOURCES_KERNEL,
> +                     gettext_noop("Sets the list of known custom variable classes"),
> +                     NULL,
> +                     GUC_LIST_INPUT | GUC_LIST_QUOTE
> +             },
> +             &custom_variable_classes,
> +             NULL, assign_custom_variable_classes, NULL
> +     },
> +
>       /* End-of-list marker */
>       {
>               {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
> @@ -1753,8 +1767,15 @@
>  /*
>   * Actual lookup of variables is done through this single, sorted array.
>   */
> -struct config_generic **guc_variables;
> -int                  num_guc_variables;
> +static struct config_generic **guc_variables;
> +
> +/* Current number of variables contained in the vector
> + */
> +static int num_guc_variables;
> +
> +/* Vector capacity
> + */
> +static int size_guc_variables;
>  
>  static bool guc_dirty;                       /* TRUE if need to do commit/abort 
> work */
>  
> @@ -1768,6 +1789,10 @@
>  static void ReportGUCOption(struct config_generic * record);
>  static char *_ShowOption(struct config_generic * record);
>  
> +struct config_generic** get_guc_variables()
> +{
> +     return guc_variables;
> +}
>  
>  /*
>   * Build the sorted array.   This is split out so that it could be
> @@ -1777,6 +1802,7 @@
>  void
>  build_guc_variables(void)
>  {
> +     int         size_vars;
>       int                     num_vars = 0;
>       struct config_generic **guc_vars;
>       int                     i;
> @@ -1814,8 +1840,12 @@
>               num_vars++;
>       }
>  
> +     /* Create table with 20% slack
> +      */
> +     size_vars = num_vars + num_vars / 4;
> +
>       guc_vars = (struct config_generic **)
> -             malloc(num_vars * sizeof(struct config_generic *));
> +             malloc(size_vars * sizeof(struct config_generic *));
>       if (!guc_vars)
>               ereport(FATAL,
>                               (errcode(ERRCODE_OUT_OF_MEMORY),
> @@ -1835,15 +1865,105 @@
>       for (i = 0; ConfigureNamesString[i].gen.name; i++)
>               guc_vars[num_vars++] = &ConfigureNamesString[i].gen;
>  
> -     qsort((void *) guc_vars, num_vars, sizeof(struct config_generic *),
> -               guc_var_compare);
> -
>       if (guc_variables)
>               free(guc_variables);
>       guc_variables = guc_vars;
>       num_guc_variables = num_vars;
> +     size_guc_variables = size_vars;
> +     qsort((void*) guc_variables, num_guc_variables,
> +             sizeof(struct config_generic*), guc_var_compare);
> +}
> +
> +static bool
> +is_custom_class(const char *name, int dotPos)
> +{
> +     /* The assign_custom_variable_classes has made sure no empty
> +      * identifiers or whitespace exists in the variable
> +      */
> +     bool result = false;
> +     const char *ccs = GetConfigOption("custom_variable_classes");
> +     if(ccs != NULL)
> +     {
> +             const char *start = ccs;
> +             for(;; ++ccs)
> +             {
> +                     int c = *ccs;
> +                     if(c == 0 || c == ',')
> +                     {
> +                             if(dotPos == ccs - start && strncmp(start, name, 
> dotPos) == 0)
> +                             {
> +                                     result = true;
> +                                     break;
> +                             }
> +                             if(c == 0)
> +                                     break;
> +                             start = ccs + 1;
> +                     }
> +             }
> +     }
> +     return result;
>  }
>  
> +/*
> + * Add a new GUC variable to the list of known variables. The
> + * list is expanded if needed.
> + */
> +static void
> +add_guc_variable(struct config_generic *var)
> +{
> +     if(num_guc_variables + 1 >= size_guc_variables)
> +     {
> +             /* Increase the vector with 20%
> +              */
> +             int size_vars = size_guc_variables + size_guc_variables / 4;
> +             if(size_vars == 0)
> +                     size_vars = 100;
> +
> +             struct config_generic** guc_vars = (struct config_generic**)
> +                     malloc(size_vars * sizeof(struct config_generic*));
> +
> +             if (guc_variables != NULL)
> +             {
> +                     memcpy(guc_vars, guc_variables,
> +                                     num_guc_variables * sizeof(struct 
> config_generic*));
> +                     free(guc_variables);
> +             }
> +
> +             guc_variables = guc_vars;
> +             size_guc_variables = size_vars;
> +     }
> +     guc_variables[num_guc_variables++] = var;
> +     qsort((void*) guc_variables, num_guc_variables,
> +             sizeof(struct config_generic*), guc_var_compare);
> +}
> +
> +/*
> + * Create and add a placeholder variable. Its presumed to belong
> + * to a valid custom variable class at this point.
> + */
> +static struct config_string*
> +add_placeholder_variable(const char *name)
> +{
> +     size_t sz = sizeof(struct config_string) + sizeof(char*);
> +     struct config_string*  var = (struct config_string*)malloc(sz);
> +     struct config_generic* gen = &var->gen;
> +
> +     memset(var, 0, sz);
> +
> +     gen->name       = strdup(name);
> +     gen->context    = PGC_USERSET;
> +     gen->group      = CUSTOM_OPTIONS;
> +     gen->short_desc = "GUC placeholder variable";
> +     gen->flags      = GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_CUSTOM_PLACEHOLDER;
> +     gen->vartype    = PGC_STRING;
> +
> +     /* The char* is allocated at the end of the struct since we have
> +      * no 'static' place to point to.
> +      */     
> +     var->variable = (char**)(var + 1);
> +     add_guc_variable((struct config_generic*)var);
> +     return var;
> +}
>  
>  /*
>   * Look up option NAME. If it exists, return a pointer to its record,
> @@ -1852,6 +1972,7 @@
>  static struct config_generic *
>  find_option(const char *name)
>  {
> +     const char *dot;
>       const char **key = &name;
>       struct config_generic **res;
>       int                     i;
> @@ -1881,6 +2002,16 @@
>                       return find_option(map_old_guc_names[i+1]);
>       }
>  
> +     /* Check if the name is qualified, and if so, check if the qualifier
> +      * maps to a custom variable class.
> +      */
> +     dot = strchr(name, GUC_QUALIFIER_SEPARATOR);
> +     if(dot != NULL && is_custom_class(name, dot - name))
> +             /*
> +              * Add a placeholder variable for this name
> +              */
> +             return (struct config_generic*)add_placeholder_variable(name);
> +
>       /* Unknown name */
>       return NULL;
>  }
> @@ -3459,6 +3590,196 @@
>       PG_RETURN_TEXT_P(result_text);
>  }
>  
> +static void
> +define_custom_variable(struct config_generic* variable)
> +{
> +     const char* name = variable->name;
> +     const char** nameAddr = &name;
> +     const char* value;
> +     struct config_string*   pHolder;
> +     struct config_generic** res = (struct config_generic**)bsearch(
> +                                                                                    
>  (void*)&nameAddr,
> +                                                                                    
>  (void*)guc_variables,
> +                                                                                    
>  num_guc_variables,
> +                                                                                    
>  sizeof(struct config_generic*),
> +                                                                                    
>  guc_var_compare);
> +
> +     if(res == NULL)
> +     {
> +             add_guc_variable(variable);
> +             return;
> +     }
> +
> +     /* This better be a placeholder
> +      */
> +     if(((*res)->flags & GUC_CUSTOM_PLACEHOLDER) == 0)
> +     {
> +             ereport(ERROR,
> +                             (errcode(ERRCODE_INTERNAL_ERROR),
> +                              errmsg("attempt to redefine parameter \"%s\"", 
> name)));
> +     }
> +     pHolder = (struct config_string*)*res;
> +     
> +     /* We have the same name, no sorting is necessary.
> +      */
> +     *res = variable;
> +
> +     value = *pHolder->variable;
> +
> +     /* Assign the variable stored in the placeholder to the real
> +      * variable.
> +      */
> +     set_config_option(name, value,
> +                               pHolder->gen.context, pHolder->gen.source,
> +                               false, true);
> +
> +     /* Free up stuff occupied by the placeholder variable
> +      */
> +     if(value != NULL)
> +             free((void*)value);
> +
> +     if(pHolder->reset_val != NULL && pHolder->reset_val != value)
> +             free(pHolder->reset_val);
> +
> +     if(pHolder->session_val != NULL
> +     && pHolder->session_val != value
> +     && pHolder->session_val != pHolder->reset_val)
> +             free(pHolder->session_val);
> +
> +     if(pHolder->tentative_val != NULL
> +     && pHolder->tentative_val != value
> +     && pHolder->tentative_val != pHolder->reset_val
> +     && pHolder->tentative_val != pHolder->session_val)
> +             free(pHolder->tentative_val);
> +
> +     free(pHolder);
> +}
> +
> +static void init_custom_variable(
> +     struct config_generic* gen,
> +     const char* name,
> +     const char* short_desc,
> +     const char* long_desc,
> +     GucContext  context,
> +     enum config_type type)
> +{
> +     gen->name       = strdup(name);
> +     gen->context    = context;
> +     gen->group      = CUSTOM_OPTIONS;
> +     gen->short_desc = short_desc;
> +     gen->long_desc  = long_desc;
> +     gen->vartype    = type;
> +}
> +
> +void DefineCustomBoolVariable(
> +     const char* name,
> +     const char* short_desc,
> +     const char* long_desc,
> +     bool*       valueAddr,
> +     GucContext  context,
> +     GucBoolAssignHook assign_hook,
> +     GucShowHook show_hook)
> +{
> +     size_t sz = sizeof(struct config_bool);
> +     struct config_bool*  var = (struct config_bool*)malloc(sz);
> +
> +     memset(var, 0, sz);
> +     init_custom_variable(&var->gen, name, short_desc, long_desc, context, 
> PGC_BOOL);
> +
> +     var->variable    = valueAddr;
> +     var->reset_val   = *valueAddr;
> +     var->assign_hook = assign_hook;
> +     var->show_hook   = show_hook;
> +     define_custom_variable(&var->gen);
> +}
> +
> +void DefineCustomIntVariable(
> +     const char* name,
> +     const char* short_desc,
> +     const char* long_desc,
> +     int*        valueAddr,
> +     GucContext  context,
> +     GucIntAssignHook assign_hook,
> +     GucShowHook show_hook)
> +{
> +     size_t sz = sizeof(struct config_int);
> +     struct config_int*  var = (struct config_int*)malloc(sz);
> +
> +     memset(var, 0, sz);
> +     init_custom_variable(&var->gen, name, short_desc, long_desc, context, PGC_INT);
> +
> +     var->variable    = valueAddr;
> +     var->reset_val   = *valueAddr;
> +     var->assign_hook = assign_hook;
> +     var->show_hook   = show_hook;
> +     define_custom_variable(&var->gen);
> +}
> +
> +void DefineCustomRealVariable(
> +     const char* name,
> +     const char* short_desc,
> +     const char* long_desc,
> +     double*     valueAddr,
> +     GucContext  context,
> +     GucRealAssignHook assign_hook,
> +     GucShowHook show_hook)
> +{
> +     size_t sz = sizeof(struct config_real);
> +     struct config_real*  var = (struct config_real*)malloc(sz);
> +
> +     memset(var, 0, sz);
> +     init_custom_variable(&var->gen, name, short_desc, long_desc, context, 
> PGC_REAL);
> +
> +     var->variable    = valueAddr;
> +     var->reset_val   = *valueAddr;
> +     var->assign_hook = assign_hook;
> +     var->show_hook   = show_hook;
> +     define_custom_variable(&var->gen);
> +}
> +
> +void DefineCustomStringVariable(
> +     const char* name,
> +     const char* short_desc,
> +     const char* long_desc,
> +     char**      valueAddr,
> +     GucContext  context,
> +     GucStringAssignHook assign_hook,
> +     GucShowHook show_hook)
> +{
> +     size_t sz = sizeof(struct config_string);
> +     struct config_string*  var = (struct config_string*)malloc(sz);
> +
> +     memset(var, 0, sz);
> +     init_custom_variable(&var->gen, name, short_desc, long_desc, context, 
> PGC_STRING);
> +
> +     var->variable    = valueAddr;
> +     var->reset_val   = *valueAddr;
> +     var->assign_hook = assign_hook;
> +     var->show_hook   = show_hook;
> +     define_custom_variable(&var->gen);
> +}
> +
> +extern void EmittWarningsOnPlaceholders(const char* className)
> +{
> +     struct config_generic** vars = guc_variables;
> +     struct config_generic** last = vars + num_guc_variables;
> +
> +     int nameLen = strlen(className);
> +     while(vars < last)
> +     {
> +             struct config_generic* var = *vars++;
> +             if((var->flags & GUC_CUSTOM_PLACEHOLDER) != 0 &&
> +                strncmp(className, var->name, nameLen) == 0 &&
> +                var->name[nameLen] == GUC_QUALIFIER_SEPARATOR)
> +             {
> +                     ereport(INFO,
> +                             (errcode(ERRCODE_UNDEFINED_OBJECT),
> +                              errmsg("unrecognized configuration parameter \"%s\"", 
> var->name)));
> +             }
> +     }
> +}
> +
> +
>  /*
>   * SHOW command
>   */
> @@ -4710,6 +5031,68 @@
>       return true;
>  }
>  
> +static const char *
> +assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
> +{
> +     /* Check syntax. newval must be a comma separated list of identifiers.
> +      * Whitespace is allowed but skipped.
> +      */
> +     bool hasSpaceAfterToken = false;
> +     const char *cp = newval;
> +     int symLen = 0;
> +     int c;
> +     StringInfoData buf;
> +
> +     initStringInfo(&buf);
> +     while((c = *cp++) != 0)
> +     {
> +             if(isspace(c))
> +             {
> +                     if(symLen > 0)
> +                             hasSpaceAfterToken = true;
> +                     continue;
> +             }
> +
> +             if(c == ',')
> +             {
> +                     hasSpaceAfterToken = false;
> +                     if(symLen > 0)
> +                     {
> +                             symLen = 0;
> +                             appendStringInfoChar(&buf, ',');
> +                     }
> +                     continue;
> +             }
> +
> +             if(hasSpaceAfterToken || !isalnum(c))
> +             {
> +                     /* Syntax error due to token following space after
> +                      * token or non alpha numeric character
> +                      */
> +                     pfree(buf.data);
> +                     ereport(WARNING,
> +                                     (errcode(ERRCODE_SYNTAX_ERROR),
> +                                      errmsg("illegal syntax for 
> custom_variable_classes \"%s\"", newval)));
> +                     return NULL;
> +             }
> +             symLen++;
> +             appendStringInfoChar(&buf, (char)c);
> +     }
> +
> +     if(symLen == 0 && buf.len > 0)
> +             /*
> +              * Remove stray ',' at end
> +              */
> +             buf.data[--buf.len] = 0;
> +
> +     if(buf.len == 0)
> +             newval = NULL;
> +     else if(doit)
> +             newval = strdup(buf.data);
> +
> +     pfree(buf.data);
> +     return newval;
> +}
>  
>  static bool
>  assign_stage_log_stats(bool newval, bool doit, GucSource source)
> Index: src/backend/utils/misc/help_config.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/misc/help_config.c,v
> retrieving revision 1.9
> diff -u -r1.9 help_config.c
> --- src/backend/utils/misc/help_config.c      29 Nov 2003 19:52:04 -0000      1.9
> +++ src/backend/utils/misc/help_config.c      19 May 2004 21:01:44 -0000
> @@ -47,13 +47,15 @@
>  GucInfoMain(void)
>  {
>       int                     i;
> +     struct config_generic **guc_vars = get_guc_variables();
> +     int numOpts = GetNumConfigOptions();
>  
>       /* Initialize the guc_variables[] array */
>       build_guc_variables();
>  
> -     for (i = 0; i < num_guc_variables; i++)
> +     for (i = 0; i < numOpts; i++)
>       {
> -             mixedStruct *var = (mixedStruct *) guc_variables[i];
> +             mixedStruct *var = (mixedStruct *) guc_vars[i];
>  
>               if (displayStruct(var))
>                       printMixedStruct(var);
> Index: src/include/utils/guc.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/include/utils/guc.h,v
> retrieving revision 1.45
> diff -u -r1.45 guc.h
> --- src/include/utils/guc.h   7 Apr 2004 05:05:50 -0000       1.45
> +++ src/include/utils/guc.h   19 May 2004 21:01:45 -0000
> @@ -102,6 +102,15 @@
>       PGC_S_SESSION                           /* SET command */
>  } GucSource;
>  
> +typedef const char* (*GucStringAssignHook)(const char *newval, bool doit, GucSource 
> source);
> +typedef bool (*GucBoolAssignHook)(bool newval, bool doit, GucSource source);
> +typedef bool (*GucIntAssignHook)(int newval, bool doit, GucSource source);
> +typedef bool (*GucRealAssignHook)(double newval, bool doit, GucSource source);
> +
> +typedef const char* (*GucShowHook)(void);
> +
> +#define GUC_QUALIFIER_SEPARATOR '.'
> +
>  /* GUC vars that are actually declared in guc.c, rather than elsewhere */
>  extern bool log_duration;
>  extern bool Debug_print_plan;
> @@ -129,6 +138,45 @@
>  
>  extern void SetConfigOption(const char *name, const char *value,
>                               GucContext context, GucSource source);
> +
> +extern void DefineCustomBoolVariable(
> +     const char* name,
> +     const char* short_desc,
> +     const char* long_desc,
> +     bool*       valueAddr,
> +     GucContext  context,
> +     GucBoolAssignHook assign_hook,
> +     GucShowHook show_hook);
> +
> +extern void DefineCustomIntVariable(
> +     const char* name,
> +     const char* short_desc,
> +     const char* long_desc,
> +     int*        valueAddr,
> +     GucContext  context,
> +     GucIntAssignHook assign_hook,
> +     GucShowHook show_hook);
> +
> +extern void DefineCustomRealVariable(
> +     const char* name,
> +     const char* short_desc,
> +     const char* long_desc,
> +     double*     valueAddr,
> +     GucContext  context,
> +     GucRealAssignHook assign_hook,
> +     GucShowHook show_hook);
> +
> +extern void DefineCustomStringVariable(
> +     const char* name,
> +     const char* short_desc,
> +     const char* long_desc,
> +     char**      valueAddr,
> +     GucContext  context,
> +     GucStringAssignHook assign_hook,
> +     GucShowHook show_hook);
> +
> +extern void EmittWarningsOnPlaceholders(const char* className);
> +
>  extern const char *GetConfigOption(const char *name);
>  extern const char *GetConfigOptionResetString(const char *name);
>  extern void ProcessConfigFile(GucContext context);
> Index: src/include/utils/guc_tables.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/include/utils/guc_tables.h,v
> retrieving revision 1.10
> diff -u -r1.10 guc_tables.h
> --- src/include/utils/guc_tables.h    5 Apr 2004 03:02:11 -0000       1.10
> +++ src/include/utils/guc_tables.h    19 May 2004 21:01:45 -0000
> @@ -51,7 +51,8 @@
>       COMPAT_OPTIONS_PREVIOUS,
>       COMPAT_OPTIONS_CLIENT,
>       DEVELOPER_OPTIONS,
> -     COMPILE_OPTIONS
> +     COMPILE_OPTIONS,
> +     CUSTOM_OPTIONS
>  };
>  
>  /*
> @@ -98,6 +99,7 @@
>  #define GUC_REPORT                           0x0010  /* auto-report changes to 
> client */
>  #define GUC_NOT_IN_SAMPLE            0x0020  /* not in postgresql.conf.sample */
>  #define GUC_DISALLOW_IN_FILE 0x0040  /* can't set in postgresql.conf */
> +#define GUC_CUSTOM_PLACEHOLDER       0x0080  /* placeholder for a custom variable */
>  
>  /* bit values in status field */
>  #define GUC_HAVE_TENTATIVE   0x0001          /* tentative value is defined */
> @@ -113,8 +115,8 @@
>       /* (all but reset_val are constants) */
>       bool       *variable;
>       bool            reset_val;
> -     bool            (*assign_hook) (bool newval, bool doit, GucSource source);
> -     const char *(*show_hook) (void);
> +     GucBoolAssignHook assign_hook;
> +     GucShowHook show_hook;
>       /* variable fields, initialized at runtime: */
>       bool            session_val;
>       bool            tentative_val;
> @@ -129,8 +131,8 @@
>       int                     reset_val;
>       int                     min;
>       int                     max;
> -     bool            (*assign_hook) (int newval, bool doit, GucSource source);
> -     const char *(*show_hook) (void);
> +     GucIntAssignHook assign_hook;
> +     GucShowHook show_hook;
>       /* variable fields, initialized at runtime: */
>       int                     session_val;
>       int                     tentative_val;
> @@ -145,8 +147,8 @@
>       double          reset_val;
>       double          min;
>       double          max;
> -     bool            (*assign_hook) (double newval, bool doit, GucSource source);
> -     const char *(*show_hook) (void);
> +     GucRealAssignHook assign_hook;
> +     GucShowHook show_hook;
>       /* variable fields, initialized at runtime: */
>       double          session_val;
>       double          tentative_val;
> @@ -159,8 +161,8 @@
>       /* (all are constants) */
>       char      **variable;
>       const char *boot_val;
> -     const char *(*assign_hook) (const char *newval, bool doit, GucSource source);
> -     const char *(*show_hook) (void);
> +     GucStringAssignHook assign_hook;
> +     GucShowHook show_hook;
>       /* variable fields, initialized at runtime: */
>       char       *reset_val;
>       char       *session_val;
> @@ -173,9 +175,8 @@
>  extern const char *const GucContext_Names[];
>  extern const char *const GucSource_Names[];
>  
> -/* the current set of variables */
> -extern struct config_generic **guc_variables;
> -extern int   num_guc_variables;
> +/* get the current set of variables */
> +extern struct config_generic **get_guc_variables(void);
>  
>  extern void build_guc_variables(void);
>  

> 
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
> 
>                http://archives.postgresql.org

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  [EMAIL PROTECTED]               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

               http://archives.postgresql.org

Reply via email to