2025年9月25日: PostgreSQL 18 釋出!
支援版本: 當前 (18) / 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 命令來測試該函式。

使用支援過程語言開發的 GUI 資料庫訪問工具是開發 PL/pgSQL 的另一種好方法。pgAdmin 就是這類工具的一個例子,儘管還有其他工具。這些工具通常提供方便的功能,例如轉義單引號,以及更輕鬆地重新建立和除錯函式。

41.12.1. 引號的處理 #

PL/pgSQL 函式的程式碼在 CREATE FUNCTION 中被指定為字串字面量。如果您以普通方式編寫帶周圍單引號的字串字面量,那麼函式體內的任何單引號都必須加倍;同樣,任何反斜槓都必須加倍(假設使用了跳脫字元串語法)。加倍引號至少是乏味的,在更復雜的情況下,程式碼會變得難以理解,因為您很容易發現需要半打或更多的相鄰引號。建議您改用“美元定界字串”(dollar-quoted)字面量來編寫函式體(參見 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 提供了額外的檢查。啟用後,根據配置,它們可以用於在函式編譯期間發出 WARNINGERROR。收到 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 語句只會使用一行,因此查詢返回多行通常效率低下和/或不確定,因此很可能是一個錯誤。

以下示例顯示了將 plpgsql.extra_warnings 設定為 shadowed_variables 的效果:

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)

提交更正

如果您在文件中看到任何不正確的內容、與您在使用特定功能時的經驗不符或需要進一步說明的內容,請使用此表單來報告文件問題。