35.2. 开发 PL/pgSQL 的一些提示

PL/pgSQL 做开发的一个好方法是简单地使用你喜欢的文本编辑器创建你的函数,然后在另外一个控制台里, 用 psql 装载这些函数。如果你用这种方法, 那么用 CREATE OR REPLACE FUNCTION 写函数是个好主意。这样,你就可以重载文件以更新函数定义。比如:

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

在运行 psql 的时候,你可以用下面命令装载或者重载这样的函数定义文件

\i filename.sql

然后马上发出 SQL 命令测试该函数。

另外一个开发PL/pgSQL程序的好方法是用一种 GUI 的数据库访问工具,并且是实现了过程语言开发设施的那种。 这种工具中的一种就是 pgaccess,当然还有其他的。 这些工具通常提供了一些很有用的功能,比如逃逸单引号,令重建和调试函数更简单等。

35.2.1. 处理引号

PL/pgSQL 函数的代码都是在 CREATE FUNCTION 里以一个字串文本的方式声明的。 如果你用两边包围单引号的常规方式写字串文本,那么任何函数体内的单引号都必须写双份;类似的是反斜杠也必须双份。 双份引号非常乏味,在更复杂的场合下,代码可能会让人难以理解, 因为你很容易发现自己需要半打甚至更多相连的引号。 我们建议你用"美元符包围"的字串文本来写函数体。 (参阅 Section 4.1.2.2)。 使用美元符包围的时候,你从不需要对任何引号写双份, 只需要为每层引号包围嵌套选择一个不同的美元符号包围分隔符即可。 比如,你可能这么写 CREATE FUNCTION 命令

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_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 35-5 里那样,才需要这么干。比如:

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 里放单引号, 因为在使用前它会被重新引号包围。

另外一个方法是用反斜杠逃逸函数体里面的单引号,而不是写双份。 用这个方法,你会发现自己写了很多类似 \'\' 这样的东西, 而不是 ''''。有些人认为这样简单些,有些人却不这么看。