W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
一般來講,PL/Python 的目標(biāo)是提供在 PostgreSQL 和 Python 世界之間的一種“自然的”映射。這包括下面介紹的數(shù)據(jù)映射規(guī)則。
在調(diào)用一個(gè) PL/Python 函數(shù)時(shí),它的參數(shù)會被從 PostgreSQL 的數(shù)據(jù)類型轉(zhuǎn)換成相應(yīng)的 Python 類型:
PostgreSQL 的boolean
被轉(zhuǎn)換成 Python 的bool
。
PostgreSQL 的smallint
和int
被轉(zhuǎn)換成 Python 的int
。 PostgreSQL 的bigint
和oid
被轉(zhuǎn)換成 Python 2 的long
或者 Python 3
的int
。
PostgreSQL 的real
和double
被轉(zhuǎn)換成 Python 的float
。
PostgreSQL 的numeric
被轉(zhuǎn)換成 Python 的Decimal
。如果存在cdecimal
包,則會從其中導(dǎo)入該類型。否則將使用來自標(biāo)準(zhǔn)庫的decimal.Decimal
。cdecimal
比decimal
要更快。不過,在
Python 3.3 以及更高的版本中,cdecimal
已經(jīng)被整合到了標(biāo)準(zhǔn)庫中(也是用decimal
這個(gè)名字),因此也就不再有什么區(qū)別。
PostgreSQL 的bytea
被轉(zhuǎn)換成 Python 的str
(Python 2)和bytes
(Python 3)。在 Python 2 中,串應(yīng)該被當(dāng)做沒有任何字符編碼的字節(jié)序列對待。
包括 PostgreSQL 字符串類型在內(nèi)的所有其他數(shù)據(jù)類型會被轉(zhuǎn)換成一個(gè) Python 的str
。在 Python 2 中,這個(gè)串將用 PostgreSQL 服務(wù)器編碼;在 Python 3 中,它將和所有串一樣使用 Unicode。
對于非標(biāo)量數(shù)據(jù)類型,請見下文。
當(dāng)一個(gè) PL/Python 函數(shù)返回時(shí),會按照下列規(guī)則把它的返回值轉(zhuǎn)換成該函數(shù)聲明的 PostgreSQL 返回?cái)?shù)據(jù)類型:
當(dāng) PostgreSQL 返回類型是boolean
時(shí),返回值會被根據(jù)Python規(guī)則計(jì)算真假。也就是說,0 和空串是假,但是要特別注意'f'
是真。
當(dāng) PostgreSQL 返回類型是bytea
時(shí),返回值會被使用相應(yīng)的 Python 內(nèi)建機(jī)制轉(zhuǎn)換成串(Python 2)或者字節(jié)(Python 3),結(jié)果將被轉(zhuǎn)換成bytea
。
對于所有其他 PostgreSQL 返回類型,返回值被使用 Python 內(nèi)建的str
轉(zhuǎn)換成一個(gè)串,并且結(jié)果會被傳遞給 PostgreSQL 數(shù)據(jù)類型的輸入函數(shù)(如果該 Python 值是一個(gè)float
,它會被用內(nèi)建的repr
而不是str
轉(zhuǎn)換,這是為了避免精度損失)。
當(dāng) Python 2 的串被傳遞給 PostgreSQL 時(shí),它們被要求是 PostgreSQL 服務(wù)器編碼。在當(dāng)前服務(wù)器編碼中不可用的串將會產(chǎn)生錯(cuò)誤,但是并非所有的編碼失配都能被檢測到,因此當(dāng)沒有正確地將串編碼時(shí),垃圾數(shù)據(jù)仍然會產(chǎn)生。Unicode 串會被自動(dòng)地轉(zhuǎn)換為正確的編碼,因此使用 Unicode 串更加安全并且更加方便。在 Python 3 中,所有串都是 Unicode 串。
對于非標(biāo)量數(shù)據(jù)類型,請見下文。
注意所聲明的 PostgreSQL 返回類型和實(shí)際返回對象的 Python 數(shù)據(jù)類型之間的邏輯失配不會被標(biāo)志,無論怎樣該值都會被轉(zhuǎn)換。
如果一個(gè) SQL 空值
被傳遞給一個(gè)函數(shù),該參數(shù)值將作為 Python 中的None
出現(xiàn)。例如,第 45.2 節(jié)中展示的pymax
的函數(shù)定義對于空值輸入將會返回錯(cuò)誤的回答。我們可以為函數(shù)定義增加STRICT
讓
PostgreSQL做得更加合理:如果一個(gè)空值被傳入,該函數(shù)將根本不會被調(diào)用,而只是自動(dòng)地返回一個(gè)空結(jié)果。此外,我們可以在函數(shù)體中檢查空輸入:
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 plpythonu;
如前所示,要從一個(gè) PL/Python 函數(shù)返回一個(gè) SQL 空值,可返回值None
。不管該函數(shù)嚴(yán)格與否都可以這樣做。
SQL 數(shù)組會被作為一個(gè) Python 列表傳遞到 PL/Python 中。要從一個(gè) PL/Python 函數(shù)中返回出一個(gè) SQL 數(shù)組值,可返回一個(gè)Python列表:
CREATE FUNCTION return_arr()
RETURNS int[]
AS $$
return [1, 2, 3, 4, 5]
$$ LANGUAGE plpythonu;
SELECT return_arr();
return_arr
-------------
{1,2,3,4,5}
(1 row)
多維數(shù)組被當(dāng)做嵌套的Python列表傳入PL/Python。例如,一個(gè)2維數(shù)組是一個(gè)列表的列表。在把一個(gè)多維SQL數(shù)組從PL/Python函數(shù)返回出去時(shí),每一層的內(nèi)層列表都必須是相同的尺寸。例如:
CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$
plpy.info(x, type(x))
return x
$$ LANGUAGE plpythonu;
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以及更低版本的向后兼容性,當(dāng)不支持多維數(shù)組時(shí),也接受元組之類的其他Python序列。不過,它們總是被當(dāng)做一維數(shù)組,因?yàn)樗鼈儠徒M合類型混淆。出于同樣的原因,當(dāng)一個(gè)組合類型被用在多維數(shù)組中時(shí),它必須被表示為一個(gè)元組而不是一個(gè)列表。
注意在 Python 中,串是序列,這可能產(chǎn)生與 Python 程序員所熟悉的不同的效果:
CREATE FUNCTION return_str_arr()
RETURNS varchar[]
AS $$
return "hello"
$$ LANGUAGE plpythonu;
SELECT return_str_arr();
return_str_arr
----------------
{h,e,l,l,o}
(1 row)
組合類型參數(shù)被作為 Python 映射傳遞給函數(shù)。映射的元素名稱就是組合類型的屬性名。如果被傳遞的行中有一個(gè)屬性是空值,在映射中它的值是None
。這里是一個(gè)例子:
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 plpythonu;
有多種方式從一個(gè) Python 函數(shù)返回行或者組合類型。下面的例子假設(shè)我們有:
CREATE TYPE named_value AS (
name text,
value integer
);
一個(gè)組合結(jié)果可以被返回為:
被返回的序列對象必須具有和組合結(jié)果類型的域個(gè)數(shù)相同的項(xiàng)。索引號為 0 的項(xiàng)被分配給組合類型的第一個(gè)域,為 1 的項(xiàng)給第二個(gè)域,以此類推。例如:
CREATE FUNCTION make_pair (name text, value integer)
RETURNS named_value
AS $$
return ( name, value )
# or alternatively, as tuple: return [ name, value ]
$$ LANGUAGE plpythonu;
要為任意列返回一個(gè) SQL 空,應(yīng)在對應(yīng)的位置插入None
。
當(dāng)一個(gè)組合類型的數(shù)組被返回時(shí),它不能被返回為列表,因?yàn)闀磺逶揚(yáng)ython列表究竟是表示一個(gè)組合類型還是另一個(gè)數(shù)組維度。
用列名作為鍵從映射中檢索每一個(gè)結(jié)果類型列的值。例如:
CREATE FUNCTION make_pair (name text, value integer)
RETURNS named_value
AS $$
return { "name": name, "value": value }
$$ LANGUAGE plpythonu;
任何額外的字典鍵/值對都會被忽略。丟失的鍵會被當(dāng)做錯(cuò)誤。要為任意列返回一個(gè) SQL 空,應(yīng)用相應(yīng)的列名作為鍵插入None
。
__getattr__
的對象)這和映射的運(yùn)作方式相同。例如:
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)
# 或簡單地
class nv: pass
nv.name = name
nv.value = value
return nv
$$ LANGUAGE plpythonu;
也支持具有OUT
參數(shù)的函數(shù)。例如:
CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$
return (1, 2)
$$ LANGUAGE plpythonu;
SELECT * FROM multiout_simple();
過程的輸出參數(shù)會以同樣的方式傳回。例如:
CREATE PROCEDURE python_triple(INOUT a integer, INOUT b integer) AS $$
return (a * 3, b * 3)
$$ LANGUAGE plpythonu;
CALL python_triple(5, 10);
PL/Python函數(shù)也能返回標(biāo)量類型或者組合類型的集合。有多種方法可以做到這一點(diǎn),因?yàn)楸环祷氐膶ο笤趦?nèi)部會被轉(zhuǎn)變成一個(gè)迭代器。下面的例子假設(shè)我們有組合類型:
CREATE TYPE greeting AS (
how text,
who text
);
可從以下類型返回集合結(jié)果:
CREATE FUNCTION greet (how text)
RETURNS SETOF greeting
AS $$
# 把包含列表的元組返回為組合類型
# 所有其他組合也能行
return ( [ how, "World" ], [ how, "PostgreSQL" ], [ how, "PL/Python" ] )
$$ LANGUAGE plpythonu;
__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 plpythonu;
yield
)CREATE FUNCTION greet (how text)
RETURNS SETOF greeting
AS $$
for who in [ "World", "PostgreSQL", "PL/Python" ]:
yield ( how, who )
$$ LANGUAGE plpythonu;
也支持有OUT
參數(shù)的集合返回函數(shù)(使用RETURNS SETOF record
)。例如:
CREATE FUNCTION multiout_simple_setof(n integer, OUT integer, OUT integer) RETURNS SETOF record AS $$
return [(1, 2)] * n
$$ LANGUAGE plpythonu;
SELECT * FROM multiout_simple_setof(3);
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: