BEGIN ATOMIC 在 PostgreSQL SQL 函数/过程中意味着什么?

ARX*_*ARX 18 postgresql functions postgresql-14

在 PG 14 的文档中,在 参考资料CREATE FUNCTION部分中,手册指出函数的主体LANGUAGE SQL可以是单个语句:

RETURN expression
Run Code Online (Sandbox Code Playgroud)

或一个块:

BEGIN ATOMIC
statement;
statement;
...
statement;
END
Run Code Online (Sandbox Code Playgroud)

没有对该块的语义给出任何解释。这看起来类似于BEGIN ... END;PL/pgSQL 中的块,但似乎有些不同。

在 内 或 外 写一组语句有什么区别BEGIN ATOMIC ... END?什么时候需要使用这样的块?关键字是ATOMIC强制的吗?

Erw*_*ter 21

它是SQL 标准函数的新语法变体(在 Postgres 14 中)。
发行说明:

允许 SQL 语言函数和过程使用 SQL 标准函数体 (Peter Eisentraut)

以前仅支持字符串文字函数体。当使用 SQL 标准语法编写函数或过程时,主体会立即被解析并存储为解析树。这可以更好地跟踪函数依赖关系,并且可以带来安全优势。

传统的 Postgres 函数和过程将正文保存为要在执行时解析的文字字符串,通常使用美元引用。看:

新语法BEGIN ATOMIC ... END(强制ATOMIC!)不引用函数体,该函数体在创建时进行解析。它只是看起来类似于 PL/pgSQL 块,用BEGIN ... END. 两者非常不同。新的语法变体仅允许用于LANGUAGE sql. 事实上,该语言是在没有声明的情况下假定的。手册:

sql如果指定则默认为sql_body

您可以编写多个纯 SQL 语句,就像传统的字符串文字函数或过程体一样。但所有内容都是在函数创建时解析的。因此,传统字符串文字形式的“早期绑定”与“后期绑定”。这有许多副作用。手册中
对 SQL 标准语法有很好的解释:

这类似于将函数体的文本写为字符串常量(参见上面的定义),但有一些区别: 这种形式仅适用于LANGUAGE SQL,字符串常量形式适用于所有语言。这种形式在函数定义时解析,字符串常量形式在执行时解析;因此,这种形式不能支持多态参数类型和其他在函数定义时无法解析的构造。这种形式跟踪函数和函数体中使用的对象之间的依赖关系,因此DROP ... CASCADE可以正常工作,而使用字符串文字的形式可能会留下悬空函数。最后,这种形式与SQL标准和其他SQL实现更加兼容。

“SQL 标准”形式也可以是“内联”的。看:

新的语法变体通常更适合简单的 SQL 函数。

代码示例

带(且不带关键字)的单个表达式的缩写形式RETURNATOMIC

CREATE OR REPLACE FUNCTION asterisk(n int)
  RETURNS text
  LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
RETURN repeat('*', n);
Run Code Online (Sandbox Code Playgroud)

完整形式:

CREATE OR REPLACE FUNCTION asterisks(n int)
  RETURNS SETOF text
  LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
BEGIN ATOMIC
SELECT repeat('*', g) FROM generate_series (1, n) g;
END;
Run Code Online (Sandbox Code Playgroud)

作为参考,与具有字符串文字主体的传统 SQL 函数相同:

CREATE OR REPLACE FUNCTION asterisks(n int)
  RETURNS SETOF text
  LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE AS
$func$
SELECT repeat('*', g) FROM generate_series (1, n) g;
$func$;
Run Code Online (Sandbox Code Playgroud)

或者作为 PL/pgSQL 函数:

CREATE OR REPLACE FUNCTION asterisks(n int)
  RETURNS SETOF text
  LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE AS
$func$
BEGIN
   RETURN QUERY
   SELECT repeat('*', g) FROM generate_series (1, n) g;
END
$func$;
Run Code Online (Sandbox Code Playgroud)

  • @Bergi:除其他外,这就是它的意思。函数体在创建时被解析,原始函数体字符串甚至没有保存(意味着您丢失了函数体中的格式和注释!) - 与将给定函数体保存为字符串的传统“CREATE FUNCTION”语法相反调用时解析的文字等。早期绑定与后期绑定,各有其优点。 (5认同)
  • “*此形式跟踪函数体中使用的函数和对象之间的依赖关系*” - 这是否意味着它也跟踪重命名?并且不再容易受到“search_path”的影响,[如默认表达式](/sf/ask/1754762831/)? (3认同)