From 29610d4e417a1a0cf099e10736b5c14aec90f641 Mon Sep 17 00:00:00 2001 From: Justin Pryzby Date: Sun, 21 Jul 2024 09:49:17 -0500 Subject: [PATCH 1/4] change function SET to use a separate GUC source This allows distinguishing it from ALTER ROLE SET and ALTER DATABASE SET, as needed for the following patch. See also: 2abae34a2e8fde42be731b4e18d44cd08901464d - added function SET 0c66a223774dec62edb5281a47e72fe480a8f7aa - (partially) updated comments about PGC_S_TEST --- src/backend/access/table/tableamapi.c | 2 +- src/backend/catalog/pg_db_role_setting.c | 8 ++++---- src/backend/commands/functioncmds.c | 4 ++-- src/backend/commands/tablespace.c | 4 ++-- src/backend/commands/variable.c | 8 ++++---- src/backend/storage/buffer/localbuf.c | 2 +- src/backend/utils/cache/ts_cache.c | 2 +- src/backend/utils/misc/guc.c | 18 +++++++++--------- src/include/utils/guc.h | 7 ++++--- 9 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/backend/access/table/tableamapi.c b/src/backend/access/table/tableamapi.c index e9b598256fb..7c0f08ed46d 100644 --- a/src/backend/access/table/tableamapi.c +++ b/src/backend/access/table/tableamapi.c @@ -132,7 +132,7 @@ check_default_table_access_method(char **newval, void **extra, GucSource source) * nonexistent table access method, only a NOTICE. See comments in * guc.h. */ - if (source == PGC_S_TEST) + if (source == PGC_S_TEST || source == PGC_S_TEST_FUNCTION) { ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_OBJECT), diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c index 8c20f519fc0..abfcc5655b3 100644 --- a/src/backend/catalog/pg_db_role_setting.c +++ b/src/backend/catalog/pg_db_role_setting.c @@ -70,7 +70,7 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt) RelationGetDescr(rel), &isnull); if (!isnull) - new = GUCArrayReset(DatumGetArrayTypeP(datum)); + new = GUCArrayReset(DatumGetArrayTypeP(datum), PGC_S_TEST); if (new) { @@ -115,9 +115,9 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt) /* Update (valuestr is NULL in RESET cases) */ if (valuestr) - a = GUCArrayAdd(a, setstmt->name, valuestr); + a = GUCArrayAdd(a, setstmt->name, valuestr, PGC_S_TEST); else - a = GUCArrayDelete(a, setstmt->name); + a = GUCArrayDelete(a, setstmt->name, PGC_S_TEST); if (a) { @@ -141,7 +141,7 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt) memset(nulls, false, sizeof(nulls)); - a = GUCArrayAdd(NULL, setstmt->name, valuestr); + a = GUCArrayAdd(NULL, setstmt->name, valuestr, PGC_S_TEST); values[Anum_pg_db_role_setting_setdatabase - 1] = ObjectIdGetDatum(databaseid); diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 6593fd7d811..30a58cf027c 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -657,9 +657,9 @@ update_proconfig_value(ArrayType *a, List *set_items) char *valuestr = ExtractSetVariableArgs(sstmt); if (valuestr) - a = GUCArrayAdd(a, sstmt->name, valuestr); + a = GUCArrayAdd(a, sstmt->name, valuestr, PGC_S_TEST_FUNCTION); else /* RESET */ - a = GUCArrayDelete(a, sstmt->name); + a = GUCArrayDelete(a, sstmt->name, PGC_S_TEST_FUNCTION); } } diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 113b4807315..b0a460c1622 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -1104,7 +1104,7 @@ check_default_tablespace(char **newval, void **extra, GucSource source) * When source == PGC_S_TEST, don't throw a hard error for a * nonexistent tablespace, only a NOTICE. See comments in guc.h. */ - if (source == PGC_S_TEST) + if (source == PGC_S_TEST || source == PGC_S_TEST_FUNCTION) { ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -1251,7 +1251,7 @@ check_temp_tablespaces(char **newval, void **extra, GucSource source) curoid = get_tablespace_oid(curname, source <= PGC_S_TEST); if (curoid == InvalidOid) { - if (source == PGC_S_TEST) + if (source == PGC_S_TEST || source == PGC_S_TEST_FUNCTION) ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 9345131711e..c9421b17952 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -831,7 +831,7 @@ check_session_authorization(char **newval, void **extra, GucSource source) roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval)); if (!HeapTupleIsValid(roleTup)) { - if (source == PGC_S_TEST) + if (source == PGC_S_TEST || source == PGC_S_TEST_FUNCTION) { ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -856,7 +856,7 @@ check_session_authorization(char **newval, void **extra, GucSource source) if (roleid != GetAuthenticatedUserId() && !superuser_arg(GetAuthenticatedUserId())) { - if (source == PGC_S_TEST) + if (source == PGC_S_TEST || source == PGC_S_TEST_FUNCTION) { ereport(NOTICE, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), @@ -940,7 +940,7 @@ check_role(char **newval, void **extra, GucSource source) roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval)); if (!HeapTupleIsValid(roleTup)) { - if (source == PGC_S_TEST) + if (source == PGC_S_TEST || source == PGC_S_TEST_FUNCTION) { ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -965,7 +965,7 @@ check_role(char **newval, void **extra, GucSource source) if (!InitializingParallelWorker && !member_can_set_role(GetSessionUserId(), roleid)) { - if (source == PGC_S_TEST) + if (source == PGC_S_TEST || source == PGC_S_TEST_FUNCTION) { ereport(NOTICE, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 8da7dd6c98a..0e92f604061 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -707,7 +707,7 @@ check_temp_buffers(int *newval, void **extra, GucSource source) * Once local buffers have been initialized, it's too late to change this. * However, if this is only a test call, allow it. */ - if (source != PGC_S_TEST && NLocBuffer && NLocBuffer != *newval) + if ((source != PGC_S_TEST && source != PGC_S_TEST_FUNCTION) && NLocBuffer && NLocBuffer != *newval) { GUC_check_errdetail("\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session."); return false; diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c index 54de33eadd2..9d7e8b66763 100644 --- a/src/backend/utils/cache/ts_cache.c +++ b/src/backend/utils/cache/ts_cache.c @@ -628,7 +628,7 @@ check_default_text_search_config(char **newval, void **extra, GucSource source) */ if (!OidIsValid(cfgId)) { - if (source == PGC_S_TEST) + if (source == PGC_S_TEST || source == PGC_S_TEST_FUNCTION) { ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_OBJECT), diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index a043d529efa..e2734475189 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -252,7 +252,7 @@ static void reapply_stacked_values(struct config_generic *variable, GucContext curscontext, GucSource cursource, Oid cursrole); static bool validate_option_array_item(const char *name, const char *value, - bool skipIfNoPermissions); + bool skipIfNoPermissions, int source); static void write_auto_conf_file(int fd, const char *filename, ConfigVariable *head); static void replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p, const char *name, const char *value); @@ -6444,7 +6444,7 @@ ProcessGUCArray(ArrayType *array, * to indicate the current table entry is NULL. */ ArrayType * -GUCArrayAdd(ArrayType *array, const char *name, const char *value) +GUCArrayAdd(ArrayType *array, const char *name, const char *value, int source) { struct config_generic *record; Datum datum; @@ -6455,7 +6455,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value) Assert(value); /* test if the option is valid and we're allowed to set it */ - (void) validate_option_array_item(name, value, false); + (void) validate_option_array_item(name, value, false, source); /* normalize name (converts obsolete GUC names to modern spellings) */ record = find_option(name, false, true, WARNING); @@ -6522,7 +6522,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value) * is NULL then a null should be stored. */ ArrayType * -GUCArrayDelete(ArrayType *array, const char *name) +GUCArrayDelete(ArrayType *array, const char *name, int source) { struct config_generic *record; ArrayType *newarray; @@ -6532,7 +6532,7 @@ GUCArrayDelete(ArrayType *array, const char *name) Assert(name); /* test if the option is valid and we're allowed to set it */ - (void) validate_option_array_item(name, NULL, false); + (void) validate_option_array_item(name, NULL, false, source); /* normalize name (converts obsolete GUC names to modern spellings) */ record = find_option(name, false, true, WARNING); @@ -6592,7 +6592,7 @@ GUCArrayDelete(ArrayType *array, const char *name) * those that are PGC_USERSET or we have permission to set */ ArrayType * -GUCArrayReset(ArrayType *array) +GUCArrayReset(ArrayType *array, int source) { ArrayType *newarray; int i; @@ -6630,7 +6630,7 @@ GUCArrayReset(ArrayType *array) *eqsgn = '\0'; /* skip if we have permission to delete it */ - if (validate_option_array_item(val, NULL, true)) + if (validate_option_array_item(val, NULL, true, source)) continue; /* else add it to the output array */ @@ -6665,7 +6665,7 @@ GUCArrayReset(ArrayType *array) */ static bool validate_option_array_item(const char *name, const char *value, - bool skipIfNoPermissions) + bool skipIfNoPermissions, int source) { struct config_generic *gconf; @@ -6726,7 +6726,7 @@ validate_option_array_item(const char *name, const char *value, /* test for permissions and valid option value */ (void) set_config_option(name, value, superuser() ? PGC_SUSET : PGC_USERSET, - PGC_S_TEST, GUC_ACTION_SET, false, 0, false); + source, GUC_ACTION_SET, false, 0, false); return true; } diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index ff506bf48d9..84203109af7 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -119,6 +119,7 @@ typedef enum PGC_S_OVERRIDE, /* special case to forcibly set default */ PGC_S_INTERACTIVE, /* dividing line for error reporting */ PGC_S_TEST, /* test per-database or per-user setting */ + PGC_S_TEST_FUNCTION, /* function SET */ PGC_S_SESSION, /* SET command */ } GucSource; @@ -406,9 +407,9 @@ extern void TransformGUCArray(ArrayType *array, List **names, List **values); extern void ProcessGUCArray(ArrayType *array, GucContext context, GucSource source, GucAction action); -extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value); -extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name); -extern ArrayType *GUCArrayReset(ArrayType *array); +extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value, int source); +extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name, int source); +extern ArrayType *GUCArrayReset(ArrayType *array, int source); extern void *guc_malloc(int elevel, size_t size); extern pg_nodiscard void *guc_realloc(int elevel, void *old, size_t size); -- 2.42.0