PostgreSQL 11升级至12时abstime函数权限授予失败的问题求助
这是典型的PostgreSQL版本迭代带来的兼容性问题——PostgreSQL 12彻底移除了abstime、reltime、tinterval这类遗留时间类型,以及对应的所有系统函数。你旧集群里针对这些函数的GRANT语句,在新集群里找不到对应的对象,自然就会触发pg_restore报错。同时系统表pg_shadow和pg_user的valuntil列,在PG12中已经从abstime改为timestamptz,不过这部分pg_upgrade通常会自动处理,重点还是权限的清理。
具体解决步骤
1. 清理旧PG11集群中的无效权限
这些pg_catalog下的abstime相关函数都是系统内置对象,普通用户(比如你的admin)根本不需要手动授予权限——系统默认的权限配置已经足够。所以第一步要在旧集群里撤销这些多余的授权:
首先连接到你的PG11集群:
psql -U postgres -d your_database_name
先确认这些权限确实存在(可选,但建议做):
SELECT routine_name, privilege_type FROM information_schema.role_routine_grants WHERE specific_schema = 'pg_catalog' AND routine_name LIKE '%abstime%' AND grantee = 'admin';
然后执行批量撤销操作(对应你导出的所有GRANT语句,改成REVOKE即可):
REVOKE ALL ON FUNCTION pg_catalog.abstime(timestamp without time zone) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstime(timestamp with time zone) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstimeeq(abstime, abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstimege(abstime, abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstimegt(abstime, abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstimein(cstring) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstimele(abstime, abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstimelt(abstime, abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstimene(abstime, abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstimeout(abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstimerecv(internal) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.abstimesend(abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.btabstimecmp(abstime, abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.date(abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.date_part(text, abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.intinterval(abstime, tinterval) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.isfinite(abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.mktinterval(abstime, abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog."time"(abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.timemi(abstime, reltime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.timepl(abstime, reltime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog."timestamp"(abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.timestamptz(abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.tinterval(abstime, abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.max(abstime) FROM admin; REVOKE ALL ON FUNCTION pg_catalog.min(abstime) FROM admin;
完成后,重新运行pg_upgrade的预检查,再执行实际升级操作,应该就能绕过权限报错了。
2. 关于pg_shadow/pg_user的valuntil列
PostgreSQL 12已经将这两个系统表的valuntil列类型从abstime改为timestamptz,不过abstime本质上是timestamp without time zone的别名,pg_upgrade在升级过程中会自动完成类型转换,不需要你手动干预。如果不放心,可以在旧集群里先检查一下这列的数据:
SELECT usename, valuntil FROM pg_shadow WHERE valuntil IS NOT NULL;
只要数据是有效的时间值,转换过程不会有问题。
3. 备选方案:用逻辑备份跳过无效权限
如果因为某些原因无法修改旧集群(比如只读环境),可以改用逻辑备份(pg_dump)的方式迁移:
- 先备份旧集群:
pg_dump -U postgres -d your_database_name -f pg11_backup.sql - 手动编辑备份文件,删除所有包含
abstime的GRANT语句; - 在PG12集群中恢复备份:
psql -U postgres -d your_database_name -f pg11_backup.sql
4. 升级后的验证
完成升级后,建议连接到PG12集群做两个检查:
-- 确认admin用户没有无效的权限条目 SELECT * FROM information_schema.role_routine_grants WHERE grantee = 'admin'; -- 确认valuntil列类型已经转换为timestamptz SELECT column_name, data_type FROM information_schema.columns WHERE table_name = 'pg_shadow' AND column_name = 'valuntil';
内容的提问来源于stack exchange,提问作者Michał Zawistowski

