为什么PostgreSQL在从稳定函数调用volatile函数时不会发出警告?

时间:2013-09-20 00:18:22

标签: postgresql stored-procedures volatile

例如:

CREATE TABLE x (
    val double);

CREATE FUNCTION g() RETURNS boolean AS $$
    INSERT INTO x SELECT rand() RETURNING val>0.5;
$$ LANGUAGE SQL VOLATILE;

CREATE FUNCTION f() RETURNS boolean AS $$
    SELECT g();         -- this is where the stability-violation happens
$$ LANGUAGE SQL STABLE; -- this is a lie

根据文档,f()也应标记为VOLATILE,因为调用f()会产生副作用。 PostgreSQL没有给出警告(或者更好的是,一个错误),这让我相信必须有一些理由为什么这个"显而易见的"允许存在错误。

1 个答案:

答案 0 :(得分:2)

这是一个非常有趣的问题,我建议您在PostgreSQL电子邮件列表中使用它。

简短的回答是,这些都是由他们所做的,而不是他们所称的功能强制执行的。

这可以让你做一些相当有趣的事情。例如,假设我想要一个每个查询只能创建一个随机数的值:

create function rand_im() returns double precision language sql immutable as 
$$ select random(); $$;

现在我有一个不可变的随机数函数,它可以优化为在形成查询计划之前发生的单个调用,因此可用于确定索引是否有用:

chris=# explain analyse select * from profile_matches where id > (4 * rand_im());
                                                 QUERY PLAN                     

--------------------------------------------------------------------------------
-----------------------------
 Seq Scan on profile_matches  (cost=0.00..39.10 rows=647 width=12) (actual time=
0.009..0.010 rows=1 loops=1)
   Filter: ((id)::double precision > 3.24490546248853::double precision)
 Total runtime: 0.022 ms
(3 rows)

所以这里我们有一个“不可变”,它调用一个明显易变的函数,这实际上很有用,因为它允许我们创建一个将被展平的函数,并且可以为查询提供一个值。

现在,根据其他链接,我真的不知道调用volatile函数的稳定函数会发生什么。据我所知,这只是一个优化的事情,保护是非常小的,但我不保证总是允许数据库副作用。

此外,一个简单的考虑因素是函数是planner-opaque,并且不可能在所有过程语言中阻止这种事情。考虑你可以有一个Java函数,可以标记为不可变但可以运行查询(这可能不是一件好事)。所以这似乎是一个明显的错误,但它实际上是一个潜在有用的错误。