static int GUC_check_errcode_value;
+static List *reserved_class_prefix = NIL;
+
/* global variables for check hook support */
char *GUC_check_errmsg_string;
char *GUC_check_errdetail_string;
* doesn't contain a separator, don't assume that it was meant to be a
* placeholder.
*/
- if (strchr(name, GUC_QUALIFIER_SEPARATOR) != NULL)
+ const char *sep = strchr(name, GUC_QUALIFIER_SEPARATOR);
+
+ if (sep != NULL)
{
- 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 two or more simple identifiers separated by dots.")));
- return NULL;
+ size_t classLen = sep - name;
+ ListCell *lc;
+
+ /* The name must be syntactically acceptable ... */
+ if (!valid_custom_variable_name(name))
+ {
+ if (!skip_errors)
+ ereport(elevel,
+ (errcode(ERRCODE_INVALID_NAME),
+ errmsg("invalid configuration parameter name \"%s\"",
+ name),
+ errdetail("Custom parameter names must be two or more simple identifiers separated by dots.")));
+ return NULL;
+ }
+ /* ... and it must not match any previously-reserved prefix */
+ foreach(lc, reserved_class_prefix)
+ {
+ const char *rcprefix = lfirst(lc);
+
+ if (strlen(rcprefix) == classLen &&
+ strncmp(name, rcprefix, classLen) == 0)
+ {
+ if (!skip_errors)
+ ereport(elevel,
+ (errcode(ERRCODE_INVALID_NAME),
+ errmsg("invalid configuration parameter name \"%s\"",
+ name),
+ errdetail("\"%s\" is a reserved prefix.",
+ rcprefix)));
+ return NULL;
+ }
+ }
+ /* OK, create it */
+ return add_placeholder_variable(name, elevel);
}
}
}
/*
+ * Mark the given GUC prefix as "reserved".
+ *
+ * This deletes any existing placeholders matching the prefix,
+ * and then prevents new ones from being created.
* Extensions should call this after they've defined all of their custom
* GUCs, to help catch misspelled config-file entries.
*/
void
-EmitWarningsOnPlaceholders(const char *className)
+MarkGUCPrefixReserved(const char *className)
{
int classLen = strlen(className);
int i;
+ MemoryContext oldcontext;
+ /*
+ * Check for existing placeholders. We must actually remove invalid
+ * placeholders, else future parallel worker startups will fail. (We
+ * don't bother trying to free associated memory, since this shouldn't
+ * happen often.)
+ */
for (i = 0; i < num_guc_variables; i++)
{
struct config_generic *var = guc_variables[i];
var->name[classLen] == GUC_QUALIFIER_SEPARATOR)
{
ereport(WARNING,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unrecognized configuration parameter \"%s\"",
- var->name)));
+ (errcode(ERRCODE_INVALID_NAME),
+ errmsg("invalid configuration parameter name \"%s\", removing it",
+ var->name),
+ errdetail("\"%s\" is now a reserved prefix.",
+ className)));
+ num_guc_variables--;
+ memmove(&guc_variables[i], &guc_variables[i + 1],
+ (num_guc_variables - i) * sizeof(struct config_generic *));
}
}
+
+ /* And remember the name so we can prevent future mistakes. */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ reserved_class_prefix = lappend(reserved_class_prefix, pstrdup(className));
+ MemoryContextSwitchTo(oldcontext);
}
DETAIL: Custom parameter names must be two or more simple identifiers separated by dots.
SHOW special."weird name";
ERROR: unrecognized configuration parameter "special.weird name"
+-- Check what happens when you try to set a "custom" GUC within the
+-- namespace of an extension.
+SET plpgsql.extra_foo_warnings = true; -- allowed if plpgsql is not loaded yet
+LOAD 'plpgsql'; -- this will throw a warning and delete the variable
+WARNING: invalid configuration parameter name "plpgsql.extra_foo_warnings", removing it
+DETAIL: "plpgsql" is now a reserved prefix.
+SET plpgsql.extra_foo_warnings = true; -- now, it's an error
+ERROR: invalid configuration parameter name "plpgsql.extra_foo_warnings"
+DETAIL: "plpgsql" is a reserved prefix.
+SHOW plpgsql.extra_foo_warnings;
+ERROR: unrecognized configuration parameter "plpgsql.extra_foo_warnings"
--
-- Test DISCARD TEMP
--