标记为 STABLE 的 PostgreSQL 函数是否允许获取锁?

Is a PostgreSQL function marked as STABLE allowed to acquire locks?

PostgreSQL 文档关于将函数标记为 STABLE 的主题是这样说的:

STABLE indicates that the function cannot modify the database, and that within a single table scan it will consistently return the same result for the same argument values, but that its result could change across SQL statements. This is the appropriate selection for functions whose results depend on database lookups, parameter variables (such as the current time zone), etc. (It is inappropriate for AFTER triggers that wish to query rows modified by the current command.) Also note that the current_timestamp family of functions qualify as stable, since their values do not change within a transaction.

我有一个函数(称之为 F)需要在开始之前锁定 table IN EXCLUSIVE MODE,以保证在函数调用期间不会插入新行并结束交易。 F 不对数据库进行任何直接更改。对于计划者来说,在同一事务中使用相同的参数省略对 F 的多次调用是安全的,只要它被调用一次即可。

例如,让我们使用

CREATE FUNCTION F(x INTEGER) RETURNS INTEGER AS $$
BEGIN
    LOCK TABLE foobar IN EXCLUSIVE MODE;
    RETURN (SELECT COUNT(*) FROM foobar WHERE id = x);
END;
$$ LANGUAGE 'plpgsql';

我的问题是,获取锁是否会取消函数被标记的资格 STABLE?也就是说,在这种情况下是否考虑获取锁 "modifying the database"?

编辑添加:使用咨询锁怎么样?这会改变答案吗?

好吧,这是一个简单的答案。我试过了,PG肯定不爽

ERROR:  LOCK TABLE is not allowed in a non-volatile function
CONTEXT:  SQL statement "LOCK TABLE foobar IN EXCLUSIVE MODE"

所以答案是,是的,使用 LOCK TABLE 肯定会取消函数被标记为 STABLE 的资格。

但是,使用建议锁不会(至少,我尝试时没有收到错误)。

正如您可以轻松测试的那样,这是行不通的。你会得到这个错误:

ERROR:  LOCK TABLE is not allowed in a non-volatile function

但这没问题。如果您希望您的函数看到 table 的 stable 快照,只需使用

开始事务
START TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY;

那么table不会为你改变。