从整体而言,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
函数定义将对空输入返回错误的答案。我们可以在函数定义中添加 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 plpython3u;
如上所示,要从 PL/Python 函数返回 SQL 空值,请返回 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。例如,2 维数组是列表列表。从 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)
其他 Python 序列,如元组,也为与 PostgreSQL 9.6 及以下版本(当时不支持多维数组)向后兼容而接受。但是,它们始终被视为一维数组,因为它们与组合类型歧义。出于同样的原因,当复合类型在多维数组中使用时,它必须由元组而不是列表表示。
请注意,在 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 映射传给函数。映射的元素名称是组合类型的属性名称。如果传递行中的属性具有空值,则它在映射中的值为 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);