一般来说,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 null 值传递给函数,则参数值在 Python 中将显示为 None
。例如,第 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
值。无论该函数是否严格,都可以执行此操作。
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 映射传递给函数。映射的元素名称是复合类型的属性名称。如果传递的行中的属性具有 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);
如果您在文档中发现任何不正确、与特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。