42.2. PL/pgSQL 的结构

通过执行CREATE FUNCTION命令可以将用 PL/pgSQL 编写的函数定义到服务器。这样的命令通常看起来像

CREATE FUNCTION somefunc(integer, text) RETURNS integer
AS 'function body text'
LANGUAGE plpgsql;

CREATE FUNCTION而言,函数主体只是一个字符串 Literals。使用美元引号(请参见Section 4.1.2.4)来编写函数主体,而不是使用普通的单引号语法通常会很有帮助。如果不使用美元引号,则必须通过将它们加倍来对函数体内的任何单引号或反斜杠进行转义。在本章中,几乎所有示例的功能体均使用加引号的 Literals。

PL/pgSQL 是一种块结构语言。函数体的完整文本必须为* block *。块定义为:

[ <<label>> ]
[ DECLARE
    declarations ]
BEGIN
    statements
END [ label ];

块中的每个声明和每个语句均以分号结尾。如上所示,出现在另一个块中的一个块必须在END后加分号。但是,最终得出函数体的END不需要分号。

Tip

一个常见的错误是在BEGIN之后立即写一个分号。这是不正确的,将导致语法错误。

仅当您要标识要在EXIT语句中使用的块或限定块中声明的变量名称时,才需要* label *。如果在END之后给出标签,则它必须与块开头的标签匹配。

所有关键字都不区分大小写。标识符被隐式转换为小写,除非使用双引号,就像在普通 SQL 命令中一样。

在 PL/pgSQL 代码中,Comments 的工作方式与在普通 SQL 中相同。双破折号(--)开始 Comments,该 Comments 延伸到该行的末尾。 /*开始一个块 Comments,该 Comments 扩展到*/的匹配出现。阻止 Comments 嵌套。

块的语句部分中的任何语句都可以是* subblock *。子块可用于逻辑分组或将变量本地化为一小段语句。在子块中声明的变量会在子块的持续时间内屏蔽外部块的任何类似名称的变量;但是如果您使用其块的标签限定它们的名称,则仍然可以访问外部变量。例如:

CREATE FUNCTION somefunc() RETURNS integer AS $$
<< outerblock >>
DECLARE
    quantity integer := 30;
BEGIN
    RAISE NOTICE 'Quantity here is %', quantity;  -- Prints 30
    quantity := 50;
    --
    -- Create a subblock
    --
    DECLARE
        quantity integer := 80;
    BEGIN
        RAISE NOTICE 'Quantity here is %', quantity;  -- Prints 80
        RAISE NOTICE 'Outer quantity here is %', outerblock.quantity;  -- Prints 50
    END;

    RAISE NOTICE 'Quantity here is %', quantity;  -- Prints 50

    RETURN quantity;
END;
$$ LANGUAGE plpgsql;

Note

实际上,任何 PL/pgSQL 函数的主体周围都有一个隐藏的“外部块”。该块提供了函数参数的声明(如果有的话),以及一些特殊变量,例如FOUND(请参见Section 42.5.5)。外部块标有函数名称,这意味着参数和特殊变量可以用函数名称限定。

重要的是不要混淆使用BEGIN/END将 PL/pgSQL 中的语句与类似名称的用于事务控制的 SQL 命令进行分组。 PL/pgSQL 的BEGIN/END仅用于分组;他们不开始或结束 Transaction。函数和触发器过程始终在由外部查询构建的事务内执行-它们无法启动或提交该事务,因为将没有上下文可在其中执行。但是,包含EXCEPTION子句的块有效地形成了一个子事务,该子事务可以在不影响外部 Transaction 的情况下回滚。有关更多信息,请参见Section 42.6.6