DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

PostgreSQL 已 GRANT ALL,创建分区仍报 must be owner of table

PostgreSQL 给父表 GRANT ALL 后仍不能创建分区,确认父表 owner 与当前角色,采用维护角色或受控成员关系,并检查分区边界和锁影响。

已经执行 GRANT ALL ON TABLE app.events TO app_writer,该账户可以读写父表,执行 CREATE TABLE ... PARTITION OF app.events 却报 must be owner of table events。这里缺少的是父表所有者权限,不是又漏了一项普通表授权。

本文针对 PostgreSQL 声明式分区的创建操作。普通表权限中的 ALL 不会把账户变成所有者,也不会独立授予修改父表结构的权利;反复执行同样的表授权不会解决这个错误。

核对当前角色和父表所有者

先确认连接的是预期数据库,并使用准确 schema。以下查询中的 app.events 为示例父表:

SELECT current_database(), session_user, current_user;

SELECT n.nspname, c.relname, c.relkind,
       pg_get_userbyid(c.relowner) AS owner
FROM pg_class AS c
JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE c.oid = 'app.events'::regclass;

session_user 是会话的登录身份,current_user 是当前执行权限使用的角色,切换角色后可能不同。owner 是表的所有者;relkind = 'p' 表示分区父表。如果这里查到别的表、数据库或角色,先修正目标,再讨论授权。

能创建一张独立表,不代表能把它创建为另一张表的分区。PARTITION OF 会建立与父表的关系,权限检查涉及父表所有权;新分区所在 schema 的创建权限等条件也仍要满足。

优先交给拥有父表的维护角色

如果应用只负责业务读写,分区维护可以由拥有父表的部署或维护账户执行,无须把结构管理能力交给普通写入账户。超级用户也能完成,但不应为了定期建分区让应用永久使用超级用户。

需要由另一个账户维护时,可以评估让它使用父表所属角色。角色成员资格的授权范围通常覆盖该角色拥有或获准操作的其他对象,并非只多出“创建一个分区”的能力。应由有授权权限的管理员确认范围,记录现有成员关系和选项后配置。

如果账户已有允许切换的成员关系,下面展示一次明确切换身份的维护流程。partition_owner 必须替换为查询得到的实际所有者;范围假设父表按整数 id 做 RANGE 分区,且 [0,10) 尚未被其他分区使用:

SET ROLE partition_owner;
SELECT current_user;

CREATE TABLE app.events_0_10
PARTITION OF app.events
FOR VALUES FROM (0) TO (10);

RESET ROLE;

SET ROLE 不是任意账户都能成功的提权命令。没有允许切换的角色成员关系时,应停止并让管理员处理,不能通过再次给表 GRANT ALL 绕过。

在 PostgreSQL 16 及以后,成员关系中的 INHERIT 与 SET 选项会分别影响自动继承和切换能力,角色链上的选项也会影响结果。旧版本采用不同的成员继承控制方式。因此只看到“是成员”仍不足以确认当前会话拥有所需权限,应核对实际版本、成员链和当前身份。

权限修复以后,仍需检查分区边界和锁

CREATE TABLE ... PARTITION OF 会对父表取得 ACCESS EXCLUSIVE 锁,可能等待或阻塞并发业务。生产分区维护应在既定窗口内进行,事先确认定义、约束、边界和影响;不能把上面的范围示例用于任意父表。

创建后通过表定义或分区目录确认新表确实属于预期父表,分区范围正确,维护账户已恢复原身份。若业务允许,再用预期范围内的业务数据验证路由。权限错误消失但随后出现边界重叠等错误,应处理分区定义,不要继续扩大授权。

临时增加的成员资格应按原记录撤回,但撤权不会自动删除已经创建的分区。新分区若已接收数据,删除会影响数据,不能把 DROP TABLE 当成普通授权回退;需要走相应数据备份与分区维护流程。