用户存在依赖关系无法删除如何处理
问题现象
数据库使用中遇到某些用户离职或者角色变更时,要对其账号进行销户、权限进行回收等操作,但是删除用户时出现类似:role “u1” cannot be dropped because some objects depend on it的报错信息,无法删除该用户。
例如,要删除用户u1时,出现如下提示:
1 2 3 4 |
testdb=# DROP USER u1; ERROR: role "u1" cannot be dropped because some objects depend on it DETAIL: owner of database testdb 3 objects in database gaussdb |
原因分析
如果用户或角色的权限比较复杂、依赖较多,删除用户时就会报错存在依赖关系无法删除。通过上述问题现象中的ERROR的提示信息,获取以下信息:
- 要删除的用户为数据库testdb的owner。
- 有3个依赖的对象在gaussdb数据库中。
处理方法
- 要删除的用户为一个数据库的owner,需要将对象的所有权重新分配给其他用户。有以下两种处理方法:
方式一:将数据库owner转移给其他用户。例如,使用ALTER语句将数据库testdb的owner用户u1修改为u2。
1 2 3 4 5 6 7 8
testdb=# ALTER DATABASE testdb OWNER to u2; ALTER DATABASE testdb=# \l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+-------------+-------------+------------------------- testdb | u2 | UTF8 | en_US.UTF-8 | en_US.UTF-8 | (4 rows)
执行删除u1用户的命令,不再提示“owner of database testdb”的信息。1 2 3
testdb=# DROP USER u1; ERROR: role "u1" cannot be dropped because some objects depend on it DETAIL: 3 objects in database gaussdb
方式二:如果已确认不需要数据库testdb,也可直接将其删除。将所有u1拥有的数据库对象的属主更改为u2。1 2
testdb=# REASSIGN OWNED BY u1 TO u2; REASSIGN OWNED
清理owner是u1的对象。请谨慎使用,会将用户同名的schema也一同清理掉。
1 2
testdb=# DROP OWNED by u1; DROP OWNED
- 要删除的用户存在依赖关系,需要解除依赖关系。处理方法如下:
- 识别依赖关系。根据报错信息“3 objects in database gaussdb”可知gaussdb数据库里有3个对象依赖u1。由于数据库内系统表的依赖,在其他数据库中不会打印出详细的依赖对象信息,那么在gaussdb库中执行DROP USER的时候,会打印出具体的信息。
1 2 3 4
gaussdb=# DROP USER u1; ERROR: role "u1" cannot be dropped because some objects depend on it DETAIL: privileges for table pg_class privileges for schema u2
获取到依赖项的详细信息如下:
- privileges for table pg_class:pg_class上u1用户的权限。
- schema u2上u1用户的权限。
- 撤销依赖对象的权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
gaussdb=# SELECT relname,relacl FROM pg_class WHERE relname = 'pg_class'; relname | relacl ----------+---------------------------------- pg_class | {=r/Ruby,u1=r/Ruby} (1 row) gaussdb=#SELECT nspname,nspacl FROM pg_namespace WHERE nspname = 'u2'; nspname | nspacl ---------+----------------------------- u2 | {u2=UC/u2,u2=LP/u2,u1=U/u2} gaussdb=# REVOKE SELECT ON TABLE pg_class FROM u1; REVOKE gaussdb=# REVOKE USAGE ON SCHEMA u2 FROM u1; REVOKE
- 再删除用户,可成功删除,不再提示有依赖。
1 2
gaussdb=# DROP USER u1; DROP USER
- 识别依赖关系。根据报错信息“3 objects in database gaussdb”可知gaussdb数据库里有3个对象依赖u1。由于数据库内系统表的依赖,在其他数据库中不会打印出详细的依赖对象信息,那么在gaussdb库中执行DROP USER的时候,会打印出具体的信息。
- 有场景中存在不知道要删除用户的具体依赖对象,还是不能成功删除,要如何处理呢?此处以构造的案例进行演示,新建用户u3, 并赋予u2的SELECT权限。
1 2 3
testdb2=# DROP USER u3; ERROR: role "u3" cannot be dropped because some objects depend on it DETAIL: 2 objects in database gaussdb
- pg_shdepend系统表里记录了各个有依赖的对象的oid及其依赖关系。首先获取到用户的oid,再去系统表中找对应的依赖记录。
1 2 3 4 5 6 7 8 9 10 11 12
testdb2=# SELECT oid ,rolname FROM pg_roles WHERE rolname = 'u3'; oid | rolname ------------+--------- 2147484573 | u3 (1 row) gaussdb=# SELECT * FROM pg_shdepend WHERE refobjid = 2147484573; dbid | classid | objid | objsubid | refclassid | refobjid | deptype | objfile -------+---------+------------+----------+------------+------------+---------+--------- 16073 | 2615 | 2147484575 | 0 | 1260 | 2147484573 | o | 16073 | 2615 | 2147484025 | 0 | 1260 | 2147484573 | a | (2 rows)
由于dependType不同,因此有两条记录,一条记录代表权限依赖(a),另一条记录代表自身是一个对象的owner。
- 获取到的classid,代表依赖当前用户的对象的记录表的oid,在pg_class表中找到对应依赖即可。
1 2 3 4 5
gaussdb=# SELECT relname,relacl FROM pg_class WHERE oid = 2615; relname | relacl --------------+---------------- pg_namespace | {=r/role23} (1 row)
- 通过查询记录表是pg_namespace,那么就可以确认依赖用户的是一个schema。再到pg_namespace系统表中,查询1获取到的objid,可确认具体对象。
1 2 3 4 5 6
gaussdb=# SELECT nspname,nspacl FROM pg_namespace WHERE oid in (2147484575,2147484025); nspname | nspacl ---------+--------------------------------------------------------- u3 | u2 | {u2=UC/u2,u2=LP/u2,u3=U/u2} (2 rows)
这里看到有两个schema,u3是用户同名的schema,u2是赋权的schema,撤销赋权schema权限。
1 2
gaussdb=# REVOKE USAGE ON SCHEMA u2 FROM u3; REVOKE
- 再删除用户u3,可成功删除。
1 2
gaussdb=# DROP USER u3; DROP USER
- pg_shdepend系统表里记录了各个有依赖的对象的oid及其依赖关系。首先获取到用户的oid,再去系统表中找对应的依赖记录。