PostgreSQL PL/pgSQL開(kāi)發(fā)提示

2021-09-03 17:38 更新
42.12.1. 處理引號(hào)
42.12.2. 額外的編譯時(shí)和運(yùn)行時(shí)檢查

PL/pgSQL中進(jìn)行開(kāi)發(fā)的一種好方法是使用你自己選擇的文本編輯器來(lái)創(chuàng)建函數(shù),并且在另一個(gè)窗口中使用psql來(lái)載入并且測(cè)試那些函數(shù)。如果你正在這樣做,使用CREATE OR REPLACE FUNCTION來(lái)編寫(xiě)函數(shù)是一個(gè)好主意。用那種方式你只需要重載該文件來(lái)更新函數(shù)的定義。例如:

CREATE OR REPLACE FUNCTION testfunc(integer) RETURNS integer AS $$
          ....
$$ LANGUAGE plpgsql;

在運(yùn)行psql期間,你可以用下面的命令載入或者重載這樣一個(gè)函數(shù)定義文件:

\i filename.sql

并且接著立即發(fā)出 SQL 命令來(lái)測(cè)試該函數(shù)。

另一種在PL/pgSQL中開(kāi)發(fā)的方式是用一個(gè) GUI 數(shù)據(jù)庫(kù)訪問(wèn)工具,它能方便對(duì)過(guò)程語(yǔ)言的開(kāi)發(fā)。這種工具的一個(gè)例子是pgAdmin。這些工具通常提供方便的特性,例如轉(zhuǎn)義單引號(hào)以及便于重新創(chuàng)建和調(diào)試函數(shù)。

42.12.1. 處理引號(hào)

一個(gè)PL/pgSQL函數(shù)的代碼在一個(gè)CREATE FUNCTION中被指定為一個(gè)字符串。如果你用通常的方式把該字符串寫(xiě)在單引號(hào)中間,那么該函數(shù)體中的任何單引號(hào)都必須被雙寫(xiě);同樣任何反斜線也必須被雙寫(xiě)(假定使用了轉(zhuǎn)義字符串語(yǔ)法)。雙寫(xiě)引號(hào)最多有點(diǎn)冗長(zhǎng),并且在更復(fù)雜的情況中代碼會(huì)變得完全無(wú)法理解,因?yàn)槟愫苋菀装l(fā)現(xiàn)你需要半打或者更多相鄰的引號(hào)。我們推薦你轉(zhuǎn)而把函數(shù)體寫(xiě)成一個(gè) 美元引用的字符串(見(jiàn)第 4.1.2.4 節(jié))。在美元引用方法中,你從不需要雙寫(xiě)任何引號(hào)。但是要注意為你需要的每一層嵌套選擇一個(gè)不同的美元引用定界符。例如,你可能把CREATE FUNCTION命令寫(xiě)成:

CREATE OR REPLACE FUNCTION testfunc(integer) RETURNS integer AS $PROC$ .... $PROC$ LANGUAGE plpgsql;

在這里面,你可以在 SQL 命令中為簡(jiǎn)單字符串使用引號(hào)并且用$$來(lái)界定被你組裝成字符串的 SQL 命令片段。如果你需要引用包括$$的文本,你可以使用$Q$等等。

下列圖表展示了在寫(xiě)沒(méi)有美元引用的引號(hào)時(shí)需要做什么。在將之前用美元引用的代碼翻譯成更容易理解的代碼時(shí),它們會(huì)有所幫助。

1 個(gè)引號(hào)

用來(lái)開(kāi)始和結(jié)束函數(shù)體,例如:

CREATE FUNCTION foo() RETURNS integer AS '
          ....
' LANGUAGE plpgsql;

在一個(gè)單引號(hào)引用的函數(shù)體中的任何位置,引號(hào)必須成對(duì)出現(xiàn)。

2 個(gè)引號(hào)

用于函數(shù)體內(nèi)的字符串,例如:

a_output := ''Blah'';
SELECT * FROM users WHERE f_name=''foobar'';

在美元引用方法中,你只需要寫(xiě):

a_output := 'Blah';
SELECT * FROM users WHERE f_name='foobar';

這恰好就是PL/pgSQL在兩種情況中會(huì)看到的。

4 個(gè)引號(hào)

當(dāng)你在函數(shù)內(nèi)的一個(gè)字符串常量中需要一個(gè)單引號(hào)時(shí),例如:

