要建立一個 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 頁中的 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 null 值被傳遞給一個函式,則引數值在 Perl 中將顯示為 “undefined”。上面的函式定義對於 null 輸入將不會有很好的表現(實際上,它會將它們當作零處理)。我們可以向函式定義新增 STRICT
來讓 PostgreSQL 做一些更合理的事情:如果傳遞了一個 null 值,函式根本不會被呼叫,只會自動返回一個 null 結果。或者,我們可以在函式體中檢查未定義輸入。例如,假設我們希望 perl_max
在有一個 null 引數和一個非 null 引數時返回非 null 引數,而不是 null 值
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 null 值,請返回一個未定義的值。無論函式是否嚴格,都可以做到這一點。
函式引數中任何不是引用的東西都是字串,它以相關的內建資料型別的標準 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
或空,因此分別為真或假。如果函式結果的型別是 bool
,它將根據 Perl 是否會將返回的值評估為真而為真或假。對於布林查詢引數和函式內部執行的 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 陣列作為已繫結的 PostgreSQL::InServer::ARRAY
物件傳遞。此物件可以被視為陣列引用或字串,從而允許與為 PostgreSQL 9.1 及以下版本編寫的 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
pragma,你有幾個選擇。對於臨時全域性使用,你可以將 plperl.use_strict
SET
為 true。這將影響後續 PL/Perl 函式的編譯,但不會影響當前會話中已編譯的函式。對於永久全域性使用,可以在 postgresql.conf
檔案中將 plperl.use_strict
設定為 true。
對於特定函式中的永久使用,你可以簡單地將
use strict;
放在函式體頂部。
如果你的 Perl 版本是 5.10.0 或更高版本,也可以使用 feature
pragma進行 use
。
如果你在文件中看到任何不正確的內容,與你對特定功能的體驗不符,或者需要進一步澄清,請使用 此表單 來報告文件問題。