總的來說,PL/Python 的目標是在 PostgreSQL 和 Python 世界之間提供一個“自然”的對映。這一點體現在以下描述的資料對映規則中。
當呼叫 PL/Python 函式時,其引數會從 PostgreSQL 資料型別轉換為相應的 Python 型別。
PostgreSQL 的 boolean 型別會被轉換為 Python 的 bool 型別。
PostgreSQL 的 smallint、int、bigint 和 oid 型別會被轉換為 Python 的 int 型別。
PostgreSQL 的 real 和 double 型別會被轉換為 Python 的 float 型別。
PostgreSQL 的 numeric 型別會被轉換為 Python 的 Decimal 型別。如果 cdecimal 包可用,則會從中匯入該型別;否則,將使用標準庫中的 decimal.Decimal。 cdecimal 的速度比 decimal 快得多。然而,在 Python 3.3 及更高版本中,cdecimal 已被整合到標準庫中,並命名為 decimal,因此不再有區別。
PostgreSQL 的 bytea 型別會被轉換為 Python 的 bytes 型別。
所有其他資料型別,包括 PostgreSQL 的字串型別,都會被轉換為 Python 的 str 型別(在 Unicode 中,就像所有 Python 字串一樣)。
對於非標量資料型別,請參見下文。
當 PL/Python 函式返回時,其返回值會轉換為函式宣告的 PostgreSQL 返回資料型別,轉換方式如下:
當 PostgreSQL 返回型別為 boolean 時,返回值將根據 **Python** 的規則進行真值評估。也就是說,0 和空字串為 False,但值得注意的是,'f' 為 True。
當 PostgreSQL 返回型別為 bytea 時,返回值將使用相應的 Python 內建函式轉換為 Python 的 bytes 型別,然後將結果轉換為 bytea。
對於所有其他 PostgreSQL 返回型別,返回值將使用 Python 內建函式 str 轉換為字串,然後將結果傳遞給 PostgreSQL 資料型別的輸入函式。(如果 Python 值是 float,則會使用 repr 內建函式而不是 str 進行轉換,以避免精度損失。)
字串在傳遞給 PostgreSQL 時會自動轉換為 PostgreSQL 伺服器編碼。
對於非標量資料型別,請參見下文。
請注意,宣告的 PostgreSQL 返回型別與實際返回物件的 Python 資料型別之間的邏輯不匹配不會被標記;無論如何都會進行值轉換。
如果將 SQL NULL 值傳遞給函式,則該引數值在 Python 中將顯示為 None。例如,上面 Section 44.1 中顯示的 pymax 函式定義對於 NULL 輸入將返回錯誤答案。我們可以向函式定義新增 STRICT 來讓 PostgreSQL 執行更合理的處理:如果傳遞 NULL 值,函式將根本不會被呼叫,而是自動返回 NULL 結果。或者,我們可以在函式體中檢查 NULL 輸入。
CREATE FUNCTION pymax (a integer, b integer)
RETURNS integer
AS $$
if (a is None) or (b is None):
return None
if a > b:
return a
return b
$$ LANGUAGE plpython3u;
如上所示,要從 PL/Python 函式返回 SQL NULL 值,請返回 None。無論函式是否為 strict,都可以這樣做。
SQL 陣列值被作為 Python 列表傳遞給 PL/Python。要從 PL/Python 函式返回 SQL 陣列值,請返回一個 Python 列表。
CREATE FUNCTION return_arr()
RETURNS int[]
AS $$
return [1, 2, 3, 4, 5]
$$ LANGUAGE plpython3u;
SELECT return_arr();
return_arr
-------------
{1,2,3,4,5}
(1 row)
多維陣列被作為巢狀的 Python 列表傳遞給 PL/Python。例如,一個二維陣列就是一個列表的列表。當從 PL/Python 函式返回多維 SQL 陣列時,每一層的內部列表都必須是相同大小的。例如:
CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$
plpy.info(x, type(x))
return x
$$ LANGUAGE plpython3u;
SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]);
INFO: ([[1, 2, 3], [4, 5, 6]], <type 'list'>)
test_type_conversion_array_int4
---------------------------------
{{1,2,3},{4,5,6}}
(1 row)
出於向後相容 PostgreSQL 9.6 及以下版本(當時不支援多維陣列)的目的,其他 Python 序列(如元組)也被接受。但是,它們始終被視為一維陣列,因為它們與複合型別存在歧義。出於相同的原因,當複合型別用於多維陣列時,必須用元組而不是列表來表示。
請注意,在 Python 中,字串是序列,這可能會產生一些 Python 程式設計師可能熟悉的不良影響。
CREATE FUNCTION return_str_arr()
RETURNS varchar[]
AS $$
return "hello"
$$ LANGUAGE plpython3u;
SELECT return_str_arr();
return_str_arr
----------------
{h,e,l,l,o}
(1 row)
複合型別引數被作為 Python 對映(mapping)傳遞給函式。對映的元素名稱是複合型別的屬性名稱。如果傳入行中的屬性值為 NULL,則在對映中其值為 None。例如:
CREATE TABLE employee (
name text,
salary integer,
age integer
);
CREATE FUNCTION overpaid (e employee)
RETURNS boolean
AS $$
if e["salary"] > 200000:
return True
if (e["age"] < 30) and (e["salary"] > 100000):
return True
return False
$$ LANGUAGE plpython3u;
有多種方法可以從 Python 函式返回行或複合型別。以下示例假定我們有:
CREATE TYPE named_value AS ( name text, value integer );
複合結果可以作為
返回的序列物件必須具有與複合結果型別欄位相同的數量的項。索引為 0 的項被分配給複合型別的第一個欄位,索引為 1 的項被分配給第二個欄位,依此類推。例如:
CREATE FUNCTION make_pair (name text, value integer) RETURNS named_value AS $$ return ( name, value ) # or alternatively, as list: return [ name, value ] $$ LANGUAGE plpython3u;
要為任何列返回 SQL NULL,請在相應位置插入 None。
當返回複合型別的陣列時,不能將其作為列表返回,因為無法區分 Python 列表代表的是複合型別還是另一個數組維度。
每個結果型別列的值都從對映中檢索,鍵為列名。示例:
CREATE FUNCTION make_pair (name text, value integer)
RETURNS named_value
AS $$
return { "name": name, "value": value }
$$ LANGUAGE plpython3u;
任何額外的字典鍵/值對都將被忽略。缺失的鍵將被視為錯誤。要為任何列返回 SQL NULL 值,請插入以相應列名作為鍵的 None。
__getattr__ 方法的任何物件)這與對映的工作方式相同。示例:
CREATE FUNCTION make_pair (name text, value integer)
RETURNS named_value
AS $$
class named_value:
def __init__ (self, n, v):
self.name = n
self.value = v
return named_value(name, value)
# or simply
class nv: pass
nv.name = name
nv.value = value
return nv
$$ LANGUAGE plpython3u;
也支援帶有 OUT 引數的函式。例如:
CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$ return (1, 2) $$ LANGUAGE plpython3u; SELECT * FROM multiout_simple();
過程的輸出引數也以相同方式返回。例如:
CREATE PROCEDURE python_triple(INOUT a integer, INOUT b integer) AS $$ return (a * 3, b * 3) $$ LANGUAGE plpython3u; CALL python_triple(5, 10);
PL/Python 函式還可以返回標量或複合型別的集合。有幾種方法可以實現這一點,因為返回的物件在內部會被轉換為迭代器。以下示例假定我們有一個複合型別:
CREATE TYPE greeting AS ( how text, who text );
可以從以下方式返回集合結果:
CREATE FUNCTION greet (how text) RETURNS SETOF greeting AS $$ # return tuple containing lists as composite types # all other combinations work also return ( [ how, "World" ], [ how, "PostgreSQL" ], [ how, "PL/Python" ] ) $$ LANGUAGE plpython3u;
__iter__ 和 __next__ 方法的任何物件)CREATE FUNCTION greet (how text)
RETURNS SETOF greeting
AS $$
class producer:
def __init__ (self, how, who):
self.how = how
self.who = who
self.ndx = -1
def __iter__ (self):
return self
def __next__(self):
self.ndx += 1
if self.ndx == len(self.who):
raise StopIteration
return ( self.how, self.who[self.ndx] )
return producer(how, [ "World", "PostgreSQL", "PL/Python" ])
$$ LANGUAGE plpython3u;
yield)CREATE FUNCTION greet (how text)
RETURNS SETOF greeting
AS $$
for who in [ "World", "PostgreSQL", "PL/Python" ]:
yield ( how, who )
$$ LANGUAGE plpython3u;
也支援帶有 OUT 引數的返回集合的函式(使用 RETURNS SETOF record)。例如:
CREATE FUNCTION multiout_simple_setof(n integer, OUT integer, OUT integer) RETURNS SETOF record AS $$ return [(1, 2)] * n $$ LANGUAGE plpython3u; SELECT * FROM multiout_simple_setof(3);
如果您在文件中看到任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用 此表格 報告文件問題。