Skip to content

Commit 2ed8a8c

Browse files
committed
Rethink handling of settings with a prefix reserved by an extension.
Commit 75d2206 made SET print a warning if you tried to set an unrecognized parameter within namespace previously reserved by an extension. It seems better for that to be an outright error though, for the same reason that we don't let you set unrecognized unqualified parameter names. In any case, the preceding implementation was inefficient and erroneous. Perform the check in a more appropriate spot, and be more careful about prefix-match cases. Discussion: https://postgr.es/m/116024.1640111629@sss.pgh.pa.us
1 parent 86d9888 commit 2ed8a8c

File tree

3 files changed

+68
-84
lines changed

3 files changed

+68
-84
lines changed

src/backend/utils/misc/guc.c

Lines changed: 42 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ extern bool optimize_bounded_sort;
148148

149149
static int GUC_check_errcode_value;
150150

151+
static List *reserved_class_prefix = NIL;
152+
151153
/* global variables for check hook support */
152154
char *GUC_check_errmsg_string;
153155
char *GUC_check_errdetail_string;
@@ -235,8 +237,6 @@ static bool check_recovery_target_lsn(char **newval, void **extra, GucSource sou
235237
static void assign_recovery_target_lsn(const char *newval, void *extra);
236238
static bool check_primary_slot_name(char **newval, void **extra, GucSource source);
237239
static bool check_default_with_oids(bool *newval, void **extra, GucSource source);
238-
static void check_reserved_prefixes(const char *varName);
239-
static List *reserved_class_prefix = NIL;
240240

241241
/* Private functions in guc-file.l that need to be called from guc.c */
242242
static ConfigVariable *ProcessConfigFileInternal(GucContext context,
@@ -5569,18 +5569,44 @@ find_option(const char *name, bool create_placeholders, bool skip_errors,
55695569
* doesn't contain a separator, don't assume that it was meant to be a
55705570
* placeholder.
55715571
*/
5572-
if (strchr(name, GUC_QUALIFIER_SEPARATOR) != NULL)
5572+
const char *sep = strchr(name, GUC_QUALIFIER_SEPARATOR);
5573+
5574+
if (sep != NULL)
55735575
{
5574-
if (valid_custom_variable_name(name))
5575-
return add_placeholder_variable(name, elevel);
5576-
/* A special error message seems desirable here */
5577-
if (!skip_errors)
5578-
ereport(elevel,
5579-
(errcode(ERRCODE_INVALID_NAME),
5580-
errmsg("invalid configuration parameter name \"%s\"",
5581-
name),
5582-
errdetail("Custom parameter names must be two or more simple identifiers separated by dots.")));
5583-
return NULL;
5576+
size_t classLen = sep - name;
5577+
ListCell *lc;
5578+
5579+
/* The name must be syntactically acceptable ... */
5580+
if (!valid_custom_variable_name(name))
5581+
{
5582+
if (!skip_errors)
5583+
ereport(elevel,
5584+
(errcode(ERRCODE_INVALID_NAME),
5585+
errmsg("invalid configuration parameter name \"%s\"",
5586+
name),
5587+
errdetail("Custom parameter names must be two or more simple identifiers separated by dots.")));
5588+
return NULL;
5589+
}
5590+
/* ... and it must not match any previously-reserved prefix */
5591+
foreach(lc, reserved_class_prefix)
5592+
{
5593+
const char *rcprefix = lfirst(lc);
5594+
5595+
if (strlen(rcprefix) == classLen &&
5596+
strncmp(name, rcprefix, classLen) == 0)
5597+
{
5598+
if (!skip_errors)
5599+
ereport(elevel,
5600+
(errcode(ERRCODE_INVALID_NAME),
5601+
errmsg("invalid configuration parameter name \"%s\"",
5602+
name),
5603+
errdetail("\"%s\" is a reserved prefix.",
5604+
rcprefix)));
5605+
return NULL;
5606+
}
5607+
}
5608+
/* OK, create it */
5609+
return add_placeholder_variable(name, elevel);
55845610
}
55855611
}
55865612

@@ -8764,7 +8790,6 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
87648790
(superuser() ? PGC_SUSET : PGC_USERSET),
87658791
PGC_S_SESSION,
87668792
action, true, 0, false);
8767-
check_reserved_prefixes(stmt->name);
87688793
break;
87698794
case VAR_SET_MULTI:
87708795

@@ -8850,8 +8875,6 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
88508875
(superuser() ? PGC_SUSET : PGC_USERSET),
88518876
PGC_S_SESSION,
88528877
action, true, 0, false);
8853-
8854-
check_reserved_prefixes(stmt->name);
88558878
break;
88568879
case VAR_RESET_ALL:
88578880
ResetAllOptions();
@@ -9345,8 +9368,9 @@ EmitWarningsOnPlaceholders(const char *className)
93459368
{
93469369
int classLen = strlen(className);
93479370
int i;
9348-
MemoryContext oldcontext;
9371+
MemoryContext oldcontext;
93499372

9373+
/* Check for existing placeholders. */
93509374
for (i = 0; i < num_guc_variables; i++)
93519375
{
93529376
struct config_generic *var = guc_variables[i];
@@ -9362,48 +9386,12 @@ EmitWarningsOnPlaceholders(const char *className)
93629386
}
93639387
}
93649388

9389+
/* And remember the name so we can prevent future mistakes. */
93659390
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
93669391
reserved_class_prefix = lappend(reserved_class_prefix, pstrdup(className));
93679392
MemoryContextSwitchTo(oldcontext);
93689393
}
93699394

