* See src/backend/utils/misc/README for more information.
*
*
- * Copyright (c) 2000-2009, PostgreSQL Global Development Group
+ * Copyright (c) 2000-2010, PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.513 2009/08/31 02:23:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.532 2010/01/07 04:53:35 tgl Exp $
*
*--------------------------------------------------------------------
*/
#include "commands/trigger.h"
#include "funcapi.h"
#include "libpq/auth.h"
+#include "libpq/be-fsstubs.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "optimizer/cost.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
#include "parser/parse_expr.h"
-#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "parser/parser.h"
#include "parser/scansup.h"
#include "postmaster/postmaster.h"
#include "postmaster/syslogger.h"
#include "postmaster/walwriter.h"
-#include "regex/regex.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "tcop/tcopprot.h"
#endif
/* upper limit for GUC variables measured in kilobytes of memory */
-#if SIZEOF_SIZE_T > 4
+/* note that various places assume the byte size fits in a "long" variable */
+#if SIZEOF_SIZE_T > 4 && SIZEOF_LONG > 4
#define MAX_KILOBYTES INT_MAX
#else
#define MAX_KILOBYTES (INT_MAX / 1024)
extern char *temp_tablespaces;
extern bool synchronize_seqscans;
extern bool fullPageWrites;
+extern int vacuum_defer_cleanup_age;
+
+int trace_recovery_messages = LOG;
#ifdef TRACE_SORT
extern bool trace_sort;
static const char *assign_custom_variable_classes(const char *newval, bool doit,
GucSource source);
static bool assign_debug_assertions(bool newval, bool doit, GucSource source);
+static bool assign_bonjour(bool newval, bool doit, GucSource source);
static bool assign_ssl(bool 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);
static bool assign_autovacuum_max_workers(int newval, bool doit, GucSource source);
static bool assign_effective_io_concurrency(int newval, bool doit, GucSource source);
static const char *assign_pgstat_temp_directory(const char *newval, bool doit, GucSource source);
+static const char *assign_application_name(const char *newval, bool doit, GucSource source);
static char *config_enum_get_options(struct config_enum * record,
const char *prefix, const char *suffix,
{NULL, 0, false}
};
-static const struct config_enum_entry regex_flavor_options[] = {
- {"advanced", REG_ADVANCED, false},
- {"extended", REG_EXTENDED, false},
- {"basic", REG_BASIC, false},
- {NULL, 0, false}
-};
-
static const struct config_enum_entry isolation_level_options[] = {
{"serializable", XACT_SERIALIZABLE, false},
{"repeatable read", XACT_REPEATABLE_READ, false},
char *pgstat_temp_directory;
+char *default_do_language;
+
+char *application_name;
+
int tcp_keepalives_idle;
int tcp_keepalives_interval;
int tcp_keepalives_count;
/* PGC_S_ARGV */ "command line",
/* PGC_S_DATABASE */ "database",
/* PGC_S_USER */ "user",
+ /* PGC_S_DATABASE_USER */ "database user",
/* PGC_S_CLIENT */ "client",
/* PGC_S_OVERRIDE */ "override",
/* PGC_S_INTERACTIVE */ "interactive",
&session_auth_is_superuser,
false, NULL, NULL
},
+ {
+ {"bonjour", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
+ gettext_noop("Enables advertising the server via Bonjour."),
+ NULL
+ },
+ &enable_bonjour,
+ false, assign_bonjour, NULL
+ },
{
{"ssl", PGC_POSTMASTER, CONN_AUTH_SECURITY,
gettext_noop("Enables SSL connections."),
&XactReadOnly,
false, assign_transaction_read_only, NULL
},
- {
- {"add_missing_from", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
- gettext_noop("Automatically adds missing table references to FROM clauses."),
- NULL
- },
- &add_missing_from,
- false, NULL, NULL
- },
{
{"check_function_bodies", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Check function bodies during CREATE FUNCTION."),
false, NULL, NULL
},
+ {
+ {"recovery_connections", PGC_POSTMASTER, WAL_SETTINGS,
+ gettext_noop("During recovery, allows connections and queries. "
+ " During normal running, causes additional info to be written"
+ " to WAL to enable hot standby mode on WAL standby nodes."),
+ NULL
+ },
+ &XLogRequestRecoveryConnections,
+ true, NULL, NULL
+ },
+
{
{"allow_system_table_mods", PGC_POSTMASTER, DEVELOPER_OPTIONS,
gettext_noop("Allows modifications of the structure of system tables."),
false, NULL, NULL
},
+ {
+ {"lo_compat_privileges", PGC_SUSET, COMPAT_OPTIONS_PREVIOUS,
+ gettext_noop("Enables backward compatibility mode for privilege checks on large objects"),
+ gettext_noop("Skips privilege checks when reading or modifying large objects, "
+ "for compatibility with PostgreSQL releases prior to 8.5.")
+ },
+ &lo_compat_privileges,
+ false, NULL, NULL
+ },
+
/* End-of-list marker */
{
{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL
* Note: MaxBackends is limited to INT_MAX/4 because some places compute
* 4*MaxBackends without any overflow check. This check is made in
* assign_maxconnections, since MaxBackends is computed as MaxConnections
- * plus autovacuum_max_workers.
+ * plus autovacuum_max_workers plus one (for the autovacuum launcher).
*
* Likewise we have to limit NBuffers to INT_MAX/2.
+ *
+ * See also CheckRequiredParameterValues() if this parameter changes
*/
{
{"max_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
100, 1, INT_MAX / 4, assign_maxconnections, NULL
},
+ {
+ {"max_standby_delay", PGC_SIGHUP, WAL_SETTINGS,
+ gettext_noop("Sets the maximum delay to avoid conflict processing on Hot Standby servers."),
+ NULL
+ },
+ &MaxStandbyDelay,
+ 30, -1, INT_MAX, NULL, NULL
+ },
+
{
{"superuser_reserved_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
gettext_noop("Sets the number of connection slots reserved for superusers."),
1000, 25, INT_MAX, NULL, NULL
},
+ /*
+ * See also CheckRequiredParameterValues() if this parameter changes
+ */
{
{"max_prepared_transactions", PGC_POSTMASTER, RESOURCES,
gettext_noop("Sets the maximum number of simultaneously prepared transactions."),
150000000, 0, 2000000000, NULL, NULL
},
+ {
+ {"vacuum_defer_cleanup_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
+ gettext_noop("Age by which VACUUM and HOT cleanup should be deferred, if any."),
+ NULL
+ },
+ &vacuum_defer_cleanup_age,
+ 0, 0, 1000000, NULL, NULL
+ },
+
+ /*
+ * See also CheckRequiredParameterValues() if this parameter changes
+ */
{
{"max_locks_per_transaction", PGC_POSTMASTER, LOCK_MANAGEMENT,
gettext_noop("Sets the maximum number of locks per transaction."),
"(FLT_DIG or DBL_DIG as appropriate).")
},
&extra_float_digits,
- 0, -15, 2, NULL, NULL
+ 0, -15, 3, NULL, NULL
},
{
{
{"bonjour_name", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
- gettext_noop("Sets the Bonjour broadcast service name."),
+ gettext_noop("Sets the Bonjour service name."),
NULL
},
&bonjour_name,
{"role", PGC_USERSET, UNGROUPED,
gettext_noop("Sets the current role."),
NULL,
- GUC_IS_NAME | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+ GUC_IS_NAME | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_REST
},
&role_string,
"none", assign_role, show_role
{"session_authorization", PGC_USERSET, UNGROUPED,
gettext_noop("Sets the session user name."),
NULL,
- GUC_IS_NAME | GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+ GUC_IS_NAME | GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_REST
},
&session_authorization_string,
NULL, assign_session_authorization, show_session_authorization
},
#endif /* USE_SSL */
+ {
+ {"default_do_language", PGC_USERSET, CLIENT_CONN_STATEMENT,
+ gettext_noop("Sets the language used in DO statement if LANGUAGE is not specified."),
+ NULL
+ },
+ &default_do_language,
+ "plpgsql", NULL, NULL
+ },
+
+ {
+ {"application_name", PGC_USERSET, LOGGING,
+ gettext_noop("Sets the application name to be reported in statistics and logs."),
+ NULL,
+ GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE
+ },
+ &application_name,
+ "", assign_application_name, NULL
+ },
+
/* End-of-list marker */
{
{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
},
#endif
- {
- {"regex_flavor", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
- gettext_noop("Sets the regular expression \"flavor\"."),
- NULL
- },
- ®ex_flavor,
- REG_ADVANCED, regex_flavor_options, NULL, NULL
- },
-
{
{"session_replication_role", PGC_SUSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the session's behavior for triggers and rewrite rules."),
assign_session_replication_role, NULL
},
+ {
+ {"trace_recovery_messages", PGC_SUSET, LOGGING_WHEN,
+ gettext_noop("Sets the message levels that are logged during recovery."),
+ gettext_noop("Each level includes all the levels that follow it. The later"
+ " the level, the fewer messages are sent.")
+ },
+ &trace_recovery_messages,
+ DEBUG1, server_message_level_options, NULL, NULL
+ },
+
{
{"track_functions", PGC_SUSET, STATS_COLLECTOR,
gettext_noop("Collects function-level statistics on database activity."),
/*
* Note: the multiple-switch coding technique here is a bit tedious,
* but seems necessary to avoid intermediate-value overflows.
- *
- * If INT64_IS_BUSTED (ie, it's really int32) we will fail to detect
- * overflow due to units conversion, but there are few enough such
- * machines that it does not seem worth trying to be smarter.
*/
if (flags & GUC_UNIT_MEMORY)
{
*/
elevel = IsUnderPostmaster ? DEBUG3 : LOG;
}
- else if (source == PGC_S_DATABASE || source == PGC_S_USER)
+ else if (source == PGC_S_DATABASE || source == PGC_S_USER ||
+ source == PGC_S_DATABASE_USER)
elevel = WARNING;
else
elevel = ERROR;
if (changeVal && !is_newvalue_equal(record, value))
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
- errmsg("attempted change of parameter \"%s\" ignored",
- name),
- errdetail("This parameter cannot be changed after server start.")));
+ errmsg("parameter \"%s\" cannot be changed without restarting the server",
+ name)));
return true;
}
if (context != PGC_POSTMASTER)
{
ereport(elevel,
(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
- errmsg("attempted change of parameter \"%s\" ignored",
- name),
- errdetail("This parameter cannot be changed after server start.")));
+ errmsg("parameter \"%s\" cannot be changed without restarting the server",
+ name)));
return false;
}
break;
break;
}
+ /*
+ * Disallow changing GUC_NOT_WHILE_SEC_REST values if we are inside a
+ * security restriction context. We can reject this regardless of
+ * the GUC context or source, mainly because sources that it might be
+ * reasonable to override for won't be seen while inside a function.
+ *
+ * Note: variables marked GUC_NOT_WHILE_SEC_REST should usually be marked
+ * GUC_NO_RESET_ALL as well, because ResetAllOptions() doesn't check this.
+ * An exception might be made if the reset value is assumed to be "safe".
+ *
+ * Note: this flag is currently used for "session_authorization" and
+ * "role". We need to prohibit changing these inside a local userid
+ * context because when we exit it, GUC won't be notified, leaving things
+ * out of sync. (This could be fixed by forcing a new GUC nesting level,
+ * but that would change behavior in possibly-undesirable ways.) Also,
+ * we prohibit changing these in a security-restricted operation because
+ * otherwise RESET could be used to regain the session user's privileges.
+ */
+ if (record->flags & GUC_NOT_WHILE_SEC_REST)
+ {
+ if (InLocalUserIdChange())
+ {
+ /*
+ * Phrasing of this error message is historical, but it's the
+ * most common case.
+ */
+ ereport(elevel,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("cannot set parameter \"%s\" within security-definer function",
+ name)));
+ return false;
+ }
+ if (InSecurityRestrictedOperation())
+ {
+ ereport(elevel,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("cannot set parameter \"%s\" within security-restricted operation",
+ name)));
+ return false;
+ }
+ }
+
/*
* Should we set reset/stacked values? (If so, the behavior is not
* transactional.) This is done either when we get a default value from
* Fetch the current value of the option `name'. If the option doesn't exist,
* throw an ereport and don't return.
*
+ * If restrict_superuser is true, we also enforce that only superusers can
+ * see GUC_SUPERUSER_ONLY variables. This should only be passed as true
+ * in user-driven calls.
+ *
* The string is *not* allocated for modification and is really only
* valid until the next call to configuration related functions.
*/
const char *
-GetConfigOption(const char *name)
+GetConfigOption(const char *name, bool restrict_superuser)
{
struct config_generic *record;
static char buffer[256];
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("unrecognized configuration parameter \"%s\"", name)));
- if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser())
+ if (restrict_superuser &&
+ (record->flags & GUC_SUPERUSER_ONLY) &&
+ !superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to examine \"%s\"", name)));
break;
case PGC_S_DATABASE:
case PGC_S_USER:
+ case PGC_S_DATABASE_USER:
case PGC_S_CLIENT:
case PGC_S_SESSION:
default:
{
/*
* Use int64 arithmetic to avoid overflows in units
- * conversion. If INT64_IS_BUSTED we might overflow
- * anyway and print bogus answers, but there are few
- * enough such machines that it doesn't seem worth trying
- * harder.
+ * conversion.
*/
int64 result = *conf->variable;
const char *unit;
return true;
}
+static bool
+assign_bonjour(bool newval, bool doit, GucSource source)
+{
+#ifndef USE_BONJOUR
+ if (newval)
+ {
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Bonjour is not supported by this build")));
+ return false;
+ }
+#endif
+ return true;
+}
+
static bool
assign_ssl(bool newval, bool doit, GucSource source)
{
if (source != PGC_S_OVERRIDE)
return false;
}
+
+ /* Can't go to r/w mode while recovery is still active */
+ if (newval == false && XactReadOnly && RecoveryInProgress())
+ {
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot set transaction read-write mode during recovery")));
+ /* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
+ if (source != PGC_S_OVERRIDE)
+ return false;
+ }
+
return true;
}
static bool
assign_maxconnections(int newval, bool doit, GucSource source)
{
- if (newval + autovacuum_max_workers > INT_MAX / 4)
+ if (newval + autovacuum_max_workers + 1 > INT_MAX / 4)
return false;
if (doit)
- MaxBackends = newval + autovacuum_max_workers;
+ MaxBackends = newval + autovacuum_max_workers + 1;
return true;
}
static bool
assign_autovacuum_max_workers(int newval, bool doit, GucSource source)
{
- if (newval + MaxConnections > INT_MAX / 4)
+ if (MaxConnections + newval + 1 > INT_MAX / 4)
return false;
if (doit)
- MaxBackends = newval + MaxConnections;
+ MaxBackends = MaxConnections + newval + 1;
return true;
}
return newval;
}
+static const char *
+assign_application_name(const char *newval, bool doit, GucSource source)
+{
+ if (doit)
+ {
+ /* Only allow clean ASCII chars in the application name */
+ char *repval = guc_strdup(ERROR, newval);
+ char *p;
+
+ for (p = repval; *p; p++)
+ {
+ if (*p < 32 || *p > 126)
+ *p = '?';
+ }
+
+ /* Update the pg_stat_activity view */
+ pgstat_report_appname(repval);
+
+ return repval;
+ }
+ else
+ return newval;
+}
+
#include "guc-file.c"