最近打算将现有的 PostgreSQL 数据库迁移到免费的 supabase 云数据库中,但是迁移的时候发生了问题。

原本的 PostgreSQL 放在我自己的云服务器上面,它的初始用户是通过 Docker 指定的,这个用户具备SUPERUSER权限。我一直使用的自己创建的yin2hao用户

supabase 云数据库没有给用户提供带有SUPERUSER权限的用户,而是给了一个隶属于普通用户权限的用户postgresql。登录控制台也是使用的这一个用户

image\.png

我按照流程,在supabase创建用户CREATE USER yin2hao WITH PASSWORD '*****',然后使用psql指令执行 sql 插入数据出错。

查看一下报错的行数,发现其都与表权限有关。

ALTER TABLE public.account_api_keys OWNER TO yin2hao;

ALTER TABLE public.agent_conversation_messages OWNER TO yin2hao;

查询资料得知,postgresql 的用户间权限分为ADMIN INHERIT SET。其作用分别是:

权限 ADMIN INHERIT SET
作用 授予和撤销成员资格 继承对象权限 切换到用户

在pg CREATE USER yin2hao WITH PASSWORD '*****'的时候,默认自动执行了GRANT yin2hao to postgres WITH ADMIN TRUE, INHERIT FALSE, SET FALSE;

可以看到,这里的SET默认为false。在ALTER TABLE public.account_api_keys OWNER TO yin2hao;时,是将表从当前的postgresql用户授予yin2hao,在pg中授予需要postgres能够切换到yin2hao,防止误操作将表授予到一个不可达的用户。

执行GRANT yin2hao TO postgres WITH SET TRUE;之后即可正常插入

还遇到个小插曲,我在验证这个结论的时候,在一台全新的服务器上安装了一台全新的PostgreSQL,并且连接上去。但是我在 superuser 用户下,CREATE USER test1 WITH CREATEROLE,再SET ROLE test1进入 test1 ,在 test1 用户 CREATE USER test2,按理来说,这个时候 test1 和 test2 之间的 SET 为 false,不应该能够切换过去。但是实际上,如果在此时SET ROLE test2能够正常切换。

这是因为,它的官方文档中存在一个 session_user 和 current_user ,其中session_user是连接的时候使用的用户,而切换用户的时候,SET ROLE是检查的 session_user。也就是说,在这个情况下,在SET ROLE test2的时候,它检测的是最开始的SUPERUSER用户对于test2的SET权限。

查询也验证了我的结论

SELECT current_user, session_user;

Text
1
2
3
4
5
6
[
{
"current_user": "test1",
"session_user": "postgres"
}
]