@@ -250,6 +250,8 @@ static void write_auto_conf_file(int fd, const char *filename, ConfigVariable *h
250250static void replace_auto_config_value (ConfigVariable * * head_p , ConfigVariable * * tail_p ,
251251 const char * name , const char * value );
252252static bool valid_custom_variable_name (const char * name );
253+ static bool assignable_custom_variable_name (const char * name , bool skip_errors ,
254+ int elevel );
253255static void do_serialize (char * * destptr , Size * maxbytes ,
254256 const char * fmt ,...) pg_attribute_printf (3 , 4 );
255257static bool call_bool_check_hook (struct config_bool * conf , bool * newval ,
@@ -1063,7 +1065,7 @@ add_guc_variable(struct config_generic *var, int elevel)
10631065 *
10641066 * It must be two or more identifiers separated by dots, where the rules
10651067 * for what is an identifier agree with scan.l. (If you change this rule,
1066- * adjust the errdetail in find_option ().)
1068+ * adjust the errdetail in assignable_custom_variable_name ().)
10671069 */
10681070static bool
10691071valid_custom_variable_name (const char * name )
@@ -1098,6 +1100,71 @@ valid_custom_variable_name(const char *name)
10981100 return saw_sep ;
10991101}
11001102
1103+ /*
1104+ * Decide whether an unrecognized variable name is allowed to be SET.
1105+ *
1106+ * It must pass the syntactic rules of valid_custom_variable_name(),
1107+ * and it must not be in any namespace already reserved by an extension.
1108+ * (We make this separate from valid_custom_variable_name() because we don't
1109+ * apply the reserved-namespace test when reading configuration files.)
1110+ *
1111+ * If valid, return true. Otherwise, return false if skip_errors is true,
1112+ * else throw a suitable error at the specified elevel (and return false
1113+ * if that's less than ERROR).
1114+ */
1115+ static bool
1116+ assignable_custom_variable_name (const char * name , bool skip_errors , int elevel )
1117+ {
1118+ /* If there's no separator, it can't be a custom variable */
1119+ const char * sep = strchr (name , GUC_QUALIFIER_SEPARATOR );
1120+
1121+ if (sep != NULL )
1122+ {
1123+ size_t classLen = sep - name ;
1124+ ListCell * lc ;
1125+
1126+ /* The name must be syntactically acceptable ... */
1127+ if (!valid_custom_variable_name (name ))
1128+ {
1129+ if (!skip_errors )
1130+ ereport (elevel ,
1131+ (errcode (ERRCODE_INVALID_NAME ),
1132+ errmsg ("invalid configuration parameter name \"%s\"" ,
1133+ name ),
1134+ errdetail ("Custom parameter names must be two or more simple identifiers separated by dots." )));
1135+ return false;
1136+ }
1137+ /* ... and it must not match any previously-reserved prefix */
1138+ foreach (lc , reserved_class_prefix )
1139+ {
1140+ const char * rcprefix = lfirst (lc );
1141+
1142+ if (strlen (rcprefix ) == classLen &&
1143+ strncmp (name , rcprefix , classLen ) == 0 )
1144+ {
1145+ if (!skip_errors )
1146+ ereport (elevel ,
1147+ (errcode (ERRCODE_INVALID_NAME ),
1148+ errmsg ("invalid configuration parameter name \"%s\"" ,
1149+ name ),
1150+ errdetail ("\"%s\" is a reserved prefix." ,
1151+ rcprefix )));
1152+ return false;
1153+ }
1154+ }
1155+ /* OK to create it */
1156+ return true;
1157+ }
1158+
1159+ /* Unrecognized single-part name */
1160+ if (!skip_errors )
1161+ ereport (elevel ,
1162+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
1163+ errmsg ("unrecognized configuration parameter \"%s\"" ,
1164+ name )));
1165+ return false;
1166+ }
1167+
11011168/*
11021169 * Create and add a placeholder variable for a custom variable name.
11031170 */
@@ -1191,52 +1258,15 @@ find_option(const char *name, bool create_placeholders, bool skip_errors,
11911258 if (create_placeholders )
11921259 {
11931260 /*
1194- * Check if the name is valid, and if so, add a placeholder. If it
1195- * doesn't contain a separator, don't assume that it was meant to be a
1196- * placeholder.
1261+ * Check if the name is valid, and if so, add a placeholder.
11971262 */
1198- const char * sep = strchr (name , GUC_QUALIFIER_SEPARATOR );
1199-
1200- if (sep != NULL )
1201- {
1202- size_t classLen = sep - name ;
1203- ListCell * lc ;
1204-
1205- /* The name must be syntactically acceptable ... */
1206- if (!valid_custom_variable_name (name ))
1207- {
1208- if (!skip_errors )
1209- ereport (elevel ,
1210- (errcode (ERRCODE_INVALID_NAME ),
1211- errmsg ("invalid configuration parameter name \"%s\"" ,
1212- name ),
1213- errdetail ("Custom parameter names must be two or more simple identifiers separated by dots." )));
1214- return NULL ;
1215- }
1216- /* ... and it must not match any previously-reserved prefix */
1217- foreach (lc , reserved_class_prefix )
1218- {
1219- const char * rcprefix = lfirst (lc );
1220-
1221- if (strlen (rcprefix ) == classLen &&
1222- strncmp (name , rcprefix , classLen ) == 0 )
1223- {
1224- if (!skip_errors )
1225- ereport (elevel ,
1226- (errcode (ERRCODE_INVALID_NAME ),
1227- errmsg ("invalid configuration parameter name \"%s\"" ,
1228- name ),
1229- errdetail ("\"%s\" is a reserved prefix." ,
1230- rcprefix )));
1231- return NULL ;
1232- }
1233- }
1234- /* OK, create it */
1263+ if (assignable_custom_variable_name (name , skip_errors , elevel ))
12351264 return add_placeholder_variable (name , elevel );
1236- }
1265+ else
1266+ return NULL ; /* error message, if any, already emitted */
12371267 }
12381268
1239- /* Unknown name */
1269+ /* Unknown name and we're not supposed to make a placeholder */
12401270 if (!skip_errors )
12411271 ereport (elevel ,
12421272 (errcode (ERRCODE_UNDEFINED_OBJECT ),
@@ -1369,18 +1399,16 @@ convert_GUC_name_for_parameter_acl(const char *name)
13691399/*
13701400 * Check whether we should allow creation of a pg_parameter_acl entry
13711401 * for the given name. (This can be applied either before or after
1372- * canonicalizing it.)
1402+ * canonicalizing it.) Throws error if not.
13731403 */
1374- bool
1404+ void
13751405check_GUC_name_for_parameter_acl (const char * name )
13761406{
13771407 /* OK if the GUC exists. */
1378- if (find_option (name , false, true, DEBUG1 ) != NULL )
1379- return true ;
1408+ if (find_option (name , false, true, DEBUG5 ) != NULL )
1409+ return ;
13801410 /* Otherwise, it'd better be a valid custom GUC name. */
1381- if (valid_custom_variable_name (name ))
1382- return true;
1383- return false;
1411+ (void ) assignable_custom_variable_name (name , false, ERROR );
13841412}
13851413
13861414/*
@@ -4515,52 +4543,64 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
45154543 {
45164544 struct config_generic * record ;
45174545
4518- record = find_option (name , false, false, ERROR );
4519- Assert (record != NULL );
4520-
4521- /*
4522- * Don't allow parameters that can't be set in configuration files to
4523- * be set in PG_AUTOCONF_FILENAME file.
4524- */
4525- if ((record -> context == PGC_INTERNAL ) ||
4526- (record -> flags & GUC_DISALLOW_IN_FILE ) ||
4527- (record -> flags & GUC_DISALLOW_IN_AUTO_FILE ))
4528- ereport (ERROR ,
4529- (errcode (ERRCODE_CANT_CHANGE_RUNTIME_PARAM ),
4530- errmsg ("parameter \"%s\" cannot be changed" ,
4531- name )));
4532-
4533- /*
4534- * If a value is specified, verify that it's sane.
4535- */
4536- if (value )
4546+ /* We don't want to create a placeholder if there's not one already */
4547+ record = find_option (name , false, true, DEBUG5 );
4548+ if (record != NULL )
45374549 {
4538- union config_var_val newval ;
4539- void * newextra = NULL ;
4540-
4541- /* Check that it's acceptable for the indicated parameter */
4542- if (! parse_and_validate_value (record , name , value ,
4543- PGC_S_FILE , ERROR ,
4544- & newval , & newextra ))
4550+ /*
4551+ * Don't allow parameters that can't be set in configuration files
4552+ * to be set in PG_AUTOCONF_FILENAME file.
4553+ */
4554+ if ((record -> context == PGC_INTERNAL ) ||
4555+ ( record -> flags & GUC_DISALLOW_IN_FILE ) ||
4556+ ( record -> flags & GUC_DISALLOW_IN_AUTO_FILE ))
45454557 ereport (ERROR ,
4546- (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
4547- errmsg ("invalid value for parameter \"%s\": \"%s\"" ,
4548- name , value )));
4558+ (errcode (ERRCODE_CANT_CHANGE_RUNTIME_PARAM ),
4559+ errmsg ("parameter \"%s\" cannot be changed" ,
4560+ name )));
4561+
4562+ /*
4563+ * If a value is specified, verify that it's sane.
4564+ */
4565+ if (value )
4566+ {
4567+ union config_var_val newval ;
4568+ void * newextra = NULL ;
45494569
4550- if (record -> vartype == PGC_STRING && newval .stringval != NULL )
4551- guc_free (newval .stringval );
4552- guc_free (newextra );
4570+ if (!parse_and_validate_value (record , name , value ,
4571+ PGC_S_FILE , ERROR ,
4572+ & newval , & newextra ))
4573+ ereport (ERROR ,
4574+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
4575+ errmsg ("invalid value for parameter \"%s\": \"%s\"" ,
4576+ name , value )));
45534577
4578+ if (record -> vartype == PGC_STRING && newval .stringval != NULL )
4579+ guc_free (newval .stringval );
4580+ guc_free (newextra );
4581+ }
4582+ }
4583+ else
4584+ {
45544585 /*
4555- * We must also reject values containing newlines, because the
4556- * grammar for config files doesn't support embedded newlines in
4557- * string literals.
4586+ * Variable not known; check we'd be allowed to create it. (We
4587+ * cannot validate the value, but that's fine. A non-core GUC in
4588+ * the config file cannot cause postmaster start to fail, so we
4589+ * don't have to be too tense about possibly installing a bad
4590+ * value.)
45584591 */
4559- if (strchr (value , '\n' ))
4560- ereport (ERROR ,
4561- (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
4562- errmsg ("parameter value for ALTER SYSTEM must not contain a newline" )));
4592+ (void ) assignable_custom_variable_name (name , false, ERROR );
45634593 }
4594+
4595+ /*
4596+ * We must also reject values containing newlines, because the grammar
4597+ * for config files doesn't support embedded newlines in string
4598+ * literals.
4599+ */
4600+ if (value && strchr (value , '\n' ))
4601+ ereport (ERROR ,
4602+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
4603+ errmsg ("parameter value for ALTER SYSTEM must not contain a newline" )));
45644604 }
45654605
45664606 /*
0 commit comments