PostgreSQL不可变函数在表参数定义变更时是否可安全使用?
问题:PostgreSQL不可变函数接收表类型参数,表元数据变更后是否返回新结果?
结论
会识别表元数据的变更,并返回包含新列的结果
原因解释
PostgreSQL中,表类型本质是一种自动维护的复合类型。当你修改表playground.t_test的元数据(比如新增列)时,对应的复合类型playground.t_test会被PostgreSQL自动更新。
你的函数f_test接收的参数是这个复合类型,每次调用函数时,PostgreSQL会基于当前最新的复合类型结构来处理参数,将其转换为jsonb。即使函数标记为IMMUTABLE,这里的场景并不违反IMMUTABLE的语义——IMMUTABLE要求相同输入参数返回相同结果,但当表结构变更后,复合类型的定义已经改变,相当于参数的类型结构发生了变化,此时的输入已经不是“相同参数”了,所以函数会返回新的结果。
正确测试步骤
你之前的测试用例加入了current_timestamp,这本身就违反了IMMUTABLE函数的约束,PostgreSQL不会对这种明显不符合IMMUTABLE语义的函数进行结果缓存,导致每次调用都生成新时间戳,无法验证表结构变更的影响。正确的测试方法如下:
- 初始状态下,创建表和函数后,调用函数:
-- 插入测试数据并调用函数 INSERT INTO playground.t_test VALUES (1, 2); SELECT playground.f_test(t) FROM playground.t_test t; -- 结果:{"c1": 1, "c2": 2} - 修改表结构,新增列:
ALTER TABLE playground.t_test ADD COLUMN c3 TEXT; - 更新数据并再次调用函数:
即使不更新数据,原有的行也会返回包含UPDATE playground.t_test SET c3 = 'test'; SELECT playground.f_test(t) FROM playground.t_test t; -- 结果:{"c1": 1, "c2": 2, "c3": "test"}c3: null的结果,证明函数已经识别了表结构的变更。
补充说明
需要注意的是,如果函数是用PL/pgSQL编写的,且在函数内部硬编码了表的列名(比如手动拼接jsonb),那表结构变更后函数不会自动识别;但你的函数是直接调用to_jsonb(test),to_jsonb会根据当前复合类型的结构来生成json,所以能自动适配表结构的变化。
内容的提问来源于stack exchange,提问作者H0LL0
相关产品推荐
相关产品推荐