a_output := a_output || '' AND name LIKE ''''foobar'''' AND xyz''

實(shí)際會(huì)被追加到a_output的值將是: AND name LIKE 'foobar' AND xyz。

在美元引用方法中,你可以寫(xiě):

a_output := a_output || $$ AND name LIKE 'foobar' AND xyz$$

要小心在這周?chē)娜魏蚊涝枚ń绶恢皇?code class="literal">$$。

6 個(gè)引號(hào)

當(dāng)在函數(shù)體內(nèi)的一個(gè)字符串中的一個(gè)單引號(hào)與該字符串常量末尾相鄰,例如:

a_output := a_output || '' AND name LIKE ''''foobar''''''

被追加到a_output的值則將是: AND name LIKE 'foobar'。

在美元引用方法中,這會(huì)變成:

a_output := a_output || $$ AND name LIKE 'foobar'$$

10 個(gè)引號(hào)

當(dāng)你想在一個(gè)字符串常量(占 8 個(gè)引號(hào))中有兩個(gè)單引號(hào)時(shí)并且這會(huì)挨著該字符串常量的末尾(另外 2 個(gè))。如果你正在寫(xiě)一個(gè)產(chǎn)生其他函數(shù)的函數(shù)(如例 42.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;

在美元引用方法中,這會(huì)變成:

a_output := a_output || $$ if v_$$ || referrer_keys.kind || $$ like '$$
    || referrer_keys.key_string || $$'
    then return '$$  || referrer_keys.referrer_type
    || $$'; end if;$$;

這里我們假定我們只需要把單引號(hào)放在a_output中,因?yàn)樵谑褂们八鼘⒈辉僖谩?/p>

42.12.2. 額外的編譯時(shí)和運(yùn)行時(shí)檢查

為了輔助用戶在一些簡(jiǎn)單但常見(jiàn)的問(wèn)題產(chǎn)生危害之前找到它們, PL/pgSQL提供了額外的檢查。當(dāng)被啟用時(shí), 根據(jù)配置,它們可以在一個(gè)函數(shù)的編譯期間被用來(lái)發(fā)出 WARNING或者ERROR。一個(gè)已經(jīng)收到了 WARNING的函數(shù)可以被繼續(xù)執(zhí)行而不會(huì)產(chǎn)生進(jìn)一步的消息, 因此建議你在一個(gè)單獨(dú)的開(kāi)發(fā)環(huán)境中進(jìn)行測(cè)試。

根據(jù)需要設(shè)置 plpgsql.extra_warningsplpgsql.extra_errors,適當(dāng)情況下,在開(kāi)發(fā)和/或測(cè)試環(huán)境中可以設(shè)置為 "all"。

這些附加檢查通過(guò)配置變量啟用, plpgsql.extra_warnings用于警告,plpgsql.extra_errors 用于錯(cuò)誤。 兩者都可以設(shè)置為逗號(hào)分隔的檢查列表,"none""all"。 默認(rèn)值為"none"。當(dāng)前可用的檢查列表包括:

shadowed_variables

檢查聲明是否遮蓋了以前定義的變量

strict_multi_assignment

某些PL/PgSQL命令允許一次將值分配給多個(gè)變量,例如SELECT INTO。 通常,目標(biāo)變量的數(shù)量和源變量的數(shù)量應(yīng)匹配,盡管PL/PgSQL將使用NULL來(lái)處理缺失的值和被忽略的額外變量。 啟用此檢查將導(dǎo)致 PL/PgSQL在目標(biāo)變量數(shù)和源變量數(shù)不同時(shí)引發(fā) WARNINGERROR。

too_many_rows

Enabling this check will cause PL/PgSQL to check if a given query returns more than one row when an INTO clause is used. As an INTO statement will only ever use one row, having a query return multiple rows is generally either inefficient and/or nondeterministic and therefore is likely an error. 啟用此檢查將導(dǎo)致PL/PgSQL檢查在使用INTO子句時(shí)給定查詢是否返回多行。 由于INTO語(yǔ)句只會(huì)使用一行,讓查詢返回多行通常會(huì)效率低下和/或不確定性,因此很可能會(huì)出現(xiàn)錯(cuò)誤。

下面的示例顯示了plpgsql.extra_warnings 設(shè)置為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 設(shè)置為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)


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)