数据库迁移ALTER表后,如何处理返回表/记录类型的函数与存储过程?
嘿,我来帮你把PostgreSQL里这两个和表结构变更、函数依赖相关的问题讲清楚~
第一个问题:ALTER表后,能不能「重新编译」返回该表的函数?
PostgreSQL里没有像Oracle那样专门的ALTER FUNCTION ... RECOMPILE命令,但我们可以通过其他方式实现类似“重新绑定最新表结构”的效果:
最可靠的方式:用
CREATE OR REPLACE FUNCTION重新定义函数
当你修改了表结构后,直接重新执行函数的创建语句(用CREATE OR REPLACE),就能让函数绑定最新的表行类型。这是最常用也最安全的做法,不会丢失函数的权限、注释等属性。另类方式:执行不改变定义的ALTER操作
比如执行ALTER FUNCTION authenticate() OWNER TO CURRENT_USER;(前提是你当前就是函数的所有者),这种操作会触发PostgreSQL重新检查函数的依赖关系,间接更新它使用的表行类型。不过这种方式不如CREATE OR REPLACE直观,不推荐作为常规操作。极端方式:清除会话缓存
在当前会话里执行DISCARD ALL;,这个命令会清空会话中所有的对象缓存、临时表、变量等状态,之后再调用函数时,PostgreSQL会重新加载最新的表结构并解析函数。但要注意,这个操作会清除会话的所有状态,可能影响其他正在进行的操作,谨慎使用。
第二个问题:修改表后,返回记录类型的存储过程报错「wrong record type supplied in RETURN NEXT」
先把你提到的失败脚本补全,方便理解场景:
CREATE TABLE p1(a INT, b TEXT); CREATE OR REPLACE FUNCTION authenticate() RETURNS SETOF p1 as $$ DECLARE player_row p1; BEGIN -- 模拟获取表数据 SELECT * INTO player_row FROM p1 LIMIT 1; RETURN NEXT player_row; RETURN; END; $$ LANGUAGE plpgsql; -- 第一次调用正常 SELECT * FROM authenticate(); -- 修改表结构,添加新列 ALTER TABLE p1 ADD COLUMN c BOOLEAN; -- 同一个会话里再次调用,触发报错:wrong record type supplied in RETURN NEXT SELECT * FROM authenticate();
报错原因
PostgreSQL的会话会缓存对象的元数据(比如表的行类型)。当你在同一个会话里修改了表结构,会话里的旧表行类型缓存还没更新,而函数authenticate的返回类型是绑定到修改前的p1行类型(只有a和b列)。但此时你声明的player_row变量已经是新的行类型(包含a、b、c列),RETURN NEXT时就会出现类型不匹配的错误。
解决方法
有三种常用的解决途径:
- 重新创建函数
直接执行CREATE OR REPLACE FUNCTION重新定义函数,让它绑定最新的p1行类型,之后再调用就不会报错了。 - 断开并重新连接会话
关闭当前psql会话,重新连接后,新会话会加载最新的表结构元数据,此时调用函数就会使用新的行类型。 - 清除会话缓存
在当前会话里执行DISCARD ALL;,清空所有缓存后再调用函数,PostgreSQL会重新解析表结构和函数定义。
内容的提问来源于stack exchange,提问作者Gregor Petrin

