要使用 PL/Perl 語言建立函數,請使用標準的 CREATE FUNCTION 語法
CREATE FUNCTIONfuncname
(argument-types
) RETURNSreturn-type
-- function attributes can go here AS $$ # PL/Perl function body goes here $$ LANGUAGE plperl;
函數主體是一般的 Perl 程式碼。事實上,PL/Perl 膠水程式碼會將它包裝在 Perl 子程式中。PL/Perl 函數會在純量內容中呼叫,因此它無法傳回清單。您可以透過傳回參考來傳回非純量值(陣列、記錄和集合),如下所述。
在 PL/Perl 程序中,Perl 程式碼的任何傳回值都會被忽略。
PL/Perl 也支援使用 DO 陳述式呼叫的匿名程式碼區塊
DO $$ # PL/Perl code $$ LANGUAGE plperl;
匿名程式碼區塊不接收任何引數,而且它可能傳回的任何值都會被丟棄。除此之外,它的行為就像函數一樣。
在 Perl 中使用具名的巢狀子程式是很危險的,尤其是在它們參照封閉範圍中的詞法變數時。由於 PL/Perl 函數包裝在子程式中,因此您在其中放置的任何具名子程式都會是巢狀的。一般來說,建立匿名子程式並透過程式碼參考呼叫它們會安全得多。如需更多資訊,請參閱 perldiag man page 中 Variable "%s" will not stay shared
和 Variable "%s" is not available
的項目,或在網際網路上搜尋 “perl nested named subroutine”。
CREATE FUNCTION
命令的語法要求將函數主體寫為字串常數。通常使用美元符號引號 (參見第 4.1.2.4 節) 作為字串常數是最方便的。如果您選擇使用逸出字串語法 E''
,您必須將函數主體中使用的任何單引號 ('
) 和反斜線 (\
) 加倍 (參見第 4.1.2.1 節)。
引數和結果的處理方式與任何其他 Perl 子程式相同:引數在 @_
中傳遞,並且使用 return
或作為函數中評估的最後一個表示式傳回結果值。
例如,傳回兩個整數值中較大者的函數可以定義為
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$ if ($_[0] > $_[1]) { return $_[0]; } return $_[1]; $$ LANGUAGE plperl;
引數將從資料庫的編碼轉換為 UTF-8,以便在 PL/Perl 中使用,然後在傳回時從 UTF-8 轉換回資料庫編碼。
如果將 SQL 空值傳遞給函數,則引數值在 Perl 中將顯示為 “未定義”。上述函數定義對於空輸入的行為不太友善(事實上,它的行為就像它們是零一樣)。我們可以將 STRICT
新增至函數定義,以使 PostgreSQL 執行更合理的動作:如果傳遞空值,則根本不會呼叫該函數,而是會自動傳回空結果。或者,我們可以在函數主體中檢查未定義的輸入。例如,假設我們希望具有一個空值和一個非空值引數的 perl_max
傳回非空值引數,而不是空值
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$ my ($x, $y) = @_; if (not defined $x) { return undef if not defined $y; return $y; } return $x if not defined $y; return $x if $x > $y; return $y; $$ LANGUAGE plperl;
如上所示,若要從 PL/Perl 函數傳回 SQL 空值,請傳回未定義的值。無論函數是否嚴格,都可以執行此操作。
函數引數中不是參考的任何內容都是字串,該字串採用相關資料類型的標準 PostgreSQL 外部文字表示法。對於普通的數值或文字類型,Perl 只會執行正確的操作,並且程式設計師通常不必擔心它。但是,在其他情況下,需要將引數轉換為在 Perl 中更可用的格式。例如,可以使用 decode_bytea
函數將 bytea
類型的引數轉換為未逸出的二進位檔。
同樣地,傳回給 PostgreSQL 的值必須採用外部文字表示法格式。例如,可以使用 encode_bytea
函數逸出二進位資料,以取得 bytea
類型的傳回值。
一個特別重要的例子是布林值。如前所述,bool
值的預設行為是將它們作為文字傳遞給 Perl,因此為 't'
或 'f'
。這是個問題,因為 Perl 不會將 'f'
視為 false!可以透過使用 “轉換” 來改善情況 (參見CREATE TRANSFORM)。bool_plperl
擴充功能提供了適當的轉換。若要使用它,請安裝擴充功能
CREATE EXTENSION bool_plperl; -- or bool_plperlu for PL/PerlU
然後,對於採用或傳回 bool
的 PL/Perl 函數,使用 TRANSFORM
函數屬性,例如
CREATE FUNCTION perl_and(bool, bool) RETURNS bool TRANSFORM FOR TYPE bool AS $$ my ($a, $b) = @_; return $a && $b; $$ LANGUAGE plperl;
當套用此轉換時,Perl 會將 bool
引數視為 1
或空,因此會正確地視為 true 或 false。如果函數結果的類型為 bool
,則根據 Perl 是否會將傳回的值評估為 true,它將為 true 或 false。也會對在函數內部執行的 SPI 查詢的布林查詢引數和結果執行類似的轉換 (第 43.3.1 節)。
Perl 可以將 PostgreSQL 陣列以 Perl 陣列參考的形式回傳。以下是一個範例:
CREATE OR REPLACE function returns_array() RETURNS text[][] AS $$ return [['a"b','c,d'],['e\\f','g']]; $$ LANGUAGE plperl; select returns_array();
Perl 將 PostgreSQL 陣列以一個被 *bless* 的 PostgreSQL::InServer::ARRAY
物件傳遞。 這個物件可以被視為一個陣列參考或一個字串,允許為相容於 9.1 以下版本的 PostgreSQL 所撰寫的 Perl 程式碼執行。 例如:
CREATE OR REPLACE FUNCTION concat_array_elements(text[]) RETURNS TEXT AS $$ my $arg = shift; my $result = ""; return undef if (!defined $arg); # as an array reference for (@$arg) { $result .= $_; } # also works as a string $result .= $arg; return $result; $$ LANGUAGE plperl; SELECT concat_array_elements(ARRAY['PL','/','Perl']);
多維陣列會被表示為對低維陣列參考的參考,這是一種每個 Perl 程式設計師都熟悉的方式。
複合型別參數會以雜湊參考的形式傳遞給函式。雜湊的鍵是複合型別的屬性名稱。以下是一個範例:
CREATE TABLE employee ( name text, basesalary integer, bonus integer ); CREATE FUNCTION empcomp(employee) RETURNS integer AS $$ my ($emp) = @_; return $emp->{basesalary} + $emp->{bonus}; $$ LANGUAGE plperl; SELECT name, empcomp(employee.*) FROM employee;
PL/Perl 函式可以使用相同的方法回傳複合型別結果:回傳一個具有所需屬性的雜湊參考。例如:
CREATE TYPE testrowperl AS (f1 integer, f2 text, f3 text); CREATE OR REPLACE FUNCTION perl_row() RETURNS testrowperl AS $$ return {f2 => 'hello', f1 => 1, f3 => 'world'}; $$ LANGUAGE plperl; SELECT * FROM perl_row();
已宣告的結果資料類型中,任何在雜湊中不存在的欄位將會以 null 值回傳。
類似地,程序的輸出參數可以被當作雜湊參考回傳。
CREATE PROCEDURE perl_triple(INOUT a integer, INOUT b integer) AS $$ my ($a, $b) = @_; return {a => $a * 3, b => $b * 3}; $$ LANGUAGE plperl; CALL perl_triple(5, 10);
PL/Perl 函式也可以回傳純量或複合型別的集合。 通常,您會希望一次回傳一列,以加速啟動時間並避免將整個結果集排隊在記憶體中。 您可以使用 return_next
來完成此操作,如下所示。 請注意,在最後一個 return_next
之後,您必須放入 return
或 (更好的是) return undef
。
CREATE OR REPLACE FUNCTION perl_set_int(int) RETURNS SETOF INTEGER AS $$ foreach (0..$_[0]) { return_next($_); } return undef; $$ LANGUAGE plperl; SELECT * FROM perl_set_int(5); CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testrowperl AS $$ return_next({ f1 => 1, f2 => 'Hello', f3 => 'World' }); return_next({ f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' }); return_next({ f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' }); return undef; $$ LANGUAGE plperl;
對於小型結果集,您可以回傳一個陣列的參考,該陣列包含純量、陣列的參考,或是分別用於簡單類型、陣列類型和複合類型的雜湊的參考。 以下是一些將整個結果集作為陣列參考回傳的簡單範例:
CREATE OR REPLACE FUNCTION perl_set_int(int) RETURNS SETOF INTEGER AS $$ return [0..$_[0]]; $$ LANGUAGE plperl; SELECT * FROM perl_set_int(5); CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testrowperl AS $$ return [ { f1 => 1, f2 => 'Hello', f3 => 'World' }, { f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' }, { f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' } ]; $$ LANGUAGE plperl; SELECT * FROM perl_set();
如果您希望對程式碼使用 strict
語法,您有幾個選項。對於暫時的全域使用,您可以 SET
plperl.use_strict
為 true。 這將會影響後續編譯的 PL/Perl 函式,但不會影響目前工作階段中已經編譯的函式。 對於永久的全域使用,您可以在 postgresql.conf
檔案中將 plperl.use_strict
設定為 true。
對於在特定函式中永久使用,您可以簡單地放入
use strict;
在函式主體的頂部。
如果您的 Perl 版本是 5.10.0 或更高版本,也可以 use
feature
語法。
如果您在文件中發現任何不正確、與您對特定功能的體驗不符或需要進一步澄清的地方,請使用此表單回報文件問題。