pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
一般来说,PL/Python 的目标是在 PostgreSQL 世界和 Python 世界之间提供一种“自然”的映射。下面描述的数据映射规则就是基于这一目标。
函数参数会从它们的 PostgreSQL 类型转换为相应的 Python 类型:
PostgreSQL boolean 会转换为 Python bool。
PostgreSQL smallint and int are converted to Python int. PostgreSQL bigint is converted to long in Python 2 and to int in Python 3.
PostgreSQL real、double 和 numeric 会转换为 Python float。注意, 对 numeric 而言这会丢失信息,并可能导致不正确的 结果。这一点也许会在未来的版本中修复。
PostgreSQL bytea 在 Python 2 中会转换为 Python str,在 Python 3 中会转换为 bytes。在 Python 2 中,该字符串应当被视为不带任何 字符编码的字节序列。
所有其他数据类型,包括 PostgreSQL 字符串类型,都会转换为 Python str。在 Python 2 中,该字符串采用 PostgreSQL 服务器编码;在 Python 3 中,它与所有字符串一样, 都是 Unicode 字符串。
对于非标量数据类型,请参见下文。
函数返回值按如下方式转换到声明的 PostgreSQL 返回数据类型:
当 PostgreSQL 返回类型为 boolean 时,返回值会按照 Python 规则进行真值判定。也就是说,0 和空 字符串为假,但值得注意的是,'f' 为真。
当 PostgreSQL 返回类型为 bytea 时,会先使用相应的 Python 内置函数,将返回值转换为字符串(Python 2)或 bytes (Python 3),再将结果转换为 bytea。
对于所有其他 PostgreSQL 返回类型,返回的 Python 值会使用 Python 内置函数 str 转换为字符串,然后将 结果传给 PostgreSQL 数据类型的输入函数。
Python 2 中的字符串传给 PostgreSQL 时,必须采用 PostgreSQL 服务器编码。在当前服务器编码中无效的字符串会引发错误,但并非 所有编码不匹配都能被检测到,因此处理不当仍可能产生乱码数据。 Unicode 字符串会自动转换为正确的编码,因而使用它们可能更安全、 更方便。在 Python 3 中,所有字符串都是 Unicode 字符串。
对于非标量数据类型,请参见下文。
注意,声明的 PostgreSQL 返回类型与实际返回对象的 Python 数据类型 之间的逻辑不匹配不会被标记;无论何种情况,值都会被转换。
PL/Python 函数不能返回 RECORD 或 SETOF RECORD 类型。一种变通 办法是编写一个创建临时表的 PL/pgSQL 函数,让它调用 PL/Python 函数来填充 该表,然后由 PL/pgSQL 函数返回该临时 表中的通用 RECORD。
如果将 SQL 空值传递给函数,该 参数值在 Python 中会表现为 None。例如,函数 pymax 的定义(见 第 42.2 节)对空值输入会返回错误结果。可以在 函数定义中添加 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。无论函数是否严格,都可以这样做。
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 中,字符串也是序列,这可能会带来一些 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 ] # 也可以使用元组: return ( name, value ) $$ LANGUAGE plpythonu;
要为某一列返回 SQL 空值,请将 None 放在对应位置。
结果类型中每一列的值,都使用列名作为键从映射中取得。例如:
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)
# 或者简写为
class nv: pass
nv.name = name
nv.value = value
return nv
$$ LANGUAGE plpythonu;
PL/Python函数也可以返回标量类型或复合类型的集合。实现方式有多种,因为返回的对象在内部会被转换成一个迭代器。以下示例假定我们有如下复合类型:
CREATE TYPE greeting AS ( how text, who text );
集合结果可以通过以下对象返回:
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;
由于 Python 的缺陷 #1483133, 某些调试版本的 Python 2.4(以--with-pydebug选项配置并编译) 在使用迭代器返回集合结果时会导致PostgreSQL服务器崩溃。 未打补丁的 Fedora 4 就包含此缺陷。在 Python 的正式版本或已打补丁的 Fedora 4 中不会发生这种情况。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。