# 43.12.在PL/pgSQL中开发的技巧

43.12.1. 引号的处理

43.12.2. 额外的编译时和运行时检查

在PL/pgSQL中开发的一个好方法是使用您选择的文本编辑器创建函数,并在另一个窗口中使用psql加载和测试这些函数。如果您是这样做的,那么使用创建或替换函数。这样,您只需重新加载文件即可更新函数定义。例如:

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

在运行psql时,您可以通过以下方式加载或重新加载此类函数定义文件:

\i filename.sql

然后立即发出SQL命令来测试函数。

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

# 43.12.1.引号的处理

PL/pgSQL函数的代码在中指定创建函数作为字符串文本。如果你用普通的方式用单引号写字符串文字,那么函数体中的任何单引号都必须加倍;同样,任何反斜杠都必须加倍(假设使用了转义字符串语法)。双引号充其量是乏味的,在更复杂的情况下,代码可能会变得完全不可理解,因为您很容易发现自己需要六个或更多相邻的引号。建议您将函数体编写为“美元报价”字符串文字(请参见第4.1.2.4节).在美元报价方法中,你永远不会将任何引号加倍,而是要注意为你需要的每一层嵌套选择不同的美元报价分隔符。例如,您可以编写创建函数命令为:

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

在此范围内,您可以在SQL命令和$$将正在组装为字符串的SQL命令片段分隔开来。如果你需要引用包含$$,你可以用$Q$等等

下表显示了在没有美元报价的情况下写引号时必须做的事情。在将美元之前的报价代码翻译成更容易理解的代码时,它可能很有用。

1引号

要开始和结束函数体,例如:

CREATE FUNCTION foo() RETURNS integer AS '
          ....
' LANGUAGE plpgsql;

在单个带引号的函数体中的任意位置,使用引号必须成对出现。

2个引号

对于函数体中的字符串文字,例如:

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_输出将是:名字像“foobar”和xyz.

在美元报价法中,你会写道:

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

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

6个引号

当函数体中字符串中的单个引号与该字符串常量的结尾相邻时,例如:

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

附加到的值a_输出那就是:名字叫“foobar”.

在美元报价法中,这变成:

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

10个引号

当你想在一个字符串常量中有两个单引号(占8个引号),而这个单引号与该字符串常量的末尾相邻(另外两个)。您可能只需要在编写生成其他函数的函数时使用它,如例43.10.例如:

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

价值a_输出那就是:

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_输出,因为它在使用前会被重新引用。

# 43.12.2.额外的编译时和运行时检查

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

背景plpgsql。额外警告plpgsql。额外错误,视情况而定“全部”在开发和/或测试环境中受到鼓励。

这些附加检查通过配置变量启用plpgsql。额外警告警告和plpgsql。额外错误因为错误。两者都可以设置为逗号分隔的检查列表,“没有”“全部”.默认值为“没有”.目前可用的检查清单包括:

阴影_变量

检查声明是否隐藏了以前定义的变量。

严格的多重分配

一些PL/PgSQL命令允许一次为多个变量赋值,例如选择进入。通常,目标变量的数量和源变量的数量应该匹配,尽管PL/PgSQL将使用无效的对于缺少的值和额外的变量将被忽略。启用此检查将导致PL/PgSQL抛出警告错误只要目标变量的数量和源变量的数量不同。

太多行了

启用此检查将导致PL/PgSQL检查给定查询在进入使用子句。作为一个进入语句将只使用一行,让查询返回多行通常是低效的和/或不确定的,因此可能是错误的。

下面的示例显示了plpgsql。额外警告开始阴影_变量:

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

下面的示例显示了设置的效果plpgsql。额外警告严格的多重分配:

SET plpgsql.extra_warnings TO 'strict_multi_assignment';

CREATE OR REPLACE FUNCTION public.foo()
 RETURNS void
 LANGUAGE plpgsql
AS $$
DECLARE
  x int;
  y int;
BEGIN
  SELECT 1 INTO x, y;
  SELECT 1, 2 INTO x, y;
  SELECT 1, 2, 3 INTO x, y;
END;
$$;

SELECT foo();
WARNING:  number of source and target fields in assignment does not match
DETAIL:  strict_multi_assignment check of extra_warnings is active.
HINT:  Make sure the query returns the exact list of columns.
WARNING:  number of source and target fields in assignment does not match
DETAIL:  strict_multi_assignment check of extra_warnings is active.
HINT:  Make sure the query returns the exact list of columns.

 foo