本文翻译自:https://www.cybertec-postgresql.com/en/drop-role-or-drop-user-postgresql/
下面是文章译文:
咋看起来,你可能以为drop role(或者drop user,两者同义)是一件简单的事情。然而,事情并不总是这样。所以我想把其中遇到的问题和解决方法与大家分享下。
为什么PostgreSQL中没有drop
role … cascade?
PostgreSQL将对象之间的依赖关系存放在系统表pg_depend和pg_shdepend中。有些情况下,删除一个对象同时也会自动删除与该对象有关的对象:比如,删除一张表也会删除该表上的索引和触发器。在其他情况下,删除一个有依赖的对象会报错:例如,删除一个包含其他对象的模式。
通常情况下,删除对象时带上cascade选项会自动删除其依赖的对象。例如,”drop schema schema_name cascade”会自动删除该模式下的所有对象。所以奇怪的是drop role没有cascade选项。原因是什么呢?考虑以下事实:
(1)角色会拥有不同数据库下的对象及权限
(2)一个SQL语句执行操作当前数据库下的对象
因此,PostgreSQL无法保证一个SQL语句删除一个角色涉及的所有对象。所以drop role没有可以删除所有依赖对象的cascade选项。
如何避免drop role带来的问题?
最佳选择是永远不删除一个拥有对象或者权限的角色。如果使用角色组来分配权限和属主,如果你确定那些可能会被删除的角色是组成员,这将变得容易实现。那样的话,通过角色继承组的所有权限,你可以随时删除该角色。例如,你有角色readonly,该角色有所有对象的只读权限,如果你临时需要一个只读角色,可以将该临时角色变成readonly的成员(将readonly授权给该临时角色)。
使用角色组的另一个好处是你不需要将相同权限授权给多个角色。那样不仅繁琐易错,而且会使对象上的访问控制列表变得很臃肿。
大帮手:drop owned by 和 reassign owned by
PostgreSQL中有个drop owned
by命令,它会删除在当前数据库中一个角色拥有的所有对象。该命令同时还会回收该角色的所有权限。所以你可以在逐个数据库中执行”drop owned by role_name”来删除所有该角色依赖的对象。
注意该操作会失败:drop owned by命令删除的对象可能被其他角色创建的对象依赖,
从而导致PostgreSQL无法删除这些对象。这种情况下,你可以使用”drop
owned by role_name cascade”来级联删除这些依赖对象。
一个可替代的方法是将这些依赖对象的属主改为其他角色。你可以通过命令reassign owned
by命令来完成该操作。再次提醒,这些操作仅仅影响当前数据库,所以你必须在每个数据库中都发起一次reassign
owned by命令。
注:reassign owned by不会改变或移除授权给该角色的权限,所以你可以再执行drop owned by来删除这些权限。
drop owned by遗留的对象
drop owned by无法删除的仅有两类对象,这两类对象不属于任何数据库:
(1)属主是被删除角色的数据库
(2)属主是被删除角色的表空间
删除数据库很简单:登录postgres数据库,然后删除数据库或者修改数据库的属主。
表空间略微复杂:在PostgreSQL中,你无法删除一个有对象的表空间。这种情况跟角色相似,因为表空间可以包含来自不同数据库的对象。因此,drop tablespace没有cascade选项。在实际操作中,你可以通过修改表空间的属主的来解决该问题。
但是,删除”postgres”角色时仍然会报错!
在PostgreSQL集群中有一个特殊角色:initdb初始化时创建的超级管理员。该角色通常被称为”postgres”,但是它的对象id总是10。如果你视图删除该角色或者执行drop owned by和reassign owned by,会返回如下报错信息:
cannot drop role
postgres because it is required by the database system
cannot drop objects
owned by role postgres because they are required by the database system
cannot reassign
ownership of objects owned by role postgres because they are required by the
database system
你总会需要一个超级管理员角色,所以你无法移除它。如果你不喜欢该角色的名字,你可以通过alter role postgres rename to role_name轻易的改变它的名字。在PostgreSQL中,对象名称只是一个标记,你可以随时改变他们。
结论
drop owned by和reassign
owned by命令使得删除角色变得不在困难,即便角色有很多依赖也没关系。避免问题更好的方式授权给角色组,而非有可能被删除的角色。