Skip to content

Commit 9bd681a

Browse files
committed
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.
1 parent 2397602 commit 9bd681a

File tree

17 files changed

+183
-144
lines changed

17 files changed

+183
-144
lines changed

src/backend/access/transam/xlog.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.131 2004/01/06 22:22:37 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.132 2004/01/19 19:04:40 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -3523,7 +3523,7 @@ xlog_outrec(char *buf, XLogRecord *record)
35233523
* GUC support
35243524
*/
35253525
const char *
3526-
assign_xlog_sync_method(const char *method, bool doit, bool interactive)
3526+
assign_xlog_sync_method(const char *method, bool doit, GucSource source)
35273527
{
35283528
int new_sync_method;
35293529
int new_sync_bit;

src/backend/catalog/namespace.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.61 2003/12/29 21:33:09 tgl Exp $
16+
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.62 2004/01/19 19:04:40 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -39,6 +39,7 @@
3939
#include "utils/acl.h"
4040
#include "utils/builtins.h"
4141
#include "utils/catcache.h"
42+
#include "utils/guc.h"
4243
#include "utils/inval.h"
4344
#include "utils/lsyscache.h"
4445
#include "utils/memutils.h"
@@ -1773,7 +1774,7 @@ RemoveTempRelationsCallback(int code, Datum arg)
17731774

17741775
/* assign_hook: validate new search_path, do extra actions as needed */
17751776
const char *
1776-
assign_search_path(const char *newval, bool doit, bool interactive)
1777+
assign_search_path(const char *newval, bool doit, GucSource source)
17771778
{
17781779
char *rawname;
17791780
List *namelist;
@@ -1795,13 +1796,19 @@ assign_search_path(const char *newval, bool doit, bool interactive)
17951796
* If we aren't inside a transaction, we cannot do database access so
17961797
* cannot verify the individual names. Must accept the list on faith.
17971798
*/
1798-
if (interactive && IsTransactionState())
1799+
if (source >= PGC_S_INTERACTIVE && IsTransactionState())
17991800
{
18001801
/*
18011802
* Verify that all the names are either valid namespace names or
18021803
* "$user". We do not require $user to correspond to a valid
18031804
* namespace. We do not check for USAGE rights, either; should
18041805
* we?
1806+
*
1807+
* When source == PGC_S_TEST, we are checking the argument of an
1808+
* ALTER DATABASE SET or ALTER USER SET command. It could be that
1809+
* the intended use of the search path is for some other database,
1810+
* so we should not error out if it mentions schemas not present
1811+
* in the current database. We reduce the message to NOTICE instead.
18051812
*/
18061813
foreach(l, namelist)
18071814
{
@@ -1812,7 +1819,7 @@ assign_search_path(const char *newval, bool doit, bool interactive)
18121819
if (!SearchSysCacheExists(NAMESPACENAME,
18131820
CStringGetDatum(curname),
18141821
0, 0, 0))
1815-
ereport(ERROR,
1822+
ereport((source == PGC_S_TEST) ? NOTICE : ERROR,
18161823
(errcode(ERRCODE_UNDEFINED_SCHEMA),
18171824
errmsg("schema \"%s\" does not exist", curname)));
18181825
}

src/backend/commands/variable.c

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.92 2003/12/21 04:34:35 momjian Exp $
12+
* $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.93 2004/01/19 19:04:40 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -48,7 +48,7 @@ extern char *tzname[];
4848
* assign_datestyle: GUC assign_hook for datestyle
4949
*/
5050
const char *
51-
assign_datestyle(const char *value, bool doit, bool interactive)
51+
assign_datestyle(const char *value, bool doit, GucSource source)
5252
{
5353
int newDateStyle = DateStyle;
5454
int newDateOrder = DateOrder;
@@ -69,7 +69,7 @@ assign_datestyle(const char *value, bool doit, bool interactive)
6969
/* syntax error in list */
7070
pfree(rawstring);
7171
freeList(elemlist);
72-
if (interactive)
72+
if (source >= PGC_S_INTERACTIVE)
7373
ereport(ERROR,
7474
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
7575
errmsg("invalid list syntax for parameter \"datestyle\"")));
@@ -137,7 +137,7 @@ assign_datestyle(const char *value, bool doit, bool interactive)
137137
const char *subval;
138138

139139
subval = assign_datestyle(GetConfigOptionResetString("datestyle"),
140-
true, interactive);
140+
true, source);
141141
if (scnt == 0)
142142
newDateStyle = DateStyle;
143143
if (ocnt == 0)
@@ -155,7 +155,7 @@ assign_datestyle(const char *value, bool doit, bool interactive)
155155
}
156156
else
157157
{
158-
if (interactive)
158+
if (source >= PGC_S_INTERACTIVE)
159159
ereport(ERROR,
160160
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
161161
errmsg("unrecognized \"datestyle\" key word: \"%s\"",
@@ -173,7 +173,7 @@ assign_datestyle(const char *value, bool doit, bool interactive)
173173

174174
if (!ok)
175175
{
176-
if (interactive)
176+
if (source >= PGC_S_INTERACTIVE)
177177
ereport(ERROR,
178178
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
179179
errmsg("conflicting \"datestyle\" specifications")));
@@ -386,7 +386,7 @@ tz_acceptable(void)
386386
* assign_timezone: GUC assign_hook for timezone
387387
*/
388388
const char *
389-
assign_timezone(const char *value, bool doit, bool interactive)
389+
assign_timezone(const char *value, bool doit, GucSource source)
390390
{
391391
char *result;
392392
char *endptr;
@@ -444,7 +444,7 @@ assign_timezone(const char *value, bool doit, bool interactive)
444444
pfree(val);
445445
if (interval->month != 0)
446446
{
447-
if (interactive)
447+
if (source >= PGC_S_INTERACTIVE)
448448
ereport(ERROR,
449449
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
450450
errmsg("invalid interval value for time zone: month not allowed")));
@@ -552,15 +552,15 @@ assign_timezone(const char *value, bool doit, bool interactive)
552552
/* Complain if it was bad */
553553
if (!known)
554554
{
555-
ereport(interactive ? ERROR : LOG,
555+
ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
556556
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
557557
errmsg("unrecognized time zone name: \"%s\"",
558558
value)));
559559
return NULL;
560560
}
561561
if (!acceptable)
562562
{
563-
ereport(interactive ? ERROR : LOG,
563+
ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
564564
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
565565
errmsg("time zone \"%s\" appears to use leap seconds",
566566
value),
@@ -628,9 +628,9 @@ show_timezone(void)
628628
*/
629629

630630
const char *
631-
assign_XactIsoLevel(const char *value, bool doit, bool interactive)
631+
assign_XactIsoLevel(const char *value, bool doit, GucSource source)
632632
{
633-
if (doit && interactive && SerializableSnapshot != NULL)
633+
if (doit && source >= PGC_S_INTERACTIVE && SerializableSnapshot != NULL)
634634
ereport(ERROR,
635635
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
636636
errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query")));
@@ -690,10 +690,10 @@ show_XactIsoLevel(void)
690690
*/
691691

692692
bool
693-
assign_random_seed(double value, bool doit, bool interactive)
693+
assign_random_seed(double value, bool doit, GucSource source)
694694
{
695695
/* Can't really roll back on error, so ignore non-interactive setting */
696-
if (doit && interactive)
696+
if (doit && source >= PGC_S_INTERACTIVE)
697697
DirectFunctionCall1(setseed, Float8GetDatum(value));
698698
return true;
699699
}
@@ -710,7 +710,7 @@ show_random_seed(void)
710710
*/
711711

712712
const char *
713-
assign_client_encoding(const char *value, bool doit, bool interactive)
713+
assign_client_encoding(const char *value, bool doit, GucSource source)
714714
{
715715
int encoding;
716716

@@ -726,7 +726,7 @@ assign_client_encoding(const char *value, bool doit, bool interactive)
726726
*/
727727
if (SetClientEncoding(encoding, doit) < 0)
728728
{
729-
if (interactive)
729+
if (source >= PGC_S_INTERACTIVE)
730730
ereport(ERROR,
731731
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
732732
errmsg("conversion between %s and %s is not supported",
@@ -748,7 +748,7 @@ assign_client_encoding(const char *value, bool doit, bool interactive)
748748
* because of the NAMEDATALEN limit on names.
749749
*/
750750
const char *
751-
assign_session_authorization(const char *value, bool doit, bool interactive)
751+
assign_session_authorization(const char *value, bool doit, GucSource source)
752752
{
753753
AclId usesysid = 0;
754754
bool is_superuser = false;
@@ -791,7 +791,7 @@ assign_session_authorization(const char *value, bool doit, bool interactive)
791791
0, 0, 0);
792792
if (!HeapTupleIsValid(userTup))
793793
{
794-
if (interactive)
794+
if (source >= PGC_S_INTERACTIVE)
795795
ereport(ERROR,
796796
(errcode(ERRCODE_UNDEFINED_OBJECT),
797797
errmsg("user \"%s\" does not exist", value)));

src/backend/utils/adt/datetime.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.123 2003/12/21 04:34:35 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.124 2004/01/19 19:04:40 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -3919,7 +3919,7 @@ EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str)
39193919

39203920
/* GUC assign_hook for australian_timezones */
39213921
bool
3922-
ClearDateCache(bool newval, bool doit, bool interactive)
3922+
ClearDateCache(bool newval, bool doit, GucSource source)
39233923
{
39243924
int i;
39253925

src/backend/utils/adt/pg_locale.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* Portions Copyright (c) 2002-2003, PostgreSQL Global Development Group
66
*
7-
* $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.24 2003/11/29 19:51:59 pgsql Exp $
7+
* $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.25 2004/01/19 19:04:40 tgl Exp $
88
*
99
*-----------------------------------------------------------------------
1010
*/
@@ -73,7 +73,7 @@ char *locale_time;
7373
* valid. (See explanation at the top of this file.)
7474
*/
7575
static const char *
76-
locale_xxx_assign(int category, const char *value, bool doit, bool interactive)
76+
locale_xxx_assign(int category, const char *value, bool doit, GucSource source)
7777
{
7878
char *save;
7979

@@ -99,29 +99,29 @@ locale_xxx_assign(int category, const char *value, bool doit, bool interactive)
9999

100100

101101
const char *
102-
locale_monetary_assign(const char *value, bool doit, bool interactive)
102+
locale_monetary_assign(const char *value, bool doit, GucSource source)
103103
{
104-
return locale_xxx_assign(LC_MONETARY, value, doit, interactive);
104+
return locale_xxx_assign(LC_MONETARY, value, doit, source);
105105
}
106106

107107
const char *
108-
locale_numeric_assign(const char *value, bool doit, bool interactive)
108+
locale_numeric_assign(const char *value, bool doit, GucSource source)
109109
{
110-
return locale_xxx_assign(LC_NUMERIC, value, doit, interactive);
110+
return locale_xxx_assign(LC_NUMERIC, value, doit, source);
111111
}
112112

113113
const char *
114-
locale_time_assign(const char *value, bool doit, bool interactive)
114+
locale_time_assign(const char *value, bool doit, GucSource source)
115115
{
116-
return locale_xxx_assign(LC_TIME, value, doit, interactive);
116+
return locale_xxx_assign(LC_TIME, value, doit, source);
117117
}
118118

119119

120120
/*
121121
* We allow LC_MESSAGES to actually be set globally.
122122
*/
123123
const char *
124-
locale_messages_assign(const char *value, bool doit, bool interactive)
124+
locale_messages_assign(const char *value, bool doit, GucSource source)
125125
{
126126
/*
127127
* LC_MESSAGES category does not exist everywhere, but accept it
@@ -134,7 +134,7 @@ locale_messages_assign(const char *value, bool doit, bool interactive)
134134
return NULL;
135135
}
136136
else
137-
value = locale_xxx_assign(LC_MESSAGES, value, false, interactive);
137+
value = locale_xxx_assign(LC_MESSAGES, value, false, source);
138138
#endif
139139
return value;
140140
}

src/backend/utils/adt/regexp.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/regexp.c,v 1.50 2003/11/29 19:51:59 pgsql Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/regexp.c,v 1.51 2004/01/19 19:04:40 tgl Exp $
1212
*
1313
* Alistair Crooks added the code for the regex caching
1414
* agc - cached the regular expressions used - there's a good chance
@@ -32,6 +32,7 @@
3232
#include "regex/regex.h"
3333
#include "mb/pg_wchar.h"
3434
#include "utils/builtins.h"
35+
#include "utils/guc.h"
3536

3637

3738
/* GUC-settable flavor parameter */
@@ -229,7 +230,7 @@ RE_compile_and_execute(text *text_re, unsigned char *dat, int dat_len,
229230
*/
230231
const char *
231232
assign_regex_flavor(const char *value,
232-
bool doit, bool interactive)
233+
bool doit, GucSource source)
233234
{
234235
if (strcasecmp(value, "advanced") == 0)
235236
{

src/backend/utils/misc/README

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
$PostgreSQL: pgsql/src/backend/utils/misc/README,v 1.3 2003/11/29 19:52:03 pgsql Exp $
1+
$PostgreSQL: pgsql/src/backend/utils/misc/README,v 1.4 2004/01/19 19:04:40 tgl Exp $
22

33

44
GUC IMPLEMENTATION NOTES
@@ -19,29 +19,30 @@ to change when a GUC variable is set. Show hooks are used to modify
1919
the default SHOW display for a variable.
2020

2121
If an assign_hook is provided, it points to a function of the signature
22-
bool assign_hook(newvalue, bool doit, bool interactive)
23-
where the type of 'newvalue' matches the kind of variable. This function
22+
bool assign_hook(newvalue, bool doit, GucSource source)
23+
where the type of "newvalue" matches the kind of variable. This function
2424
is called immediately before actually setting the variable's value (so it
2525
can look at the actual variable to determine the old value). If the
2626
function returns "true" then the assignment is completed; if it returns
2727
"false" then newvalue is considered invalid and the assignment is not
2828
performed. If "doit" is false then the function should simply check
29-
validity of newvalue and not change any derived state. "interactive" is
30-
true when we are performing a SET command; in this case it is okay for the
31-
assign_hook to raise an error via elog(). If the function returns false
32-
for an interactive assignment then guc.c will report a generic "invalid
33-
value" error message. (An internal elog() in an assign_hook is only
34-
needed if you want to generate a specialized error message.) But when
35-
"interactive" is false we are reading a non-interactive option source,
36-
such as postgresql.conf. In this case the assign_hook should *not* elog
37-
but should just return false if it doesn't like the newvalue. (An
38-
elog(LOG) call would be acceptable if you feel a need for a custom
39-
complaint in this situation.)
29+
validity of newvalue and not change any derived state. The "source" parameter
30+
indicates where the new value came from. If it is >= PGC_S_INTERACTIVE,
31+
then we are performing an interactive assignment (e.g., a SET command).
32+
In such cases it is okay for the assign_hook to raise an error via ereport().
33+
If the function returns false for an interactive assignment then guc.c will
34+
report a generic "invalid value" error message. (An internal ereport() in
35+
an assign_hook is only needed if you want to generate a specialized error
36+
message.) But when source < PGC_S_INTERACTIVE, we are reading a
37+
non-interactive option source, such as postgresql.conf. In this case the
38+
assign_hook should *not* ereport but should just return false if it doesn't
39+
like the newvalue. (An ereport(LOG) call would be acceptable if you feel a
40+
need for a custom complaint in this situation.)
4041

4142
For string variables, the signature for assign hooks is a bit different:
4243
const char *assign_hook(const char *newvalue,
4344
bool doit,
44-
bool interactive)
45+
GucSource source)
4546
The meanings of the parameters are the same as for the other types of GUC
4647
variables, but the return value is handled differently:
4748
NULL --- assignment fails (like returning false for other datatypes)

0 commit comments

Comments
 (0)