用 PL/pgSQL 编写的函数通过执行 CREATE FUNCTION 命令定义给服务器。这样的命令通常看起来像这样,举个例子:
CREATE FUNCTION somefunc(integer, text) RETURNS integer
AS 'function body text'
LANGUAGE plpgsql;
从 CREATE FUNCTION 的角度来看,函数体只是一个字符串字面量。与使用普通的单引号语法相比,使用美元引用(参见 第 4.1.2.4 节)来编写函数体通常很有用。如果不使用美元引用,函数体中的任何单引号或反斜杠都必须通过加倍来转义。本章中的几乎所有示例都使用美元引用字面量作为它们的函数体。
PL/pgSQL 是一种块结构语言。函数体的完整文本必须是一个 块。块定义为:
[ <<label>> ] [ DECLAREdeclarations] BEGINstatementsEND [label];
块中的每个声明和每个语句都以分号结束。如上所示,出现在另一个块内的块在 END 之后必须有一个分号;然而,结束函数体的最终 END 不需要分号。
一个常见的错误是在 BEGIN 之后立即写一个分号。这是不正确的,并且会导致语法错误。
只有当你想用 EXIT 语句标识该块,或者限定块中声明的变量的名称时,才需要 label。如果在 END 之后给出了标签,它必须与块开头的标签匹配。
所有关键字都不区分大小写。标识符会被隐式转换为小写,除非被双引号括起来,这与普通 SQL 命令中的情况一样。
注释在 PL/pgSQL 代码中的工作方式与在普通 SQL 中相同。双破折号 (--) 启动一个注释,该注释一直延伸到行尾。一个 /* 启动一个块注释,该注释一直延伸到匹配的 */。块注释是嵌套的。
块的语句部分中的任何语句都可以是 子块。子块可用于逻辑分组或将变量限定在少数语句中。在子块中声明的变量会掩盖子块持续期间内任何同名但属于外部块的变量;但是,您仍然可以通过使用其块标签来限定名称来访问外部变量。例如:
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;
在任何 PL/pgSQL 函数的主体周围实际上有一个隐藏的“外部块”。这个块提供了函数参数(如果有)的声明,以及一些特殊变量,例如 FOUND(参见 第 41.5.5 节)。外部块用函数名标记,这意味着参数和特殊变量可以用函数名限定。
重要的是不要将 PL/pgSQL 中用于对语句进行分组的 BEGIN/END 与用于事务控制的同名 SQL 命令混淆。PL/pgSQL 的 BEGIN/END 仅用于分组;它们不会启动或结束事务。有关在 PL/pgSQL 中管理事务的信息,请参见 第 41.8 节。此外,包含 EXCEPTION 子句的块实际上构成了一个子事务,该子事务可以在不影响外部事务的情况下回滚。有关更多信息,请参见 第 41.6.8 节。