return true;
}
+/*
+ * Decide whether a proposed custom variable name is allowed.
+ *
+ * It must be "identifier.identifier", where the rules for what is an
+ * identifier agree with scan.l.
+ */
+static bool
+valid_custom_variable_name(const char *name)
+{
+ int num_sep = 0;
+ bool name_start = true;
+
+ for (const char *p = name; *p; p++)
+ {
+ if (*p == GUC_QUALIFIER_SEPARATOR)
+ {
+ if (name_start)
+ return false; /* empty name component */
+ num_sep++;
+ name_start = true;
+ }
+ else if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz", *p) != NULL ||
+ IS_HIGHBIT_SET(*p))
+ {
+ /* okay as first or non-first character */
+ name_start = false;
+ }
+ else if (!name_start && strchr("0123456789_$", *p) != NULL)
+ /* okay as non-first character */ ;
+ else
+ return false;
+ }
+ if (name_start)
+ return false; /* empty name component */
+ /* OK if we had exactly one separator */
+ return (num_sep == 1);
+}
+
/*
* Create and add a placeholder variable for a custom variable name.
*/
}
/*
- * Look up option NAME. If it exists, return a pointer to its record,
- * else return NULL. If create_placeholders is true, we'll create a
- * placeholder record for a valid-looking custom variable name.
+ * Look up option "name". If it exists, return a pointer to its record.
+ * Otherwise, if create_placeholders is true and name is a valid-looking
+ * custom variable name, we'll create and return a placeholder record.
+ * Otherwise, if skip_errors is true, then we silently return NULL for
+ * an unrecognized or invalid name. Otherwise, the error is reported at
+ * error level elevel (and we return NULL if that's less than ERROR).
+ *
+ * Note: internal errors, primarily out-of-memory, draw an elevel-level
+ * report and NULL return regardless of skip_errors. Hence, callers must
+ * handle a NULL return whenever elevel < ERROR, but they should not need
+ * to emit any additional error message. (In practice, internal errors
+ * can only happen when create_placeholders is true, so callers passing
+ * false need not think terribly hard about this.)
*/
static struct config_generic *
-find_option(const char *name, bool create_placeholders, int elevel)
+find_option(const char *name, bool create_placeholders, bool skip_errors,
+ int elevel)
{
const char **key = &name;
struct config_generic **res;
for (i = 0; map_old_guc_names[i] != NULL; i += 2)
{
if (guc_name_compare(name, map_old_guc_names[i]) == 0)
- return find_option(map_old_guc_names[i + 1], false, elevel);
+ return find_option(map_old_guc_names[i + 1], false,
+ skip_errors, elevel);
}
if (create_placeholders)
{
/*
- * Check if the name is qualified, and if so, add a placeholder.
+ * Check if the name is valid, and if so, add a placeholder. If it
+ * doesn't contain a separator, don't assume that it was meant to be a
+ * placeholder.
*/
if (strchr(name, GUC_QUALIFIER_SEPARATOR) != NULL)
- return add_placeholder_variable(name, elevel);
+ {
+ if (valid_custom_variable_name(name))
+ return add_placeholder_variable(name, elevel);
+ /* A special error message seems desirable here */
+ if (!skip_errors)
+ ereport(elevel,
+ (errcode(ERRCODE_INVALID_NAME),
+ errmsg("invalid configuration parameter name \"%s\"",
+ name),
+ errdetail("Custom parameter names must be of the form \"identifier.identifier\".")));
+ return NULL;
+ }
}
/* Unknown name */
+ if (!skip_errors)
+ ereport(elevel,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("unrecognized configuration parameter \"%s\"",
+ name)));
return NULL;
}
{
struct config_generic *record;
- record = find_option("in_hot_standby", false, ERROR);
+ record = find_option("in_hot_standby", false, false, ERROR);
Assert(record != NULL);
record->status |= GUC_NEEDS_REPORT;
report_needed = true;
(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
errmsg("cannot set parameters during a parallel operation")));
- record = find_option(name, true, elevel);
+ record = find_option(name, true, false, elevel);
if (record == NULL)
- {
- ereport(elevel,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\"", name)));
return 0;
- }
/*
* Check if the option can be set at this time. See guc.h for the precise
*/
elevel = IsUnderPostmaster ? DEBUG3 : LOG;
- record = find_option(name, true, elevel);
+ record = find_option(name, true, false, elevel);
/* should not happen */
if (record == NULL)
- elog(ERROR, "unrecognized configuration parameter \"%s\"", name);
+ return;
sourcefile = guc_strdup(elevel, sourcefile);
if (record->sourcefile)
struct config_generic *record;
static char buffer[256];
- record = find_option(name, false, ERROR);
+ record = find_option(name, false, missing_ok, ERROR);
if (record == NULL)
- {
- if (missing_ok)
- return NULL;
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\"",
- name)));
- }
+ return NULL;
if (restrict_privileged &&
(record->flags & GUC_SUPERUSER_ONLY) &&
!is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
struct config_generic *record;
static char buffer[256];
- record = find_option(name, false, ERROR);
- if (record == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\"", name)));
+ record = find_option(name, false, false, ERROR);
+ Assert(record != NULL);
if ((record->flags & GUC_SUPERUSER_ONLY) &&
!is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))
ereport(ERROR,
{
struct config_generic *record;
- record = find_option(name, false, WARNING);
+ record = find_option(name, false, missing_ok, ERROR);
if (record == NULL)
- {
- if (missing_ok)
- return 0;
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\"",
- name)));
- }
+ return 0;
return record->flags;
}
* Get flags for the variable; if it's not known, use default flags.
* (Caller might throw error later, but not our business to do so here.)
*/
- record = find_option(name, false, WARNING);
+ record = find_option(name, false, true, WARNING);
if (record)
flags = record->flags;
else
{
struct config_generic *record;
- record = find_option(name, false, ERROR);
- if (record == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\"",
- name)));
+ record = find_option(name, false, false, ERROR);
+ Assert(record != NULL);
/*
* Don't allow parameters that can't be set in configuration files to
{
struct config_generic *record;
- record = find_option(name, false, ERROR);
+ record = find_option(name, false, missing_ok, ERROR);
if (record == NULL)
{
- if (missing_ok)
- {
- if (varname)
- *varname = NULL;
- return NULL;
- }
-
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\"", name)));
+ if (varname)
+ *varname = NULL;
+ return NULL;
}
if ((record->flags & GUC_SUPERUSER_ONLY) &&
if ((varname = read_string_with_null(fp)) == NULL)
break;
- if ((record = find_option(varname, true, FATAL)) == NULL)
+ if ((record = find_option(varname, true, false, FATAL)) == NULL)
elog(FATAL, "failed to locate variable \"%s\" in exec config params file", varname);
if ((varvalue = read_string_with_null(fp)) == NULL)
(void) validate_option_array_item(name, value, false);
/* normalize name (converts obsolete GUC names to modern spellings) */
- record = find_option(name, false, WARNING);
+ record = find_option(name, false, true, WARNING);
if (record)
name = record->name;
(void) validate_option_array_item(name, NULL, false);
/* normalize name (converts obsolete GUC names to modern spellings) */
- record = find_option(name, false, WARNING);
+ record = find_option(name, false, true, WARNING);
if (record)
name = record->name;
* SUSET and user is superuser).
*
* name is not known, but exists or can be created as a placeholder (i.e.,
- * it has a prefixed name). We allow this case if you're a superuser,
+ * it has a valid custom name). We allow this case if you're a superuser,
* otherwise not. Superusers are assumed to know what they're doing. We
* can't allow it for other users, because when the placeholder is
* resolved it might turn out to be a SUSET variable;
* name is not known and can't be created as a placeholder. Throw error,
* unless skipIfNoPermissions is true, in which case return false.
*/
- gconf = find_option(name, true, WARNING);
+ gconf = find_option(name, true, skipIfNoPermissions, ERROR);
if (!gconf)
{
/* not known, failed to make a placeholder */
- if (skipIfNoPermissions)
- return false;
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\"",
- name)));
+ return false;
}
if (gconf->flags & GUC_CUSTOM_PLACEHOLDER)