总的来说,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);
如果您在文档中看到任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用 此表格 报告文档问题。