2222#include "catalog/pg_auth_members.h"
2323#include "catalog/pg_authid.h"
2424#include "catalog/pg_class.h"
25+ #include "catalog/pg_database.h"
2526#include "catalog/pg_type.h"
2627#include "commands/dbcommands.h"
2728#include "commands/proclang.h"
@@ -68,6 +69,7 @@ enum RoleRecurseType
6869};
6970static Oid cached_role [] = {InvalidOid , InvalidOid };
7071static List * cached_roles [] = {NIL , NIL };
72+ static uint32 cached_db_hash ;
7173
7274
7375static const char * getid (const char * s , char * n );
@@ -4665,17 +4667,24 @@ initialize_acl(void)
46654667{
46664668 if (!IsBootstrapProcessingMode ())
46674669 {
4670+ cached_db_hash =
4671+ GetSysCacheHashValue1 (DATABASEOID ,
4672+ ObjectIdGetDatum (MyDatabaseId ));
4673+
46684674 /*
46694675 * In normal mode, set a callback on any syscache invalidation of rows
4670- * of pg_auth_members (for roles_is_member_of()) or pg_authid (for
4671- * has_rolinherit())
4676+ * of pg_auth_members (for roles_is_member_of()), pg_authid (for
4677+ * has_rolinherit()), or pg_database (for roles_is_member_of())
46724678 */
46734679 CacheRegisterSyscacheCallback (AUTHMEMROLEMEM ,
46744680 RoleMembershipCacheCallback ,
46754681 (Datum ) 0 );
46764682 CacheRegisterSyscacheCallback (AUTHOID ,
46774683 RoleMembershipCacheCallback ,
46784684 (Datum ) 0 );
4685+ CacheRegisterSyscacheCallback (DATABASEOID ,
4686+ RoleMembershipCacheCallback ,
4687+ (Datum ) 0 );
46794688 }
46804689}
46814690
@@ -4686,6 +4695,13 @@ initialize_acl(void)
46864695static void
46874696RoleMembershipCacheCallback (Datum arg , int cacheid , uint32 hashvalue )
46884697{
4698+ if (cacheid == DATABASEOID &&
4699+ hashvalue != cached_db_hash &&
4700+ hashvalue != 0 )
4701+ {
4702+ return ; /* ignore pg_database changes for other DBs */
4703+ }
4704+
46894705 /* Force membership caches to be recomputed on next use */
46904706 cached_role [ROLERECURSE_PRIVS ] = InvalidOid ;
46914707 cached_role [ROLERECURSE_MEMBERS ] = InvalidOid ;
@@ -4728,6 +4744,7 @@ static List *
47284744roles_is_member_of (Oid roleid , enum RoleRecurseType type ,
47294745 Oid admin_of , bool * is_admin )
47304746{
4747+ Oid dba ;
47314748 List * roles_list ;
47324749 ListCell * l ;
47334750 List * new_cached_roles ;
@@ -4740,6 +4757,24 @@ roles_is_member_of(Oid roleid, enum RoleRecurseType type,
47404757 OidIsValid (cached_role [type ]))
47414758 return cached_roles [type ];
47424759
4760+ /*
4761+ * Role expansion happens in a non-database backend when guc.c checks
4762+ * DEFAULT_ROLE_READ_ALL_SETTINGS for a physical walsender SHOW command.
4763+ * In that case, no role gets pg_database_owner.
4764+ */
4765+ if (!OidIsValid (MyDatabaseId ))
4766+ dba = InvalidOid ;
4767+ else
4768+ {
4769+ HeapTuple dbtup ;
4770+
4771+ dbtup = SearchSysCache1 (DATABASEOID , ObjectIdGetDatum (MyDatabaseId ));
4772+ if (!HeapTupleIsValid (dbtup ))
4773+ elog (ERROR , "cache lookup failed for database %u" , MyDatabaseId );
4774+ dba = ((Form_pg_database ) GETSTRUCT (dbtup ))-> datdba ;
4775+ ReleaseSysCache (dbtup );
4776+ }
4777+
47434778 /*
47444779 * Find all the roles that roleid is a member of, including multi-level
47454780 * recursion. The role itself will always be the first element of the
@@ -4787,6 +4822,11 @@ roles_is_member_of(Oid roleid, enum RoleRecurseType type,
47874822 roles_list = list_append_unique_oid (roles_list , otherid );
47884823 }
47894824 ReleaseSysCacheList (memlist );
4825+
4826+ /* implement pg_database_owner implicit membership */
4827+ if (memberid == dba && OidIsValid (dba ))
4828+ roles_list = list_append_unique_oid (roles_list ,
4829+ DEFAULT_ROLE_DATABASE_OWNER );
47904830 }
47914831
47924832 /*
0 commit comments