支援的版本:目前版本 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4

41.12. 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,儘管還有其他工具存在。這些工具通常提供方便的功能,例如跳脫單引號,並使其更容易重新建立和偵錯函式。

41.12.1. 引號的處理 #

PL/pgSQL 函式的程式碼在 CREATE FUNCTION 中被指定為字串文字。如果您以普通方式使用周圍的單引號撰寫字串文字,則函式主體內的任何單引號都必須加倍;同樣,任何反斜線也必須加倍(假設使用跳脫字串語法)。加倍引號充其量是乏味的,而在更複雜的情況下,程式碼會變得難以理解,因為您很容易發現自己需要六個或更多相鄰的引號。建議您改為將函式主體撰寫為美元符號引號字串文字(請參閱第 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 個引號)。您可能只需要在編寫生成其他函式的函式時才需要這樣做,如範例 41.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 中,因為它在使用前會被重新引號。

41.12.2. 額外的編譯時和執行時檢查 #

為了幫助使用者在簡單但常見的問題造成損害之前找到它們,PL/pgSQL 提供了額外的 checks (檢查)。啟用後,根據配置,它們可用於在函式編譯期間發出 WARNING (警告) 或 ERROR (錯誤)。收到 WARNING 的函式可以執行而不會產生進一步的訊息,因此建議您在單獨的開發環境中進行測試。

建議在開發和/或測試環境中將 plpgsql.extra_warningsplpgsql.extra_errors 適當地設定為 "all"

這些額外的檢查是通過配置變數 plpgsql.extra_warnings (用於警告) 和 plpgsql.extra_errors (用於錯誤) 啟用的。兩者都可以設定為逗號分隔的檢查清單、"none" (無) 或 "all" (全部)。預設值為 "none"。目前,可用的檢查清單包括

shadowed_variables #

檢查宣告是否遮蔽了先前定義的變數。

strict_multi_assignment #

某些 PL/pgSQL 命令允許一次將值賦予多個變數,例如 SELECT INTO。通常,目標變數的數量和來源變數的數量應該匹配,儘管 PL/pgSQL 將使用 NULL 作為缺失值,並且忽略額外的變數。啟用此檢查將導致 PL/pgSQL 在目標變數的數量和來源變數的數量不同時拋出 WARNINGERROR

too_many_rows #

啟用此檢查將導致 PL/pgSQL 檢查給定的查詢在使用 INTO 子句時是否傳回多個資料列。由於 INTO 陳述式只會使用一個資料列,因此讓查詢傳回多個資料列通常是效率低下和/或不確定的,因此很可能是一個錯誤。

以下範例顯示了設定為 shadowed_variablesplpgsql.extra_warnings 的效果

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.extra_warnings 設定為 strict_multi_assignment 的效果

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
-----

(1 row)

提交更正

如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的地方,請使用此表格回報文件問題。