40.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,当然还有其它的。这些工具通常提供了一些很有用的功能, 比如逃逸单引号使得重建和调试函数更简单等。

40.11.1. 引号标记处理

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

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