Re: Configuration parameters for plugin modules

From: Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us>
To: Thomas Hallgren <thhal(at)mailblocks(dot)com>
Cc: pgsql-patches(at)postgresql(dot)org
Subject: Re: Configuration parameters for plugin modules
Date: 2004-05-26 15:10:33
Message-ID: 200405261510.i4QFAXc04604@candle.pha.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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(at)candle(dot)pha(dot)pa(dot)us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073

In response to

Browse pgsql-patches by date

  From Date Subject
Next Message Bruce Momjian 2004-05-26 15:25:49 Re: new aggregate functions v4
Previous Message Bruce Momjian 2004-05-26 14:59:32 Re: pg_ctl.c