9370-
/*
9371-
* Check a setting name against prefixes previously reserved by
9372-
* EmitWarningsOnPlaceholders() and throw a warning if matching.
9373-
*/
9374-
static void
9375-
check_reserved_prefixes(const char *varName)
9376-
{
9377-
char *sep = strchr(varName, GUC_QUALIFIER_SEPARATOR);
9378-
9379-
if (sep)
9380-
{
9381-
size_t classLen = sep - varName;
9382-
ListCell *lc;
9383-
9384-
foreach(lc, reserved_class_prefix)
9385-
{
9386-
char *rcprefix = lfirst(lc);
9387-
9388-
if (strncmp(varName, rcprefix, classLen) == 0)
9389-
{
9390-
for (int i = 0; i < num_guc_variables; i++)
9391-
{
9392-
struct config_generic *var = guc_variables[i];
9393-
9394-
if ((var->flags & GUC_CUSTOM_PLACEHOLDER) != 0 &&
9395-
strcmp(varName, var->name) == 0)
9396-
{
9397-
ereport(WARNING,
9398-
(errcode(ERRCODE_UNDEFINED_OBJECT),
9399-
errmsg("unrecognized configuration parameter \"%s\"", var->name),
9400-
errdetail("\"%.*s\" is a reserved prefix.", (int) classLen, var->name)));
9401-
}
9402-
}
9403-
}
9404-
}
9405-
}
9406-
}
94079395

94089396
/*
94099397
* SHOW command

src/test/regress/expected/guc.out

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,23 @@ ERROR: invalid configuration parameter name "special.weird name"
548548
DETAIL: Custom parameter names must be two or more simple identifiers separated by dots.
549549
SHOW special."weird name";
550550
ERROR: unrecognized configuration parameter "special.weird name"
551+
-- Check what happens when you try to set a "custom" GUC within the
552+
-- namespace of an extension.
553+
SET plpgsql.bogus_setting = 42; -- allowed if plpgsql is not loaded yet
554+
LOAD 'plpgsql'; -- this will now warn about it
555+
WARNING: unrecognized configuration parameter "plpgsql.bogus_setting"
556+
SET plpgsql.extra_foo_warnings = false; -- but now, it's an error
557+
ERROR: invalid configuration parameter name "plpgsql.extra_foo_warnings"
558+
DETAIL: "plpgsql" is a reserved prefix.
559+
SHOW plpgsql.extra_foo_warnings;
560+
ERROR: unrecognized configuration parameter "plpgsql.extra_foo_warnings"
561+
SET plpgsql.bogus_setting = 43; -- you can still use the pre-existing variable
562+
SHOW plpgsql.bogus_setting;
563+
plpgsql.bogus_setting
564+
-----------------------
565+
43
566+
(1 row)
567+
551568
--
552569
-- Test DISCARD TEMP
553570
--
@@ -813,22 +830,3 @@ set default_with_oids to f;
813830
-- Should not allow to set it to true.
814831
set default_with_oids to t;
815832
ERROR: tables declared WITH OIDS are not supported
816-
-- test SET unrecognized parameter
817-
SET foo = false; -- no such setting
818-
ERROR: unrecognized configuration parameter "foo"
819-
-- test setting a parameter with a registered prefix (plpgsql)
820-
SET plpgsql.extra_foo_warnings = false; -- no such setting
821-
WARNING: unrecognized configuration parameter "plpgsql.extra_foo_warnings"
822-
DETAIL: "plpgsql" is a reserved prefix.
823-
SHOW plpgsql.extra_foo_warnings; -- but the parameter is set
824-
plpgsql.extra_foo_warnings
825-
----------------------------
826-
false
827-
(1 row)
828-
829-
-- cleanup
830-
RESET foo;
831-
ERROR: unrecognized configuration parameter "foo"
832-
RESET plpgsql.extra_foo_warnings;
833-
WARNING: unrecognized configuration parameter "plpgsql.extra_foo_warnings"
834-
DETAIL: "plpgsql" is a reserved prefix.

src/test/regress/sql/guc.sql

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,15 @@ SHOW custom."bad-guc";
163163
SET special."weird name" = 'foo'; -- could be allowed, but we choose not to
164164
SHOW special."weird name";
165165

166+
-- Check what happens when you try to set a "custom" GUC within the
167+
-- namespace of an extension.
168+
SET plpgsql.bogus_setting = 42; -- allowed if plpgsql is not loaded yet
169+
LOAD 'plpgsql'; -- this will now warn about it
170+
SET plpgsql.extra_foo_warnings = false; -- but now, it's an error
171+
SHOW plpgsql.extra_foo_warnings;
172+
SET plpgsql.bogus_setting = 43; -- you can still use the pre-existing variable
173+
SHOW plpgsql.bogus_setting;
174+
166175
--
167176
-- Test DISCARD TEMP
168177
--
@@ -311,14 +320,3 @@ reset check_function_bodies;
311320
set default_with_oids to f;
312321
-- Should not allow to set it to true.
313322
set default_with_oids to t;
314-
315-
-- test SET unrecognized parameter
316-
SET foo = false; -- no such setting
317-
318-
-- test setting a parameter with a registered prefix (plpgsql)
319-
SET plpgsql.extra_foo_warnings = false; -- no such setting
320-
SHOW plpgsql.extra_foo_warnings; -- but the parameter is set
321-
322-
-- cleanup
323-
RESET foo;
324-
RESET plpgsql.extra_foo_warnings;

0 commit comments

Comments
 (0)