@@ -5334,6 +5334,45 @@ add_guc_variable(struct config_generic *var, int elevel)
53345334 return true;
53355335}
53365336
5337+ /*
5338+ * Decide whether a proposed custom variable name is allowed.
5339+ *
5340+ * It must be "identifier.identifier", where the rules for what is an
5341+ * identifier agree with scan.l.
5342+ */
5343+ static bool
5344+ valid_custom_variable_name (const char * name )
5345+ {
5346+ int num_sep = 0 ;
5347+ bool name_start = true;
5348+
5349+ for (const char * p = name ; * p ; p ++ )
5350+ {
5351+ if (* p == GUC_QUALIFIER_SEPARATOR )
5352+ {
5353+ if (name_start )
5354+ return false; /* empty name component */
5355+ num_sep ++ ;
5356+ name_start = true;
5357+ }
5358+ else if (strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
5359+ "abcdefghijklmnopqrstuvwxyz" , * p ) != NULL ||
5360+ IS_HIGHBIT_SET (* p ))
5361+ {
5362+ /* okay as first or non-first character */
5363+ name_start = false;
5364+ }
5365+ else if (!name_start && strchr ("0123456789_$" , * p ) != NULL )
5366+ /* okay as non-first character */ ;
5367+ else
5368+ return false;
5369+ }
5370+ if (name_start )
5371+ return false; /* empty name component */
5372+ /* OK if we had exactly one separator */
5373+ return (num_sep == 1 );
5374+ }
5375+
53375376/*
53385377 * Create and add a placeholder variable for a custom variable name.
53395378 */
@@ -5381,12 +5420,23 @@ add_placeholder_variable(const char *name, int elevel)
53815420}
53825421
53835422/*
5384- * Look up option NAME. If it exists, return a pointer to its record,
5385- * else return NULL. If create_placeholders is true, we'll create a
5386- * placeholder record for a valid-looking custom variable name.
5423+ * Look up option "name". If it exists, return a pointer to its record.
5424+ * Otherwise, if create_placeholders is true and name is a valid-looking
5425+ * custom variable name, we'll create and return a placeholder record.
5426+ * Otherwise, if skip_errors is true, then we silently return NULL for
5427+ * an unrecognized or invalid name. Otherwise, the error is reported at
5428+ * error level elevel (and we return NULL if that's less than ERROR).
5429+ *
5430+ * Note: internal errors, primarily out-of-memory, draw an elevel-level
5431+ * report and NULL return regardless of skip_errors. Hence, callers must
5432+ * handle a NULL return whenever elevel < ERROR, but they should not need
5433+ * to emit any additional error message. (In practice, internal errors
5434+ * can only happen when create_placeholders is true, so callers passing
5435+ * false need not think terribly hard about this.)
53875436 */
53885437static struct config_generic *
5389- find_option (const char * name , bool create_placeholders , int elevel )
5438+ find_option (const char * name , bool create_placeholders , bool skip_errors ,
5439+ int elevel )
53905440{
53915441 const char * * key = & name ;
53925442 struct config_generic * * res ;
@@ -5414,19 +5464,38 @@ find_option(const char *name, bool create_placeholders, int elevel)
54145464 for (i = 0 ; map_old_guc_names [i ] != NULL ; i += 2 )
54155465 {
54165466 if (guc_name_compare (name , map_old_guc_names [i ]) == 0 )
5417- return find_option (map_old_guc_names [i + 1 ], false, elevel );
5467+ return find_option (map_old_guc_names [i + 1 ], false,
5468+ skip_errors , elevel );
54185469 }
54195470
54205471 if (create_placeholders )
54215472 {
54225473 /*
5423- * Check if the name is qualified, and if so, add a placeholder.
5474+ * Check if the name is valid, and if so, add a placeholder. If it
5475+ * doesn't contain a separator, don't assume that it was meant to be a
5476+ * placeholder.
54245477 */
54255478 if (strchr (name , GUC_QUALIFIER_SEPARATOR ) != NULL )
5426- return add_placeholder_variable (name , elevel );
5479+ {
5480+ if (valid_custom_variable_name (name ))
5481+ return add_placeholder_variable (name , elevel );
5482+ /* A special error message seems desirable here */
5483+ if (!skip_errors )
5484+ ereport (elevel ,
5485+ (errcode (ERRCODE_INVALID_NAME ),
5486+ errmsg ("invalid configuration parameter name \"%s\"" ,
5487+ name ),
5488+ errdetail ("Custom parameter names must be of the form \"identifier.identifier\"." )));
5489+ return NULL ;
5490+ }
54275491 }
54285492
54295493 /* Unknown name */
5494+ if (!skip_errors )
5495+ ereport (elevel ,
5496+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
5497+ errmsg ("unrecognized configuration parameter \"%s\"" ,
5498+ name )));
54305499 return NULL ;
54315500}
54325501
@@ -6444,7 +6513,7 @@ ReportChangedGUCOptions(void)
64446513 {
64456514 struct config_generic * record ;
64466515
6447- record = find_option ("in_hot_standby" , false, ERROR );
6516+ record = find_option ("in_hot_standby" , false, false, ERROR );
64486517 Assert (record != NULL );
64496518 record -> status |= GUC_NEEDS_REPORT ;
64506519 report_needed = true;
@@ -7218,14 +7287,9 @@ set_config_option(const char *name, const char *value,
72187287 (errcode (ERRCODE_INVALID_TRANSACTION_STATE ),
72197288 errmsg ("cannot set parameters during a parallel operation" )));
72207289
7221- record = find_option (name , true, elevel );
7290+ record = find_option (name , true, false, elevel );
72227291 if (record == NULL )
7223- {
7224- ereport (elevel ,
7225- (errcode (ERRCODE_UNDEFINED_OBJECT ),
7226- errmsg ("unrecognized configuration parameter \"%s\"" , name )));
72277292 return 0 ;
7228- }
72297293
72307294 /*
72317295 * Check if the option can be set at this time. See guc.h for the precise
@@ -7947,10 +8011,10 @@ set_config_sourcefile(const char *name, char *sourcefile, int sourceline)
79478011 */
79488012 elevel = IsUnderPostmaster ? DEBUG3 : LOG ;
79498013
7950- record = find_option (name , true, elevel );
8014+ record = find_option (name , true, false, elevel );
79518015 /* should not happen */
79528016 if (record == NULL )
7953- elog ( ERROR , "unrecognized configuration parameter \"%s\"" , name ) ;
8017+ return ;
79548018
79558019 sourcefile = guc_strdup (elevel , sourcefile );
79568020 if (record -> sourcefile )
@@ -7999,16 +8063,9 @@ GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged)
79998063 struct config_generic * record ;
80008064 static char buffer [256 ];
80018065
8002- record = find_option (name , false, ERROR );
8066+ record = find_option (name , false, missing_ok , ERROR );
80038067 if (record == NULL )
8004- {
8005- if (missing_ok )
8006- return NULL ;
8007- ereport (ERROR ,
8008- (errcode (ERRCODE_UNDEFINED_OBJECT ),
8009- errmsg ("unrecognized configuration parameter \"%s\"" ,
8010- name )));
8011- }
8068+ return NULL ;
80128069 if (restrict_privileged &&
80138070 (record -> flags & GUC_SUPERUSER_ONLY ) &&
80148071 !is_member_of_role (GetUserId (), ROLE_PG_READ_ALL_SETTINGS ))
@@ -8055,11 +8112,8 @@ GetConfigOptionResetString(const char *name)
80558112 struct config_generic * record ;
80568113 static char buffer [256 ];
80578114
8058- record = find_option (name , false, ERROR );
8059- if (record == NULL )
8060- ereport (ERROR ,
8061- (errcode (ERRCODE_UNDEFINED_OBJECT ),
8062- errmsg ("unrecognized configuration parameter \"%s\"" , name )));
8115+ record = find_option (name , false, false, ERROR );
8116+ Assert (record != NULL );
80638117 if ((record -> flags & GUC_SUPERUSER_ONLY ) &&
80648118 !is_member_of_role (GetUserId (), ROLE_PG_READ_ALL_SETTINGS ))
80658119 ereport (ERROR ,
@@ -8103,16 +8157,9 @@ GetConfigOptionFlags(const char *name, bool missing_ok)
81038157{
81048158 struct config_generic * record ;
81058159
8106- record = find_option (name , false, WARNING );
8160+ record = find_option (name , false, missing_ok , ERROR );
81078161 if (record == NULL )
8108- {
8109- if (missing_ok )
8110- return 0 ;
8111- ereport (ERROR ,
8112- (errcode (ERRCODE_UNDEFINED_OBJECT ),
8113- errmsg ("unrecognized configuration parameter \"%s\"" ,
8114- name )));
8115- }
8162+ return 0 ;
81168163 return record -> flags ;
81178164}
81188165
@@ -8144,7 +8191,7 @@ flatten_set_variable_args(const char *name, List *args)
81448191 * Get flags for the variable; if it's not known, use default flags.
81458192 * (Caller might throw error later, but not our business to do so here.)
81468193 */
8147- record = find_option (name , false, WARNING );
8194+ record = find_option (name , false, true, WARNING );
81488195 if (record )
81498196 flags = record -> flags ;
81508197 else
@@ -8439,12 +8486,8 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
84398486 {
84408487 struct config_generic * record ;
84418488
8442- record = find_option (name , false, ERROR );
8443- if (record == NULL )
8444- ereport (ERROR ,
8445- (errcode (ERRCODE_UNDEFINED_OBJECT ),
8446- errmsg ("unrecognized configuration parameter \"%s\"" ,
8447- name )));
8489+ record = find_option (name , false, false, ERROR );
8490+ Assert (record != NULL );
84488491
84498492 /*
84508493 * Don't allow parameters that can't be set in configuration files to
@@ -9460,19 +9503,12 @@ GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
94609503{
94619504 struct config_generic * record ;
94629505
9463- record = find_option (name , false, ERROR );
9506+ record = find_option (name , false, missing_ok , ERROR );
94649507 if (record == NULL )
94659508 {
9466- if (missing_ok )
9467- {
9468- if (varname )
9469- * varname = NULL ;
9470- return NULL ;
9471- }
9472-
9473- ereport (ERROR ,
9474- (errcode (ERRCODE_UNDEFINED_OBJECT ),
9475- errmsg ("unrecognized configuration parameter \"%s\"" , name )));
9509+ if (varname )
9510+ * varname = NULL ;
9511+ return NULL ;
94769512 }
94779513
94789514 if ((record -> flags & GUC_SUPERUSER_ONLY ) &&
@@ -10318,7 +10354,7 @@ read_nondefault_variables(void)
1031810354 if ((varname = read_string_with_null (fp )) == NULL )
1031910355 break ;
1032010356
10321- if ((record = find_option (varname , true, FATAL )) == NULL )
10357+ if ((record = find_option (varname , true, false, FATAL )) == NULL )
1032210358 elog (FATAL , "failed to locate variable \"%s\" in exec config params file" , varname );
1032310359
1032410360 if ((varvalue = read_string_with_null (fp )) == NULL )
@@ -11008,7 +11044,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value)
1100811044 (void ) validate_option_array_item (name , value , false);
1100911045
1101011046 /* normalize name (converts obsolete GUC names to modern spellings) */
11011- record = find_option (name , false, WARNING );
11047+ record = find_option (name , false, true, WARNING );
1101211048 if (record )
1101311049 name = record -> name ;
1101411050
@@ -11087,7 +11123,7 @@ GUCArrayDelete(ArrayType *array, const char *name)
1108711123 (void ) validate_option_array_item (name , NULL , false);
1108811124
1108911125 /* normalize name (converts obsolete GUC names to modern spellings) */
11090- record = find_option (name , false, WARNING );
11126+ record = find_option (name , false, true, WARNING );
1109111127 if (record )
1109211128 name = record -> name ;
1109311129
@@ -11234,7 +11270,7 @@ validate_option_array_item(const char *name, const char *value,
1123411270 * SUSET and user is superuser).
1123511271 *
1123611272 * name is not known, but exists or can be created as a placeholder (i.e.,
11237- * it has a prefixed name). We allow this case if you're a superuser,
11273+ * it has a valid custom name). We allow this case if you're a superuser,
1123811274 * otherwise not. Superusers are assumed to know what they're doing. We
1123911275 * can't allow it for other users, because when the placeholder is
1124011276 * resolved it might turn out to be a SUSET variable;
@@ -11243,16 +11279,11 @@ validate_option_array_item(const char *name, const char *value,
1124311279 * name is not known and can't be created as a placeholder. Throw error,
1124411280 * unless skipIfNoPermissions is true, in which case return false.
1124511281 */
11246- gconf = find_option (name , true, WARNING );
11282+ gconf = find_option (name , true, skipIfNoPermissions , ERROR );
1124711283 if (!gconf )
1124811284 {
1124911285 /* not known, failed to make a placeholder */
11250- if (skipIfNoPermissions )
11251- return false;
11252- ereport (ERROR ,
11253- (errcode (ERRCODE_UNDEFINED_OBJECT ),
11254- errmsg ("unrecognized configuration parameter \"%s\"" ,
11255- name )));
11286+ return false;
1125611287 }
1125711288
1125811289 if (gconf -> flags & GUC_CUSTOM_PLACEHOLDER )
0 commit comments