本文將為您介紹在Hologres中如何刪除賬號(drop user),以及刪除賬號時報錯如何排查并處理。
背景信息
在日常業務使用中,會有需要刪除某個賬號的場景。在Hologres中當需要刪除的賬號是DB對象(數據庫、Schema、表、視圖等)的所有者時,通常執行刪除操作時會報錯,常見報錯如下。
賬號有所屬的對象,無法刪除報錯如下。
ERROR: role "<uid>" cannot be dropped because some objects depend on it DETAIL: owner of table xxx owner of schema yyy
賬號有對象依賴,無法刪除報錯如下。
ERROR: role "<uid>" cannot be dropped because some objects depend on it DETAIL: 1 object in database xxx
賬號上有被賦予的權限,無法刪除報錯如下。
ERROR: role "<uid>" cannot be dropped because some objects depend on it Detail: privileges for table xxx privileges for table yyy
刪除賬號報錯,都是因為被刪除的賬號在實例內還有對象(DB、Schema、View、Table)的依賴或者權限,所以不能直接刪除。
明確刪除賬號的原因
在刪除賬號之前,需要明確為什么需要刪除賬號,常見原因如下。
原因一:賬號授權有誤,想要刪除賬號,重新授權。
原因二:該賬號的所有者離職了或者賬號不再使用等業務種種原因確實需要刪除。
建議解決方法。
刪除賬號原因為原因一。
此情形不需要刪除賬號,建議將賬號當前的權限取消,再重新授權。
專家權限模型撤銷權限并重新授權,詳情請參見專家權限模型。
簡單權限模型撤銷授權并重新授權,詳情請參見簡單權限模型的使用和基于Schema級別的簡單權限模型的使用。
當前賬號被誤設置成了Normal,想要改成Superuser,執行以下語句進行修改。
-- 若是子賬號,需要將uid改成p4_id alter user "<uid>" superuser;
uid為賬號ID,詳情請參見賬號ID。
當前賬號被誤設置成了Superuser,想要改成普通用戶,執行以下語句進行修改。
說明將Superuser改成普通用戶后,用戶將會沒有任何權限,需要重新給用戶授權。
-- 若是子賬號,需要將uid改成p4_id alter user "<uid>" nosuperuser;
uid為賬號ID,詳情請參見賬號ID
刪除賬號原因為原因二。
保留賬號擁有的對象,將對象的所有者轉移給其他用戶,再刪除該賬號,詳情請參見刪除賬號但是保留賬號擁有的對象。
刪除賬號但是保留賬號擁有的對象
當確定要刪除賬號,又要保留賬號擁有的對象(包括表、View、函數)等時,可以將賬號擁有的對象轉移給另一個用戶,再將賬號刪除,命令語法如下。
將對象的所有者轉移給另一用戶。
REASSIGN OWNED BY "<uid>" TO "<Another_uid>" ;
uid為賬號ID,詳情請參見賬號ID。
刪除賬號。
DROP USER "<uid>";
查看賬號依賴
通過以下語句可以查看賬號的依賴對象。
select 'select * from ' || s.classid::regclass || ' where oid = ' || s.objid || '; (在 ' || d.datname || ' DB中執行)' as "查詢依賴的對象", case when deptype = 'a' then '權限依賴' when deptype = 'o' then 'Owner依賴' else deptype::text end as "依賴類型"from pg_shdepend s join pg_database d on (s.dbid = d.oid) join pg_roles r on (r.oid = s.refobjid) where datname = current_database() and refclassid = 1260 and r.rolname = '<用戶名>';
查看所有表、視圖、外表的Owner。
SELECT n.nspname AS "Schema", c.relname AS "Name", CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 't' THEN 'TOAST table' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END AS "Type", pg_catalog.pg_get_userbyid(c.relowner) AS "Owner", pg_catalog.obj_description(c.oid,'pg_class') AS "Description" FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN ('r', 'p', 't', 'v', 'm', 'S', 's', 'f', '') AND pg_catalog.pg_table_is_visible(c.oid);
查看某用戶為Owner的表、視圖、外表。
SELECT n.nspname AS "Schema", c.relname AS "Name", CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 't' THEN 'TOAST table' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' WHEN 'I' THEN 'partitioned index' END AS "Type", pg_catalog.pg_get_userbyid(c.relowner) AS "Owner", pg_catalog.obj_description(c.oid, 'pg_class') AS "Description" FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN ('r', 'p', 't', 'v', 'm', 'S', 's', 'f', '') AND pg_catalog.pg_table_is_visible(c.oid) AND pg_catalog.pg_get_userbyid(c.relowner) ='<user_name>';
更改Owner。
-- 更改表的Owner ALTER TABLE schema_name.table_name OWNER TO new_owner; -- 更改外表的Owner ALTER FOREIGN TABLE schema_name.foreign_table_name OWNER TO new_owner; -- 更改視圖的Owner ALTER VIEW schema_name.view_name OWNER TO new_owner;
查看SCHEMA的Owner
查看所有SCHEMA的Owner。
SELECT n.nspname AS "Name", pg_catalog.pg_get_userbyid(n.nspowner) AS "Owner", pg_catalog.array_to_string(n.nspacl, E'\n') AS "Access privileges", pg_catalog.obj_description(n.oid, 'pg_namespace') AS "Description" FROM pg_catalog.pg_namespace n ORDER BY 1;
查看某用戶為Owner的SCHEMA。
SELECT n.nspname AS "Name", pg_catalog.pg_get_userbyid(n.nspowner) AS "Owner", pg_catalog.array_to_string(n.nspacl, E'\n') AS "Access privileges", pg_catalog.obj_description(n.oid, 'pg_namespace') AS "Description" FROM pg_catalog.pg_namespace n WHERE pg_catalog.pg_get_userbyid(n.nspowner) ='<user_name>';
更改Owner。
-- 更改schema的Owner ALTER SCHEMA schema_name OWNER TO new_owner;
查看Server的Owner。
查看所有SERVER的Owner。
SELECT s.srvname AS "Name", pg_catalog.pg_get_userbyid(s.srvowner) AS "Owner", f.fdwname AS "Foreign-data wrapper", pg_catalog.array_to_string(s.srvacl, E'\n') AS "Access privileges", s.srvtype AS "Type", s.srvversion AS "Version", CASE WHEN srvoptions IS NULL THEN '' ELSE '(' || pg_catalog.array_to_string(ARRAY ( SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM pg_catalog.pg_options_to_table(srvoptions)), ', ') || ')' END AS "FDW options", d.description AS "Description" FROM pg_catalog.pg_foreign_server s JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid = s.srvfdw LEFT JOIN pg_catalog.pg_description d ON d.classoid = s.tableoid AND d.objoid = s.oid AND d.objsubid = 0;
查看某用戶為Owner的SERVER。
SELECT s.srvname AS "Name", pg_catalog.pg_get_userbyid(s.srvowner) AS "Owner", f.fdwname AS "Foreign-data wrapper", pg_catalog.array_to_string(s.srvacl, E'\n') AS "Access privileges", s.srvtype AS "Type", s.srvversion AS "Version", CASE WHEN srvoptions IS NULL THEN '' ELSE '(' || pg_catalog.array_to_string(ARRAY ( SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM pg_catalog.pg_options_to_table(srvoptions)), ', ') || ')' END AS "FDW options", d.description AS "Description" FROM pg_catalog.pg_foreign_server s JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid = s.srvfdw LEFT JOIN pg_catalog.pg_description d ON d.classoid = s.tableoid AND d.objoid = s.oid AND d.objsubid = 0 WHERE pg_catalog.pg_get_userbyid(s.srvowner) = '<user_name>';
更改Owner。
-- 更改server的Owner ALTER SERVER server_name OWNER TO new_owner;
查看USER MAPPING的Owner。
查看所有USER MAPPING的Owner。
SELECT um.srvname AS "Server", um.usename AS "User name", CASE WHEN umoptions IS NULL THEN '' ELSE '(' || pg_catalog.array_to_string(ARRAY ( SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM pg_catalog.pg_options_to_table(umoptions)), ', ') || ')' END AS "FDW options" FROM pg_catalog.pg_user_mappings um;
查看某用戶為Owner的USER MAPPING。
SELECT um.srvname AS "Server", um.usename AS "User name", CASE WHEN umoptions IS NULL THEN '' ELSE '(' || pg_catalog.array_to_string(ARRAY ( SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM pg_catalog.pg_options_to_table(umoptions)), ', ') || ')' END AS "FDW options" FROM pg_catalog.pg_user_mappings um WHERE um.usename = '<user_name>';
刪除User Mapping。
-- 刪除User Mapping DROP USER MAPPING FOR user_name SERVER server_name;