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

Reply via email to