Re: Configuration parameters for plugin modules - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: Configuration parameters for plugin modules
Date
Msg-id 200405261510.i4QFAXc04604@candle.pha.pa.us
Whole thread Raw
In response to Re: Configuration parameters for plugin modules  (Thomas Hallgren <thhal@mailblocks.com>)
List pgsql-patches
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
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: pg_ctl.c
Next
From: Bruce Momjian
Date:
Subject: Re: new aggregate functions v4