</variablelist>
<para>
- In order to set these parameters in your <filename>postgresql.conf</> file,
- you will need to add <literal>auth_delay</> to
- <xref linkend="guc-custom-variable-classes">. Typical usage might be:
+ These parameters must be set in <filename>postgresql.conf</>.
+ Typical usage might be:
</para>
<programlisting>
# postgresql.conf
shared_preload_libraries = 'auth_delay'
-custom_variable_classes = 'auth_delay'
auth_delay.milliseconds = '500'
</programlisting>
</sect2>
</variablelist>
<para>
- In order to set these parameters in your <filename>postgresql.conf</> file,
- you will need to add <literal>auto_explain</> to
- <xref linkend="guc-custom-variable-classes">. Typical usage might be:
+ These parameters must be set in <filename>postgresql.conf</>.
+ Typical usage might be:
</para>
<programlisting>
# postgresql.conf
shared_preload_libraries = 'auto_explain'
-custom_variable_classes = 'auto_explain'
auto_explain.log_min_duration = '3s'
</programlisting>
</sect2>
<para>
This feature was designed to allow parameters not normally known to
<productname>PostgreSQL</productname> to be added by add-on modules
- (such as procedural languages). This allows add-on modules to be
+ (such as procedural languages). This allows extension modules to be
configured in the standard ways.
</para>
- <variablelist>
-
- <varlistentry id="guc-custom-variable-classes" xreflabel="custom_variable_classes">
- <term><varname>custom_variable_classes</varname> (<type>string</type>)</term>
- <indexterm>
- <primary><varname>custom_variable_classes</> configuration parameter</primary>
- </indexterm>
- <listitem>
- <para>
- This variable specifies one or several class names to be used for
- custom variables, in the form of a comma-separated list. A custom
- variable is a variable not normally known
- to <productname>PostgreSQL</productname> proper but used by some
- add-on module. Such variables must have names consisting of a class
- name, a dot, and a variable name. <varname>custom_variable_classes</>
- specifies all the class names in use in a particular installation.
- This parameter can only be set in the <filename>postgresql.conf</>
- file or on the server command line.
- </para>
-
- </listitem>
- </varlistentry>
- </variablelist>
-
<para>
- The difficulty with setting custom variables in
- <filename>postgresql.conf</> is that the file must be read before add-on
- modules have been loaded, and so custom variables would ordinarily be
- rejected as unknown. When <varname>custom_variable_classes</> is set,
- the server will accept definitions of arbitrary variables within each
- specified class. These variables will be treated as placeholders and
- will have no function 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 its class name, convert any placeholder
- values according to those definitions, and issue warnings for any
- unrecognized placeholders of its class that remain.
+ Custom options have two-part names: an extension name, then a dot, then
+ the parameter name proper, much like qualified names in SQL. An example
+ is <literal>plpgsql.variable_conflict</>.
</para>
<para>
- Here is an example of what <filename>postgresql.conf</> might contain
- when using custom variables:
-
-<programlisting>
-custom_variable_classes = 'plpgsql,plperl'
-plpgsql.variable_conflict = use_variable
-plperl.use_strict = true
-plruby.use_strict = true # generates error: unknown class name
-</programlisting>
+ Because custom options may need to be set in processes that have not
+ loaded the relevant extension module, <productname>PostgreSQL</>
+ will accept a setting for any two-part parameter name. Such variables
+ are treated as placeholders and have no function until the module that
+ defines them is loaded. When an extension module is loaded, it will add
+ its variable definitions, convert any placeholder values according to
+ those definitions, and issue warnings for any unrecognized placeholders
+ that begin with its extension name.
</para>
</sect1>
</para>
<para>
- In order to set any of these parameters in your
- <filename>postgresql.conf</> file,
- you will need to add <literal>pg_stat_statements</> to
- <xref linkend="guc-custom-variable-classes">. Typical usage might be:
+ These parameters must be set in <filename>postgresql.conf</>.
+ Typical usage might be:
<programlisting>
# postgresql.conf
shared_preload_libraries = 'pg_stat_statements'
-custom_variable_classes = 'pg_stat_statements'
pg_stat_statements.max = 10000
pg_stat_statements.track = all
</programlisting>
<para>
This section lists configuration parameters that affect <application>PL/Perl</>.
- To set any of these parameters before <application>PL/Perl</> has been loaded,
- it is necessary to have added <quote><literal>plperl</></> to the
- <xref linkend="guc-custom-variable-classes"> list in
- <filename>postgresql.conf</filename>.
</para>
<variablelist>
<literal>use_column</> (where <literal>error</> is the factory default).
This parameter affects subsequent compilations
of statements in <application>PL/pgSQL</> functions, but not statements
- already compiled in the current session. To set the parameter before
- <application>PL/pgSQL</> has been loaded, it is necessary to have added
- <quote><literal>plpgsql</></> to the <xref
- linkend="guc-custom-variable-classes"> list in
- <filename>postgresql.conf</filename>. Because changing this setting
+ already compiled in the current session.
+ Because changing this setting
can cause unexpected changes in the behavior of <application>PL/pgSQL</>
functions, it can only be changed by a superuser.
</para>
ConfigVariable *item,
*head,
*tail;
- char *cvc = NULL;
- struct config_string *cvc_struct;
int i;
/*
goto cleanup_list;
}
- /*
- * We need the proposed new value of custom_variable_classes to check
- * custom variables with. ParseConfigFile ensured that if it's in
- * the file, it's first in the list. But first check to see if we
- * have an active value from the command line, which should override
- * the file in any case. (Since there's no relevant env var, the
- * only possible nondefault sources are the file and ARGV.)
- */
- cvc_struct = (struct config_string *)
- find_option("custom_variable_classes", false, elevel);
- Assert(cvc_struct);
- if (cvc_struct->gen.reset_source > PGC_S_FILE)
- {
- cvc = guc_strdup(elevel, cvc_struct->reset_val);
- if (cvc == NULL)
- {
- error = true;
- goto cleanup_list;
- }
- }
- else if (head != NULL &&
- guc_name_compare(head->name, "custom_variable_classes") == 0)
- {
- /*
- * Need to canonicalize the value by calling the check hook.
- */
- void *extra = NULL;
-
- cvc = guc_strdup(elevel, head->value);
- if (cvc == NULL)
- {
- error = true;
- goto cleanup_list;
- }
- if (!call_string_check_hook(cvc_struct, &cvc, &extra,
- PGC_S_FILE, elevel))
- {
- error = true;
- goto cleanup_list;
- }
- if (extra)
- free(extra);
- }
-
/*
* Mark all extant GUC variables as not present in the config file.
* We need this so that we can tell below which ones have been removed
* quasi-syntactic check on the validity of the config file. It is
* important that the postmaster and all backends agree on the results
* of this phase, else we will have strange inconsistencies about which
- * processes accept a config file update and which don't. Hence, custom
- * variable names can only be checked against custom_variable_classes,
- * not against any loadable modules that might (or might not) be present.
- * Likewise, we don't attempt to validate the options' values here.
+ * processes accept a config file update and which don't. Hence, unknown
+ * custom variable names have to be accepted without complaint. For the
+ * same reason, we don't attempt to validate the options' values here.
*
* In addition, the GUC_IS_IN_FILE flag is set on each existing GUC
* variable mentioned in the file.
*/
for (item = head; item; item = item->next)
{
- char *sep = strchr(item->name, GUC_QUALIFIER_SEPARATOR);
struct config_generic *record;
- if (sep)
- {
- /* Custom variable, so check against custom_variable_classes */
- if (!is_custom_class(item->name, sep - item->name, cvc))
- {
- ereport(elevel,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\" in file \"%s\" line %u",
- item->name,
- item->filename, item->sourceline)));
- error = true;
- continue;
- }
- }
-
+ /*
+ * Try to find the variable; but do not create a custom placeholder
+ * if it's not there already.
+ */
record = find_option(item->name, false, elevel);
if (record)
+ {
+ /* Found, so mark it as present in file */
record->status |= GUC_IS_IN_FILE;
- else if (!sep)
+ }
+ else if (strchr(item->name, GUC_QUALIFIER_SEPARATOR) == NULL)
{
/* Invalid non-custom variable, so complain */
ereport(elevel,
cleanup_list:
FreeConfigVariables(head);
- if (cvc)
- free(cvc);
if (error)
{
pfree(opt_name);
pfree(opt_value);
}
- else if (guc_name_compare(opt_name, "custom_variable_classes") == 0)
- {
- /*
- * This variable must be processed first as it controls
- * the validity of other variables; so it goes at the head
- * of the result list. If we already found a value for it,
- * replace with this one.
- */
- item = *head_p;
- if (item != NULL &&
- guc_name_compare(item->name, "custom_variable_classes") == 0)
- {
- /* replace existing head item */
- pfree(item->name);
- pfree(item->value);
- item->name = opt_name;
- item->value = opt_value;
- item->filename = pstrdup(config_file);
- item->sourceline = ConfigFileLineno-1;
- }
- else
- {
- /* prepend to list */
- item = palloc(sizeof *item);
- item->name = opt_name;
- item->value = opt_value;
- item->filename = pstrdup(config_file);
- item->sourceline = ConfigFileLineno-1;
- item->next = *head_p;
- *head_p = item;
- if (*tail_p == NULL)
- *tail_p = item;
- }
- }
else
{
/* ordinary variable, append to list */
static void assign_session_replication_role(int newval, void *extra);
static bool check_temp_buffers(int *newval, void **extra, GucSource source);
static bool check_phony_autocommit(bool *newval, void **extra, GucSource source);
-static bool check_custom_variable_classes(char **newval, void **extra, GucSource source);
static bool check_debug_assertions(bool *newval, void **extra, GucSource source);
static bool check_bonjour(bool *newval, void **extra, GucSource source);
static bool check_ssl(bool *newval, void **extra, GucSource source);
static char *timezone_abbreviations_string;
static char *XactIsoLevel_string;
static char *session_authorization_string;
-static char *custom_variable_classes;
static int max_function_args;
static int max_index_keys;
static int max_identifier_length;
NULL, NULL, NULL
},
- {
- {"custom_variable_classes", PGC_SIGHUP, CUSTOM_OPTIONS,
- gettext_noop("Sets the list of known custom variable classes."),
- NULL,
- GUC_LIST_INPUT | GUC_LIST_QUOTE
- },
- &custom_variable_classes,
- NULL,
- check_custom_variable_classes, NULL, NULL
- },
-
{
{"data_directory", PGC_POSTMASTER, FILE_LOCATIONS,
gettext_noop("Sets the server's data directory."),
}
/*
- * Create and add a placeholder variable. It's presumed to belong
- * to a valid custom variable class at this point.
+ * Create and add a placeholder variable for a custom variable name.
*/
static struct config_generic *
add_placeholder_variable(const char *name, int elevel)
return gen;
}
-/*
- * Detect whether the portion of "name" before dotPos matches any custom
- * variable class name listed in custom_var_classes. The latter must be
- * formatted the way that assign_custom_variable_classes does it, ie,
- * no whitespace. NULL is valid for custom_var_classes.
- */
-static bool
-is_custom_class(const char *name, int dotPos, const char *custom_var_classes)
-{
- bool result = false;
- const char *ccs = custom_var_classes;
-
- if (ccs != NULL)
- {
- const char *start = ccs;
-
- for (;; ++ccs)
- {
- char 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;
-}
-
/*
* Look up option NAME. If it exists, return a pointer to its record,
* else return NULL. If create_placeholders is TRUE, we'll create a
if (create_placeholders)
{
/*
- * Check if the name is qualified, and if so, check if the qualifier
- * matches any custom variable class. If so, add a placeholder.
+ * Check if the name is qualified, and if so, add a placeholder.
*/
- const char *dot = strchr(name, GUC_QUALIFIER_SEPARATOR);
-
- if (dot != NULL &&
- is_custom_class(name, dot - name, custom_variable_classes))
+ if (strchr(name, GUC_QUALIFIER_SEPARATOR) != NULL)
return add_placeholder_variable(name, elevel);
}
{
int elevel;
FILE *fp;
- struct config_generic *cvc_conf;
int i;
Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
return;
}
- /*
- * custom_variable_classes must be written out first; otherwise we might
- * reject custom variable values while reading the file.
- */
- cvc_conf = find_option("custom_variable_classes", false, ERROR);
- if (cvc_conf)
- write_one_nondefault_variable(fp, cvc_conf);
-
for (i = 0; i < num_guc_variables; i++)
{
- struct config_generic *gconf = guc_variables[i];
-
- if (gconf != cvc_conf)
- write_one_nondefault_variable(fp, gconf);
+ write_one_nondefault_variable(fp, guc_variables[i]);
}
if (FreeFile(fp))
* permissions normally (ie, allow if variable is USERSET, or if it's
* SUSET and user is superuser).
*
- * name is not known, but exists or can be created as a placeholder
- * (implying it has a prefix listed in custom_variable_classes). We allow
- * this case if you're a superuser, otherwise not. Superusers are assumed
- * to know what they're doing. We can't allow it for other users, because
- * when the placeholder is resolved it might turn out to be a SUSET
- * variable; define_custom_variable assumes we checked that.
+ * name is not known, but exists or can be created as a placeholder (i.e.,
+ * it has a prefixed name). We allow this case if you're a superuser,
+ * otherwise not. Superusers are assumed to know what they're doing.
+ * We can't allow it for other users, because when the placeholder is
+ * resolved it might turn out to be a SUSET variable;
+ * define_custom_variable assumes we checked that.
*
* name is not known and can't be created as a placeholder. Throw error,
- * unless skipIfNoPermissions is true, in which case return FALSE. (It's
- * tempting to allow this case to superusers, if the name is qualified but
- * not listed in custom_variable_classes. That would ease restoring of
- * dumps containing ALTER ROLE/DATABASE SET. However, it's not clear that
- * this usage justifies such a loss of error checking. You can always fix
- * custom_variable_classes before you restore.)
+ * unless skipIfNoPermissions is true, in which case return FALSE.
*/
gconf = find_option(name, true, WARNING);
if (!gconf)
return false;
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\"", name)));
+ errmsg("unrecognized configuration parameter \"%s\"",
+ name)));
}
if (gconf->flags & GUC_CUSTOM_PLACEHOLDER)
return true;
}
-static bool
-check_custom_variable_classes(char **newval, void **extra, GucSource source)
-{
- /*
- * Check syntax. newval must be a comma separated list of identifiers.
- * Whitespace is allowed but removed from the result.
- */
- bool hasSpaceAfterToken = false;
- const char *cp = *newval;
- int symLen = 0;
- char c;
- StringInfoData buf;
-
- /* Default NULL is OK */
- if (cp == NULL)
- return true;
-
- initStringInfo(&buf);
- while ((c = *cp++) != '\0')
- {
- if (isspace((unsigned char) c))
- {
- if (symLen > 0)
- hasSpaceAfterToken = true;
- continue;
- }
-
- if (c == ',')
- {
- if (symLen > 0) /* terminate identifier */
- {
- appendStringInfoChar(&buf, ',');
- symLen = 0;
- }
- hasSpaceAfterToken = false;
- continue;
- }
-
- if (hasSpaceAfterToken || !(isalnum((unsigned char) c) || c == '_'))
- {
- /*
- * Syntax error due to token following space after token or
- * non-identifier character
- */
- pfree(buf.data);
- return false;
- }
- appendStringInfoChar(&buf, c);
- symLen++;
- }
-
- /* Remove stray ',' at end */
- if (symLen == 0 && buf.len > 0)
- buf.data[--buf.len] = '\0';
-
- /* GUC wants the result malloc'd */
- free(*newval);
- *newval = guc_strdup(LOG, buf.data);
-
- pfree(buf.data);
- return true;
-}
-
static bool
check_debug_assertions(bool *newval, void **extra, GucSource source)
{
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------
-#custom_variable_classes = '' # list of custom variable class names
+# Add settings for extensions here
-- test plperl.on_plperl_init errors are fatal
--- Avoid need for custom_variable_classes = 'plperl'
+-- Must load plperl before we can set on_plperl_init
LOAD 'plperl';
SET SESSION plperl.on_plperl_init = ' system("/nonesuch") ';
SHOW plperl.on_plperl_init;
-- test plperl.on_plperl_init via the shared hash
-- (must be done before plperl is first used)
--- Avoid need for custom_variable_classes = 'plperl'
+-- Must load plperl before we can set on_plperl_init
LOAD 'plperl';
-- testing on_plperl_init gets run, and that it can alter %_SHARED
SET plperl.on_plperl_init = '$_SHARED{on_init} = 42';
-- Use ONLY plperlu tests here. For plperl/plerlu combined tests
-- see plperl_plperlu.sql
--- Avoid need for custom_variable_classes = 'plperl'
+-- Must load plperl before we can set on_plperlu_init
LOAD 'plperl';
-- Test plperl.on_plperlu_init gets run
SET plperl.on_plperlu_init = '$_SHARED{init} = 42';
-- test plperl.on_plperl_init errors are fatal
--- Avoid need for custom_variable_classes = 'plperl'
+-- Must load plperl before we can set on_plperl_init
LOAD 'plperl';
SET SESSION plperl.on_plperl_init = ' system("/nonesuch") ';
-- test plperl.on_plperl_init via the shared hash
-- (must be done before plperl is first used)
--- Avoid need for custom_variable_classes = 'plperl'
+-- Must load plperl before we can set on_plperl_init
LOAD 'plperl';
-- testing on_plperl_init gets run, and that it can alter %_SHARED
-- Use ONLY plperlu tests here. For plperl/plerlu combined tests
-- see plperl_plperlu.sql
--- Avoid need for custom_variable_classes = 'plperl'
+-- Must load plperl before we can set on_plperlu_init
LOAD 'plperl';
-- Test plperl.on_plperlu_init gets run