postgresql 调用VOLATILE函数会破坏SELECT语句的原子性

shyt4zoc  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(1)|浏览(110)

Given(PostgreSQL 15.3):

create table test (
    test_id int2,
    test_val int4,
    primary key (test_id)
);

字符串
如果这两个事务在read committed隔离级别并行运行:

-- Transaction 1
insert into test (select 1, 1 from pg_sleep(2));
-- Transaction 2
select coalesce(
    (select test_val from test where test_id = 1),
    (select null::int4 from pg_sleep(5)),
    (select test_val from test where test_id = 1)
);

的数据
第二个事务返回null,因为它是一个单独的语句。
但是,如果第二个事务替换为:

create function select_testval
    (id int2) returns int4
    language sql strict volatile -- stable function will work as previous version
return (select test_val from test where test_id = id);

-- Transaction 2.1
select coalesce(
    (select test_val from test where test_id = 1),
    (select null::int4 from pg_sleep(5)),
    select_testval(1::int2)
);


它返回1,作为一系列两个语句,每个语句看到不同的数据快照。
我的问题是
1.函数调用引入一个单独的语句来查看一个较新的快照,这是一个正确的行为吗?如果是,在哪里记录?
1.显然,在这种情况下,stable函数被内联,因此仍然是一条语句。在某些情况下,volatile函数调用是否也可以内联,从而改变并发语义?如果是,如何控制内联?
编辑1.根据评论的反馈,编辑了帖子,以找出造成混乱的实际问题。最初的问题相当琐碎。
P.S.对于上下文,我在试图找到一个惯用的纯SQL解决方案来解决具有唯一约束问题(12)的并发插入时发现了这一点,而不是求助于plpgsql

67up9zun

67up9zun1#

好吧,看来我真的忽略了标准文档:
STABLEIMMUTABLE函数使用在调用查询开始时建立的快照,而VOLATILE函数在它们执行的每个查询开始时获取新的快照。
38.7. Function Volatility Categories
此行为与内联无关。
值得注意的是,volatile函数获得的快照符合事务隔离级别。因此,当隔离度为repeatable read时,该函数不会看到来自其他事务的任何新数据。

相关问题