42.11. PL/pgSQL 开发技巧

在 PL/pgSQL 中进行开发的一种好方法是使用您选择的文本编辑器来创建函数,而在另一个窗口中,使用 psql 来加载和测试这些函数。如果以这种方式进行操作,则最好使用CREATE OR REPLACE FUNCTION编写函数。这样,您只需重新加载文件即可更新函数定义。例如:

CREATE OR REPLACE FUNCTION testfunc(integer) RETURNS integer AS $$
          ....
$$ LANGUAGE plpgsql;

运行 psql 时,可以使用以下命令加载或重新加载这样的函数定义文件:

\i filename.sql

然后立即发出 SQL 命令以测试该功能。

使用 PL/pgSQL 进行开发的另一种好方法是使用 GUI 数据库访问工具,该工具有助于以过程语言进行开发。这种工具的一个示例是 pgAdmin,尽管还有其他示例。这些工具通常提供便利的功能,例如转义单引号并使其更易于重新创建和调试功能。

42 .11.1. 引号的处理

PL/pgSQL 函数的代码在CREATE FUNCTION中指定为字符串 Literals。如果您以普通的方式用双引号引起来写字符串 Literals,那么函数体内的任何单引号都必须加倍;同样,任何反斜杠都必须加倍(假定使用了转义字符串语法)。引号加倍充其量是乏味的,在更复杂的情况下,代码可能变得彻头彻尾难以理解,因为您可以轻松地发现自己需要六个或更多相邻的引号。建议您改用“美元引号”字符串 Literals 形式写函数体(请参见Section 4.1.2.4)。在美元报价方法中,您永远不要将任何引号加倍,而要注意为所需的每个嵌套级别选择不同的美元报价分隔符。例如,您可以将CREATE FUNCTION命令编写为:

CREATE OR REPLACE FUNCTION testfunc(integer) RETURNS integer AS $PROC$
          ....
$PROC$ LANGUAGE plpgsql;

在其中,您可以在 SQL 命令中的简单 Literals 字符串上使用引号,并在$$处定界以字符串形式组装的 SQL 命令的片段。如果需要引用包含$$的文本,则可以使用$Q$,依此类推。

下图显示了在不带美元引号的情况下编写引号时必须执行的操作。将美元前的报价代码转换为更易于理解的代码时,这可能会很有用。

  • 1 引号

    • 要开始和结束功能主体,例如:
CREATE FUNCTION foo() RETURNS integer AS '
          ....
' LANGUAGE plpgsql;

在单引号函数体内的任何地方,引号必须成对出现。

  • 2 引号

    • 对于函数体内的字符串 Literals,例如:
a_output := ''Blah'';
SELECT * FROM users WHERE f_name=''foobar'';

在美元报价方法中,您只需编写:

a_output := 'Blah';
SELECT * FROM users WHERE f_name='foobar';

无论哪种情况,这都是 PL/pgSQL 解析器所看到的。

  • 4 引号

    • 例如,当您需要在函数体内的字符串常量中使用单引号引起来时,例如:
a_output := a_output || '' AND name LIKE ''''foobar'''' AND xyz''

实际附加到a_output的值将是:AND name LIKE 'foobar' AND xyz

在美元报价方法中,您将编写:

a_output := a_output || $$ AND name LIKE 'foobar' AND xyz$$

请注意,围绕此的任何美元引号分隔符都不仅是$$

  • 6 引号

    • 当函数体内的字符串中的单引号与该字符串常量的末尾相邻时,例如:
a_output := a_output || '' AND name LIKE ''''foobar''''''

附加到a_output的值将是:AND name LIKE 'foobar'

在美元报价方法中,这变为:

a_output := a_output || $$ AND name LIKE 'foobar'$$
  • 10 引号

    • 如果要在字符串常量中使用两个单引号(占 8 个引号),并且该位置与该字符串常量的末尾相邻(另外 2 个)。如编写Example 42.10一样,您可能只需要编写生成其他函数的函数。例如:
a_output := a_output || '' if v_'' ||
    referrer_keys.kind || '' like ''''''''''
    || referrer_keys.key_string || ''''''''''
    then return ''''''  || referrer_keys.referrer_type
    || ''''''; end if;'';

a_output的值为:

if v_... like ''...'' then return ''...''; end if;

在美元报价方法中,这变为:

a_output := a_output || $$ if v_$$ || referrer_keys.kind || $$ like '$$
    || referrer_keys.key_string || $$'
    then return '$$  || referrer_keys.referrer_type
    || $$'; end if;$$;

我们假设我们只需要在a_output内加上单引号,因为在使用前将对其重新报价。

42 .11.2. 其他编译时检查

为了帮助用户在造成危害之前找到简单但常见的问题实例,PL/pgSQL 提供了额外的* checks *。启用后,根据配置,它们可用于在函数编译期间发出WARNINGERROR。接收到WARNING的函数可以在不产生进一步消息的情况下执行,因此建议您在单独的开发环境中进行测试。

这些其他检查通过配置变量plpgsql.extra_warnings发出警告,并通过plpgsql.extra_errors出错来启用。两者都可以设置为以逗号分隔的支票清单"none""all"。默认值为"none"。当前,可用支票列表仅包括一项:

  • shadowed_variables

    • 检查声明是否覆盖了先前定义的变量。

以下示例显示了plpgsql.extra_warnings设置为shadowed_variables的效果:

SET plpgsql.extra_warnings TO 'shadowed_variables';

CREATE FUNCTION foo(f1 int) RETURNS int AS $$
DECLARE
f1 int;
BEGIN
RETURN f1;
END
$$ LANGUAGE plpgsql;
WARNING:  variable "f1" shadows a previously defined variable
LINE 3: f1 int;
        ^
CREATE FUNCTION