
# 用户存在依赖关系无法删除如何处理
#### 问题现象
数据库使用中遇到某些用户离职或者角色变更时，要对其账号进行销户、权限进行回收等操作，但是删除用户时出现类似：**role "u1" cannot be dropped because some objects depend on it**的报错信息，无法删除该用户。
例如，要删除用户u1时，出现如下提示：
```
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。
  ```
  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"的信息。
  ```
  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。
  ```
  testdb=# REASSIGN OWNED BY u1 TO u2;
  REASSIGN OWNED
  ```
  清理owner是u1的对象。请谨慎使用，会将用户同名的schema也一同清理掉。
  ```
  testdb=# DROP OWNED by u1;
  DROP OWNED
  ```
  

- **要删除的用户存在依赖关系，需要解除依赖关系** 。处理方法如下：
  1. 识别依赖关系。根据报错信息"3 objects in database gaussdb"可知gaussdb数据库里有3个对象依赖u1。由于数据库内系统表的依赖，在其他数据库中不会打印出详细的依赖对象信息，那么在gaussdb库中执行DROP USER的时候，会打印出具体的信息。 连接到gaussdb库执行如下命令：
     ```
     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
     ```
     获取到依赖项的详细信息如下：
     1. privileges for table pg_class：pg_class上u1用户的权限。
     
     2. schema u2上u1用户的权限。
      
  
  2. 撤销依赖对象的权限。
     ```
     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
     ```
     
  
  3. 再删除用户，可成功删除，不再提示有依赖。
     ```
     gaussdb=# DROP USER u1;
     DROP USER
     ```
     
   
 
- **有场景中存在不知道要删除用户的具体依赖对象，还是不能成功删除，要如何处理呢？** 此处以构造的案例进行演示，新建用户u3， 并赋予u2的SELECT权限。
  ```
  testdb2=# DROP USER u3;
  ERROR:  role "u3" cannot be dropped because some objects depend on it
  DETAIL:  2 objects in database gaussdb
  ```
  1. pg_shdepend系统表里记录了各个有依赖的对象的oid及其依赖关系。首先获取到用户的oid，再去系统表中找对应的依赖记录。
     ```
     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。
     
  
  2. 获取到的classid，代表依赖当前用户的对象的记录表的oid，在pg_class表中找到对应依赖即可。
     ```
     gaussdb=# SELECT relname,relacl FROM pg_class WHERE oid = 2615;
        relname    |     relacl
     --------------+----------------
      pg_namespace | {=r/role23}
     (1 row)
     ```
     
  
  3. 通过查询记录表是pg_namespace，那么就可以确认依赖用户的是一个schema。再到pg_namespace系统表中，查询[1]获取到的objid，可确认具体对象。
     ```
     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权限。
     ```
     gaussdb=# REVOKE USAGE ON SCHEMA u2 FROM u3;
     REVOKE
     ```
     
  
  4. 再删除用户u3，可成功删除。
     ```
     gaussdb=# DROP USER u3;
     DROP USER
     ```
     
   
 
