Code review for various recent GUC hacking. Don't elog(ERROR) when

not supposed to (fixes problem with postmaster aborting due to mistaken
postgresql.conf change); don't call superuser() when not inside a
transaction (fixes coredump when, eg, try to set log_statement from
PGOPTIONS); some message style guidelines enforcement.
This commit is contained in:
Tom Lane 2004-08-31 19:28:51 +00:00
parent 617d6ea7df
commit c32416ebb7
2 changed files with 137 additions and 97 deletions

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.102 2004/08/30 02:54:38 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.103 2004/08/31 19:28:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -475,16 +475,23 @@ show_timezone(void)
const char *
assign_XactIsoLevel(const char *value, bool doit, GucSource source)
{
if (doit && source >= PGC_S_INTERACTIVE)
if (SerializableSnapshot != NULL)
{
if (SerializableSnapshot != NULL)
if (source >= PGC_S_INTERACTIVE)
ereport(ERROR,
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query")));
if (IsSubTransaction())
else
return NULL;
}
if (IsSubTransaction())
{
if (source >= PGC_S_INTERACTIVE)
ereport(ERROR,
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction")));
else
return NULL;
}
if (strcmp(value, "serializable") == 0)

View File

@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.236 2004/08/31 04:53:44 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.237 2004/08/31 19:28:51 tgl Exp $
*
*--------------------------------------------------------------------
*/
@ -1848,6 +1848,10 @@ static int guc_name_compare(const char *namea, const char *nameb);
static void push_old_value(struct config_generic * gconf);
static void ReportGUCOption(struct config_generic * record);
static char *_ShowOption(struct config_generic * record);
static bool check_userlimit_privilege(struct config_generic *record,
GucSource source, int elevel);
static bool check_userlimit_override(struct config_generic *record,
GucSource source);
/*
@ -2034,7 +2038,7 @@ static bool
is_custom_class(const char *name, int dotPos)
{
/*
* The assign_custom_variable_classes has made sure no empty
* assign_custom_variable_classes() has made sure no empty
* identifiers or whitespace exists in the variable
*/
bool result = false;
@ -3233,22 +3237,14 @@ set_config_option(const char *name, const char *value,
if (newval < conf->reset_val)
{
/* Limit non-superuser changes */
if (source > PGC_S_UNPRIVILEGED && !superuser())
{
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name),
errhint("must be superuser to change this value to false")));
if (!check_userlimit_privilege(record, source,
elevel))
return false;
}
}
if (newval > *conf->variable)
{
/* Allow change if admin should override */
if (source < PGC_S_UNPRIVILEGED &&
record->source > PGC_S_UNPRIVILEGED &&
!superuser())
if (check_userlimit_override(record, source))
changeVal = changeValOrig;
}
}
@ -3338,30 +3334,25 @@ set_config_option(const char *name, const char *value,
}
if (record->context == PGC_USERLIMIT)
{
/* handle log_min_duration_statement, -1=disable */
if ((newval != -1 && conf->reset_val != -1 &&
newval > conf->reset_val) || /* increase duration */
(newval == -1 && conf->reset_val != -1)) /* turn off */
/*
* handle log_min_duration_statement: if it's enabled
* then either turning it off or increasing it
* requires privileges.
*/
if (conf->reset_val != -1 &&
(newval == -1 || newval > conf->reset_val))
{
/* Limit non-superuser changes */
if (source > PGC_S_UNPRIVILEGED && !superuser())
{
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name),
errhint("Must be superuser to increase this value or turn it off.")));
if (!check_userlimit_privilege(record, source,
elevel))
return false;
}
}
/* Allow change if admin should override */
if ((newval != -1 && *conf->variable != -1 &&
newval < *conf->variable) || /* decrease duration */
(newval != -1 && *conf->variable == -1)) /* turn on */
/* Admin override includes turning on or decreasing */
if (newval != -1 &&
(*conf->variable == -1 || newval < *conf->variable))
{
if (source < PGC_S_UNPRIVILEGED &&
record->source > PGC_S_UNPRIVILEGED &&
!superuser())
/* Allow change if admin should override */
if (check_userlimit_override(record, source))
changeVal = changeValOrig;
}
}
@ -3450,23 +3441,21 @@ set_config_option(const char *name, const char *value,
return false;
}
if (record->context == PGC_USERLIMIT)
/* No REAL PGC_USERLIMIT */
{
/* Limit non-superuser changes */
if (source > PGC_S_UNPRIVILEGED && !superuser())
/* No REAL PGC_USERLIMIT at present */
if (newval < conf->reset_val)
{
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name),
errhint("Must be superuser to increase this value or turn it off.")));
return false;
/* Limit non-superuser changes */
if (!check_userlimit_privilege(record, source,
elevel))
return false;
}
if (newval > *conf->variable)
{
/* Allow change if admin should override */
if (check_userlimit_override(record, source))
changeVal = changeValOrig;
}
/* Allow change if admin should override */
if (source < PGC_S_UNPRIVILEGED &&
record->source > PGC_S_UNPRIVILEGED &&
!superuser())
changeVal = false;
}
}
else
@ -3559,27 +3548,17 @@ set_config_option(const char *name, const char *value,
(*var_hook) (&var_value, *conf->variable, true,
source);
/* Limit non-superuser changes */
if (new_value > reset_value)
{
/* Limit non-superuser changes */
if (source > PGC_S_UNPRIVILEGED && !superuser())
{
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name),
errhint("Must be superuser to increase this value.")));
if (!check_userlimit_privilege(record, source,
elevel))
return false;
}
}
/* Allow change if admin should override */
if (new_value < var_value)
{
if (source < PGC_S_UNPRIVILEGED &&
record->source > PGC_S_UNPRIVILEGED &&
!superuser())
/* Allow change if admin should override */
if (check_userlimit_override(record, source))
changeVal = changeValOrig;
}
}
@ -3702,6 +3681,71 @@ set_config_option(const char *name, const char *value,
return true;
}
/*
* Check whether we should allow a USERLIMIT parameter to be set
*
* This is invoked only when the desired new setting is "less" than the
* old and so appropriate privileges are needed. If the setting should
* be disallowed, either throw an error (in interactive case) or return false.
*/
static bool
check_userlimit_privilege(struct config_generic *record, GucSource source,
int elevel)
{
/* Allow if trusted source (e.g., config file) */
if (source < PGC_S_UNPRIVILEGED)
return true;
/*
* Allow if superuser. We can only check this inside a transaction,
* though, so assume not-superuser otherwise. (In practice this means
* that settings coming from PGOPTIONS will be treated as non-superuser)
*/
if (IsTransactionState() && superuser())
return true;
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
record->name),
(record->vartype == PGC_BOOL) ?
errhint("Must be superuser to change this value to false.")
: ((record->vartype == PGC_INT) ?
errhint("Must be superuser to increase this value or turn it off.")
: errhint("Must be superuser to increase this value."))));
return false;
}
/*
* Check whether we should allow a USERLIMIT parameter to be overridden
*
* This is invoked when the desired new setting is "greater" than the
* old; if the old setting was unprivileged and the new one is privileged,
* we should apply it, even though the normal rule would be not to.
*/
static bool
check_userlimit_override(struct config_generic *record, GucSource source)
{
/* Unprivileged source never gets to override this way */
if (source > PGC_S_UNPRIVILEGED)
return false;
/* If existing setting is from privileged source, keep it */
if (record->source < PGC_S_UNPRIVILEGED)
return false;
/*
* If user is a superuser, he gets to keep his setting. We can't check
* this unless inside a transaction, though. XXX in practice that
* restriction means this code is essentially worthless, because the
* result will depend on whether we happen to be inside a transaction
* block when SIGHUP arrives. Dike out until we can think of something
* that actually works.
*/
#ifdef NOT_USED
if (IsTransactionState() && superuser())
return false;
#endif
/* Otherwise override */
return true;
}
/*
@ -5450,22 +5494,19 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
* Syntax error due to token following space after token or
* non alpha numeric character
*/
pfree(buf.data);
ereport(WARNING,
ereport(LOG,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("illegal syntax for custom_variable_classes \"%s\"", newval)));
errmsg("invalid syntax for custom_variable_classes: \"%s\"", newval)));
pfree(buf.data);
return NULL;
}
symLen++;
appendStringInfoChar(&buf, (char) c);
}
/* Remove stray ',' at end */
if (symLen == 0 && buf.len > 0)
/*
* Remove stray ',' at end
*/
buf.data[--buf.len] = 0;
buf.data[--buf.len] = '\0';
if (buf.len == 0)
newval = NULL;
@ -5479,39 +5520,32 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
static bool
assign_stage_log_stats(bool newval, bool doit, GucSource source)
{
if (newval)
if (newval && log_statement_stats)
{
if (log_statement_stats)
{
if (doit)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot enable parameter when \"log_statement_stats\" is true.")));
else
return false;
}
return true;
if (source >= PGC_S_INTERACTIVE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot enable parameter when \"log_statement_stats\" is true")));
else
return false;
}
return true;
}
static bool
assign_log_stats(bool newval, bool doit, GucSource source)
{
if (newval)
if (newval &&
(log_parser_stats || log_planner_stats || log_executor_stats))
{
if (log_parser_stats || log_planner_stats || log_executor_stats)
{
if (doit)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot enable \"log_statement_stats\" when \"log_parser_stats\",\n"
"\"log_planner_stats\", or \"log_executor_stats\" is true.")));
else
return false;
}
return true;
if (source >= PGC_S_INTERACTIVE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot enable \"log_statement_stats\" when "
"\"log_parser_stats\", \"log_planner_stats\", "
"or \"log_executor_stats\" is true")));
else
return false;
}
return true;
}
@ -5534,7 +5568,6 @@ assign_transaction_read_only(bool newval, bool doit, GucSource source)
static const char *
assign_canonical_path(const char *newval, bool doit, GucSource source)
{
if (doit)
{
/* We have to create a new pointer to force the change */