一般来说,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(和所有 Python 字符串一样,都是 Unicode)。
对于非标量数据类型,请参见下文。
当 PL/Python 函数返回时,其返回值会按如下方式转换成该函数声明的 PostgreSQL 返回数据类型:
当 PostgreSQL 返回类型为boolean时,返回值会按照Python规则进行真值判定。也就是说,0 和空字符串为假,但值得注意的是,'f' 为真。
当 PostgreSQL 返回类型为bytea时,返回值会通过相应的 Python 内置函数转换成 Python bytes,再将结果转换成bytea。
对于所有其他 PostgreSQL 返回类型,返回值会使用 Python 内置函数str转换为字符串,然后将结果传给 PostgreSQL 数据类型的输入函数。(如果 Python 值是float,则会使用repr内置函数而不是str来转换,以避免精度损失。)
字符串在传给 PostgreSQL 时,会自动转换为 PostgreSQL 服务器编码。
对于非标量数据类型,请参见下文。
请注意,即使声明的 PostgreSQL 返回类型与实际返回对象的 Python 数据类型在逻辑上并不匹配,也不会报错;无论如何该值都会被转换。
如果把 SQL 空值传给函数,参数值在 Python 中会显示为None。例如,Section 44.2中展示的pymax定义在处理空输入时就会返回错误结果。我们可以在函数定义中添加STRICT,让PostgreSQL做出更合理的处理:如果传入空值,函数根本不会被调用,而是自动返回空结果。另一种办法是在函数体中检查空输入:
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;
如上所示,要从 PL/Python 函数返回 SQL 空值,只需返回None。无论函数是否被声明为STRICT,都可以这样做。
SQL 数组值会作为 Python 列表传入 PL/Python。要从 PL/Python 函数返回 SQL 数组值,请返回一个 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)
多维数组会作为嵌套的 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 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)
其他 Python 序列(如元组)也可被接受,这是为了与 PostgreSQL 9.6 及以下版本保持向后兼容,因为那时尚不支持多维数组。不过,它们始终被视为一维数组,因为它们与复合类型存在歧义。出于同样原因,当在多维数组中使用复合类型时,必须用元组而不是列表来表示。
请注意,在 Python 中,字符串也是序列,这可能会带来一些 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)
复合类型参数会以 Python 映射的形式传给函数。映射中的元素名就是复合类型的属性名。如果传入行中的某个属性为空值,那么它在映射中的值就是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 plpythonu;
有多种方法可以从 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 plpythonu;
要为任意列返回 SQL 空值,请在相应位置插入None。
当返回复合类型数组时,不能将其表示为列表,因为这样无法区分 Python 列表表示的是复合类型还是另一个数组维度。
每个结果类型列的值都从该映射中取出,列名作为键。例如:
CREATE FUNCTION make_pair (name text, value integer)
RETURNS named_value
AS $$
return { "name": name, "value": value }
$$ LANGUAGE plpythonu;
额外的字典键/值对会被忽略。缺失的键会被视为错误。 要为任意列返回 SQL 空值,请使用相应列名作为键插入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 plpythonu;
也支持带OUT参数的函数。例如:
CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$ return (1, 2) $$ LANGUAGE plpythonu; SELECT * FROM multiout_simple();
过程的输出参数也以同样的方式传回。例如:
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函数也可以返回标量类型或复合类型的集合。实现方式有多种,因为返回的对象在内部会被转换成一个迭代器。以下示例假定我们有如下复合类型:
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 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参数的返回集函数(使用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);
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。