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 裡放單引號, 因為在使用前它會被重新引號包圍。

另外一個方法是用反斜槓逃逸函數體裡面的單引號,而不是寫雙份。 用這個方法,您會發現自己寫了很多類似 \'\' 這樣的東西, 而不是 ''''。有些人認為這樣簡單些,有些人卻不這麼看。