總的來說,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);
如果您在文件中看到任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用 此表格 報告文件問題。