diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2004-01-19 19:04:40 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2004-01-19 19:04:40 +0000 |
commit | 9bd681a5220186230e0ea0f718a71af7ebe4b560 (patch) | |
tree | 3dddc229c62a5cc2b4da3ea50b2bc0b7256443d0 /src/backend/utils | |
parent | 239760209b739d06e19ed4935776aeb89b6605f1 (diff) | |
download | postgresql-9bd681a5220186230e0ea0f718a71af7ebe4b560.tar.gz postgresql-9bd681a5220186230e0ea0f718a71af7ebe4b560.zip |
Repair problem identified by Olivier Prenant: ALTER DATABASE SET search_path
should not be too eager to reject paths involving unknown schemas, since
it can't really tell whether the schemas exist in the target database.
(Also, when reading pg_dumpall output, it could be that the schemas
don't exist yet, but eventually will.) ALTER USER SET has a similar issue.
So, reduce the normal ERROR to a NOTICE when checking search_path values
for these commands. Supporting this requires changing the API for GUC
assign_hook functions, which causes the patch to touch a lot of places,
but the changes are conceptually trivial.
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/datetime.c | 4 | ||||
-rw-r--r-- | src/backend/utils/adt/pg_locale.c | 20 | ||||
-rw-r--r-- | src/backend/utils/adt/regexp.c | 5 | ||||
-rw-r--r-- | src/backend/utils/misc/README | 31 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 119 |
5 files changed, 93 insertions, 86 deletions
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 35ef845c5d0..5fa4be73c43 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.123 2003/12/21 04:34:35 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.124 2004/01/19 19:04:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3919,7 +3919,7 @@ EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str) /* GUC assign_hook for australian_timezones */ bool -ClearDateCache(bool newval, bool doit, bool interactive) +ClearDateCache(bool newval, bool doit, GucSource source) { int i; diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index 15ae8ce953c..5c2e951be10 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -4,7 +4,7 @@ * * Portions Copyright (c) 2002-2003, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.24 2003/11/29 19:51:59 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.25 2004/01/19 19:04:40 tgl Exp $ * *----------------------------------------------------------------------- */ @@ -73,7 +73,7 @@ char *locale_time; * valid. (See explanation at the top of this file.) */ static const char * -locale_xxx_assign(int category, const char *value, bool doit, bool interactive) +locale_xxx_assign(int category, const char *value, bool doit, GucSource source) { char *save; @@ -99,21 +99,21 @@ locale_xxx_assign(int category, const char *value, bool doit, bool interactive) const char * -locale_monetary_assign(const char *value, bool doit, bool interactive) +locale_monetary_assign(const char *value, bool doit, GucSource source) { - return locale_xxx_assign(LC_MONETARY, value, doit, interactive); + return locale_xxx_assign(LC_MONETARY, value, doit, source); } const char * -locale_numeric_assign(const char *value, bool doit, bool interactive) +locale_numeric_assign(const char *value, bool doit, GucSource source) { - return locale_xxx_assign(LC_NUMERIC, value, doit, interactive); + return locale_xxx_assign(LC_NUMERIC, value, doit, source); } const char * -locale_time_assign(const char *value, bool doit, bool interactive) +locale_time_assign(const char *value, bool doit, GucSource source) { - return locale_xxx_assign(LC_TIME, value, doit, interactive); + return locale_xxx_assign(LC_TIME, value, doit, source); } @@ -121,7 +121,7 @@ locale_time_assign(const char *value, bool doit, bool interactive) * We allow LC_MESSAGES to actually be set globally. */ const char * -locale_messages_assign(const char *value, bool doit, bool interactive) +locale_messages_assign(const char *value, bool doit, GucSource source) { /* * LC_MESSAGES category does not exist everywhere, but accept it @@ -134,7 +134,7 @@ locale_messages_assign(const char *value, bool doit, bool interactive) return NULL; } else - value = locale_xxx_assign(LC_MESSAGES, value, false, interactive); + value = locale_xxx_assign(LC_MESSAGES, value, false, source); #endif return value; } diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c index 63b14266af1..78944a57951 100644 --- a/src/backend/utils/adt/regexp.c +++ b/src/backend/utils/adt/regexp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/regexp.c,v 1.50 2003/11/29 19:51:59 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/regexp.c,v 1.51 2004/01/19 19:04:40 tgl Exp $ * * Alistair Crooks added the code for the regex caching * agc - cached the regular expressions used - there's a good chance @@ -32,6 +32,7 @@ #include "regex/regex.h" #include "mb/pg_wchar.h" #include "utils/builtins.h" +#include "utils/guc.h" /* GUC-settable flavor parameter */ @@ -229,7 +230,7 @@ RE_compile_and_execute(text *text_re, unsigned char *dat, int dat_len, */ const char * assign_regex_flavor(const char *value, - bool doit, bool interactive) + bool doit, GucSource source) { if (strcasecmp(value, "advanced") == 0) { diff --git a/src/backend/utils/misc/README b/src/backend/utils/misc/README index bf6c8c7cc59..12a2cdef036 100644 --- a/src/backend/utils/misc/README +++ b/src/backend/utils/misc/README @@ -1,4 +1,4 @@ -$PostgreSQL: pgsql/src/backend/utils/misc/README,v 1.3 2003/11/29 19:52:03 pgsql Exp $ +$PostgreSQL: pgsql/src/backend/utils/misc/README,v 1.4 2004/01/19 19:04:40 tgl Exp $ GUC IMPLEMENTATION NOTES @@ -19,29 +19,30 @@ to change when a GUC variable is set. Show hooks are used to modify the default SHOW display for a variable. If an assign_hook is provided, it points to a function of the signature - bool assign_hook(newvalue, bool doit, bool interactive) -where the type of 'newvalue' matches the kind of variable. This function + bool assign_hook(newvalue, bool doit, GucSource source) +where the type of "newvalue" matches the kind of variable. This function is called immediately before actually setting the variable's value (so it can look at the actual variable to determine the old value). If the function returns "true" then the assignment is completed; if it returns "false" then newvalue is considered invalid and the assignment is not performed. If "doit" is false then the function should simply check -validity of newvalue and not change any derived state. "interactive" is -true when we are performing a SET command; in this case it is okay for the -assign_hook to raise an error via elog(). If the function returns false -for an interactive assignment then guc.c will report a generic "invalid -value" error message. (An internal elog() in an assign_hook is only -needed if you want to generate a specialized error message.) But when -"interactive" is false we are reading a non-interactive option source, -such as postgresql.conf. In this case the assign_hook should *not* elog -but should just return false if it doesn't like the newvalue. (An -elog(LOG) call would be acceptable if you feel a need for a custom -complaint in this situation.) +validity of newvalue and not change any derived state. The "source" parameter +indicates where the new value came from. If it is >= PGC_S_INTERACTIVE, +then we are performing an interactive assignment (e.g., a SET command). +In such cases it is okay for the assign_hook to raise an error via ereport(). +If the function returns false for an interactive assignment then guc.c will +report a generic "invalid value" error message. (An internal ereport() in +an assign_hook is only needed if you want to generate a specialized error +message.) But when source < PGC_S_INTERACTIVE, we are reading a +non-interactive option source, such as postgresql.conf. In this case the +assign_hook should *not* ereport but should just return false if it doesn't +like the newvalue. (An ereport(LOG) call would be acceptable if you feel a +need for a custom complaint in this situation.) For string variables, the signature for assign hooks is a bit different: const char *assign_hook(const char *newvalue, bool doit, - bool interactive) + GucSource source) The meanings of the parameters are the same as for the other types of GUC variables, but the return value is handled differently: NULL --- assignment fails (like returning false for other datatypes) diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index f0a0a88dd60..45bbfc96ea0 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut <peter_e@gmx.net>. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.176 2004/01/06 17:26:23 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.177 2004/01/19 19:04:40 tgl Exp $ * *-------------------------------------------------------------------- */ @@ -24,7 +24,6 @@ #include "utils/guc.h" #include "utils/guc_tables.h" -#include "access/xlog.h" #include "catalog/namespace.h" #include "catalog/pg_type.h" #include "commands/async.h" @@ -52,7 +51,6 @@ #include "tcop/tcopprot.h" #include "utils/array.h" #include "utils/builtins.h" -#include "utils/datetime.h" #include "utils/pg_locale.h" #include "pgstat.h" @@ -81,22 +79,22 @@ extern char *Syslog_facility; extern char *Syslog_ident; static const char *assign_facility(const char *facility, - bool doit, bool interactive); + bool doit, GucSource source); #endif static const char *assign_defaultxactisolevel(const char *newval, - bool doit, bool interactive); + bool doit, GucSource source); static const char *assign_log_min_messages(const char *newval, - bool doit, bool interactive); + bool doit, GucSource source); static const char *assign_client_min_messages(const char *newval, - bool doit, bool interactive); + bool doit, GucSource source); static const char *assign_min_error_statement(const char *newval, bool doit, - bool interactive); + GucSource source); static const char *assign_msglvl(int *var, const char *newval, - bool doit, bool interactive); + bool doit, GucSource source); static const char *assign_log_error_verbosity(const char *newval, bool doit, - bool interactive); -static bool assign_phony_autocommit(bool newval, bool doit, bool interactive); + GucSource source); +static bool assign_phony_autocommit(bool newval, bool doit, GucSource source); /* @@ -227,16 +225,18 @@ const char *const GucContext_Names[] = */ const char *const GucSource_Names[] = { - /* PGC_S_DEFAULT */ "default", - /* PGC_S_ENV_VAR */ "environment variable", - /* PGC_S_FILE */ "configuration file", - /* PGC_S_ARGV */ "command line", - /* PGC_S_UNPRIVILEGED */ "unprivileged", - /* PGC_S_DATABASE */ "database", - /* PGC_S_USER */ "user", - /* PGC_S_CLIENT */ "client", - /* PGC_S_OVERRIDE */ "override", - /* PGC_S_SESSION */ "session" + /* PGC_S_DEFAULT */ "default", + /* PGC_S_ENV_VAR */ "environment variable", + /* PGC_S_FILE */ "configuration file", + /* PGC_S_ARGV */ "command line", + /* PGC_S_UNPRIVILEGED */ "unprivileged", + /* PGC_S_DATABASE */ "database", + /* PGC_S_USER */ "user", + /* PGC_S_CLIENT */ "client", + /* PGC_S_OVERRIDE */ "override", + /* PGC_S_INTERACTIVE */ "interactive", + /* PGC_S_TEST */ "test", + /* PGC_S_SESSION */ "session" }; /* @@ -1893,7 +1893,8 @@ InitializeGUCOptions(void) struct config_bool *conf = (struct config_bool *) gconf; if (conf->assign_hook) - if (!(*conf->assign_hook) (conf->reset_val, true, false)) + if (!(*conf->assign_hook) (conf->reset_val, true, + PGC_S_DEFAULT)) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, (int) conf->reset_val); *conf->variable = conf->reset_val; @@ -1914,7 +1915,8 @@ InitializeGUCOptions(void) Assert(conf->gen.context != PGC_USERLIMIT || strcmp(conf->gen.name, "log_min_duration_statement") == 0); if (conf->assign_hook) - if (!(*conf->assign_hook) (conf->reset_val, true, false)) + if (!(*conf->assign_hook) (conf->reset_val, true, + PGC_S_DEFAULT)) elog(FATAL, "failed to initialize %s to %d", conf->gen.name, conf->reset_val); *conf->variable = conf->reset_val; @@ -1929,7 +1931,8 @@ InitializeGUCOptions(void) Assert(conf->reset_val <= conf->max); Assert(conf->gen.context != PGC_USERLIMIT); if (conf->assign_hook) - if (!(*conf->assign_hook) (conf->reset_val, true, false)) + if (!(*conf->assign_hook) (conf->reset_val, true, + PGC_S_DEFAULT)) elog(FATAL, "failed to initialize %s to %g", conf->gen.name, conf->reset_val); *conf->variable = conf->reset_val; @@ -1971,7 +1974,8 @@ InitializeGUCOptions(void) { const char *newstr; - newstr = (*conf->assign_hook) (str, true, false); + newstr = (*conf->assign_hook) (str, true, + PGC_S_DEFAULT); if (newstr == NULL) { elog(FATAL, "failed to initialize %s to \"%s\"", @@ -2065,7 +2069,8 @@ ResetAllOptions(void) struct config_bool *conf = (struct config_bool *) gconf; if (conf->assign_hook) - if (!(*conf->assign_hook) (conf->reset_val, true, true)) + if (!(*conf->assign_hook) (conf->reset_val, true, + PGC_S_SESSION)) elog(ERROR, "failed to reset %s", conf->gen.name); *conf->variable = conf->reset_val; conf->tentative_val = conf->reset_val; @@ -2080,7 +2085,8 @@ ResetAllOptions(void) struct config_int *conf = (struct config_int *) gconf; if (conf->assign_hook) - if (!(*conf->assign_hook) (conf->reset_val, true, true)) + if (!(*conf->assign_hook) (conf->reset_val, true, + PGC_S_SESSION)) elog(ERROR, "failed to reset %s", conf->gen.name); *conf->variable = conf->reset_val; conf->tentative_val = conf->reset_val; @@ -2095,7 +2101,8 @@ ResetAllOptions(void) struct config_real *conf = (struct config_real *) gconf; if (conf->assign_hook) - if (!(*conf->assign_hook) (conf->reset_val, true, true)) + if (!(*conf->assign_hook) (conf->reset_val, true, + PGC_S_SESSION)) elog(ERROR, "failed to reset %s", conf->gen.name); *conf->variable = conf->reset_val; conf->tentative_val = conf->reset_val; @@ -2123,7 +2130,8 @@ ResetAllOptions(void) { const char *newstr; - newstr = (*conf->assign_hook) (str, true, true); + newstr = (*conf->assign_hook) (str, true, + PGC_S_SESSION); if (newstr == NULL) elog(ERROR, "failed to reset %s", conf->gen.name); else if (newstr != str) @@ -2198,7 +2206,7 @@ AtEOXact_GUC(bool isCommit) { if (conf->assign_hook) if (!(*conf->assign_hook) (conf->session_val, - true, false)) + true, PGC_S_OVERRIDE)) elog(LOG, "failed to commit %s", conf->gen.name); *conf->variable = conf->session_val; @@ -2222,7 +2230,7 @@ AtEOXact_GUC(bool isCommit) { if (conf->assign_hook) if (!(*conf->assign_hook) (conf->session_val, - true, false)) + true, PGC_S_OVERRIDE)) elog(LOG, "failed to commit %s", conf->gen.name); *conf->variable = conf->session_val; @@ -2246,7 +2254,7 @@ AtEOXact_GUC(bool isCommit) { if (conf->assign_hook) if (!(*conf->assign_hook) (conf->session_val, - true, false)) + true, PGC_S_OVERRIDE)) elog(LOG, "failed to commit %s", conf->gen.name); *conf->variable = conf->session_val; @@ -2277,7 +2285,8 @@ AtEOXact_GUC(bool isCommit) { const char *newstr; - newstr = (*conf->assign_hook) (str, true, false); + newstr = (*conf->assign_hook) (str, true, + PGC_S_OVERRIDE); if (newstr == NULL) elog(LOG, "failed to commit %s", conf->gen.name); @@ -2500,7 +2509,6 @@ set_config_option(const char *name, const char *value, { struct config_generic *record; int elevel; - bool interactive; bool makeDefault; bool changeVal_orig; @@ -2610,9 +2618,6 @@ set_config_option(const char *name, const char *value, break; } - /* Should we report errors interactively? */ - interactive = (source >= PGC_S_SESSION); - /* * Should we set reset/session values? (If so, the behavior is not * transactional.) @@ -2687,7 +2692,7 @@ set_config_option(const char *name, const char *value, } if (conf->assign_hook) - if (!(*conf->assign_hook) (newval, changeVal, interactive)) + if (!(*conf->assign_hook) (newval, changeVal, source)) { ereport(elevel, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -2784,7 +2789,7 @@ set_config_option(const char *name, const char *value, } if (conf->assign_hook) - if (!(*conf->assign_hook) (newval, changeVal, interactive)) + if (!(*conf->assign_hook) (newval, changeVal, source)) { ereport(elevel, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -2880,7 +2885,7 @@ set_config_option(const char *name, const char *value, } if (conf->assign_hook) - if (!(*conf->assign_hook) (newval, changeVal, interactive)) + if (!(*conf->assign_hook) (newval, changeVal, source)) { ereport(elevel, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -2949,9 +2954,9 @@ set_config_option(const char *name, const char *value, /* all USERLIMIT strings are message levels */ assign_msglvl(&old_int_value, conf->reset_val, - true, interactive); + true, source); assign_msglvl(&new_int_value, newval, - true, interactive); + true, source); /* Limit non-superuser changes */ if (source > PGC_S_UNPRIVILEGED && new_int_value > old_int_value && @@ -3008,7 +3013,7 @@ set_config_option(const char *name, const char *value, const char *hookresult; hookresult = (*conf->assign_hook) (newval, - changeVal, interactive); + changeVal, source); guc_string_workspace = NULL; if (hookresult == NULL) { @@ -4189,7 +4194,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value) /* test if the option is valid */ set_config_option(name, value, superuser() ? PGC_SUSET : PGC_USERSET, - PGC_S_SESSION, false, false); + PGC_S_TEST, false, false); /* convert name to canonical spelling, so we can use plain strcmp */ (void) GetConfigOptionByName(name, &varname); @@ -4268,7 +4273,7 @@ GUCArrayDelete(ArrayType *array, const char *name) /* test if the option is valid */ set_config_option(name, NULL, superuser() ? PGC_SUSET : PGC_USERSET, - PGC_S_SESSION, false, false); + PGC_S_TEST, false, false); /* convert name to canonical spelling, so we can use plain strcmp */ (void) GetConfigOptionByName(name, &varname); @@ -4333,7 +4338,7 @@ GUCArrayDelete(ArrayType *array, const char *name) #ifdef HAVE_SYSLOG static const char * -assign_facility(const char *facility, bool doit, bool interactive) +assign_facility(const char *facility, bool doit, GucSource source) { if (strcasecmp(facility, "LOCAL0") == 0) return facility; @@ -4357,7 +4362,7 @@ assign_facility(const char *facility, bool doit, bool interactive) static const char * -assign_defaultxactisolevel(const char *newval, bool doit, bool interactive) +assign_defaultxactisolevel(const char *newval, bool doit, GucSource source) { if (strcasecmp(newval, "serializable") == 0) { @@ -4386,26 +4391,26 @@ assign_defaultxactisolevel(const char *newval, bool doit, bool interactive) static const char * assign_log_min_messages(const char *newval, - bool doit, bool interactive) + bool doit, GucSource source) { - return (assign_msglvl(&log_min_messages, newval, doit, interactive)); + return (assign_msglvl(&log_min_messages, newval, doit, source)); } static const char * assign_client_min_messages(const char *newval, - bool doit, bool interactive) + bool doit, GucSource source) { - return (assign_msglvl(&client_min_messages, newval, doit, interactive)); + return (assign_msglvl(&client_min_messages, newval, doit, source)); } static const char * -assign_min_error_statement(const char *newval, bool doit, bool interactive) +assign_min_error_statement(const char *newval, bool doit, GucSource source) { - return (assign_msglvl(&log_min_error_statement, newval, doit, interactive)); + return (assign_msglvl(&log_min_error_statement, newval, doit, source)); } static const char * -assign_msglvl(int *var, const char *newval, bool doit, bool interactive) +assign_msglvl(int *var, const char *newval, bool doit, GucSource source) { if (strcasecmp(newval, "debug") == 0) { @@ -4479,7 +4484,7 @@ assign_msglvl(int *var, const char *newval, bool doit, bool interactive) } static const char * -assign_log_error_verbosity(const char *newval, bool doit, bool interactive) +assign_log_error_verbosity(const char *newval, bool doit, GucSource source) { if (strcasecmp(newval, "terse") == 0) { @@ -4502,11 +4507,11 @@ assign_log_error_verbosity(const char *newval, bool doit, bool interactive) } static bool -assign_phony_autocommit(bool newval, bool doit, bool interactive) +assign_phony_autocommit(bool newval, bool doit, GucSource source) { if (!newval) { - if (doit && interactive) + if (doit && source >= PGC_S_INTERACTIVE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SET AUTOCOMMIT TO OFF is no longer supported"))); |