在 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,儘管還有其他工具存在。這些工具通常提供方便的功能,例如跳脫單引號,並使其更容易重新建立和偵錯函式。
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$
,依此類推。
下表顯示了在沒有美元符號引號的情況下撰寫引號時必須做的事情。在將美元符號引號之前的程式碼轉換為更容易理解的內容時,它可能會很有用。
例如,要開始和結束函式主體
CREATE FUNCTION foo() RETURNS integer AS ' .... ' LANGUAGE plpgsql;
在單引號函式主體中的任何位置,引號必須成對出現。
對於函式主體內的字串文字,例如
a_output := ''Blah''; SELECT * FROM users WHERE f_name=''foobar'';
在美元符號引號方法中,您只需撰寫
a_output := 'Blah'; SELECT * FROM users WHERE f_name='foobar';
無論哪種情況,這正是 PL/pgSQL 剖析器會看到的。
當您需要在函式主體內的字串常數中使用單引號時,例如
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$$
請注意,此字串周圍的任何美元符號引號分隔符不僅僅是 $$
。
當函式主體內字串中的單引號與該字串常數的結尾相鄰時,例如
a_output := a_output || '' AND name LIKE ''''foobar''''''
然後附加到 a_output
的值將是:AND name LIKE 'foobar'
。
在美元符號引號方法中,這變成了
a_output := a_output || $$ AND name LIKE 'foobar'$$
當您想要在字串常數中使用兩個單引號 (這佔用了 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
中,因為它在使用前會被重新引號。
為了幫助使用者在簡單但常見的問題造成損害之前找到它們,PL/pgSQL 提供了額外的 checks
(檢查)。啟用後,根據配置,它們可用於在函式編譯期間發出 WARNING
(警告) 或 ERROR
(錯誤)。收到 WARNING
的函式可以執行而不會產生進一步的訊息,因此建議您在單獨的開發環境中進行測試。
建議在開發和/或測試環境中將 plpgsql.extra_warnings
或 plpgsql.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 在目標變數的數量和來源變數的數量不同時拋出 WARNING
或 ERROR
。
too_many_rows
#啟用此檢查將導致 PL/pgSQL 檢查給定的查詢在使用 INTO
子句時是否傳回多個資料列。由於 INTO
陳述式只會使用一個資料列,因此讓查詢傳回多個資料列通常是效率低下和/或不確定的,因此很可能是一個錯誤。
以下範例顯示了設定為 shadowed_variables
的 plpgsql.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)
如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的地方,請使用此表格回報文件問題。