44.3. 数据值
一般来讲,PL/Python 的目标是提供在 PostgreSQL 和 Python 世界之间的一种"自然的"映射。这包括下面介绍的数据映射规则。
44.3.1. 数据类型映射
在调用一个 PL/Python 函数时,它的参数会被从 PostgreSQL 的数据类型转换成相应的 Python 类型:
PostgreSQL 的boolean被转换成 Python 的bool。
PostgreSQL 的smallint和int被转换成 Python 的int。 PostgreSQL 的bigint和oid被转换成 Python 2 的long或者 Python 3 的int。
PostgreSQL 的real和double被转换成 Python 的float。
PostgreSQL 的numeric被转换成 Python 的Decimal。如果存在cdecimal包,则会从其中导入该类型。否则将使用来自标准库的decimal.Decimal。cdecimal比decimal要更快。不过,在 Python 3.3 以及更高的版本中,cdecimal已经被整合到了标准库中(也是用decimal这个名字),因此也就不再有什么区别。
PostgreSQL 的bytea被转换成 Python 的str(Python 2)和bytes(Python 3)。在 Python 2 中,串应该被当做没有任何字符编码的字节序列对待。
包括 PostgreSQL 字符串类型在内的所有其他数据类型会被转换成一个 Python 的str。在 Python 2 中,这个串将用 PostgreSQL 服务器编码;在 Python 3 中,它将和所有串一样使用 unicode。
对于非标量数据类型,请见下文。
当一个 PL/Python 函数返回时,会按照下列规则把它的返回值转换成该函数声明的 PostgreSQL 返回数据类型:
当 PostgreSQL 返回类型是boolean时,返回值会被根据Python规则计算真假。也就是说,0 和空串是假,但是要特别注意'f'是真。
当 PostgreSQL 返回类型是bytea时,返回值会被使用相应的 Python 内建机制转换成串(Python 2)或者字节(Python 3),结果将被转换成bytea。
-
对于所有其他 PostgreSQL 返回类型,返回值被使用 Python 内建的str转换成一个串,并且结果会被传递给 PostgreSQL 数据类型的输入函数(如果该 Python 值是一个float,它会被用内建的repr而不是str转换,这是为了避免精度损失)。
当 Python 2 的串被传递给 PostgreSQL 时,它们被要求是 PostgreSQL 服务器编码。在当前服务器编码中不可用的串将会产生错误,但是并非所有的编码失配都能被检测到,因此当没有正确地将串编码时,垃圾数据仍然会产生。Unicode 串会被自动地转换为正确的编码,因此使用 Unicode 串更加安全并且更加方便。在 Python 3 中,所有串都是 Unicode 串。
对于非标量数据类型,请见下文。
注意所声明的 PostgreSQL 返回类型和实际返回对象的 Python 数据类型之间的逻辑失配不会被标志,无论怎样该值都会被转换。
44.3.2. Null, None
如果一个 SQL 空值被传递给一个函数,该参数值将作为 Python 中的None出现。例如,第 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。不管该函数严格与否都可以这样做。
44.3.3. 数组、列表
SQL 数组会被作为一个 Python 列表传递到 PL/Python 中。要从一个 PL/Python 函数中返回出一个 SQL 数组值,可返回一个序列,例如一个列表或者元组:
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)
44.3.4. 组合类型
组合类型参数被作为 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 tuple: 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;
也支持具有OUT参数的函数。例如:
CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$ return (1, 2) $$ LANGUAGE plpythonu; SELECT * FROM multiout_simple();
44.3.5. 集合返回函数
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;
警告 由于 Pythonbug #1483133,已知 Python 2.4 的某些调试版本(用选项--with-pydebug配置并且编译)在使用迭代器返回集合结果时会让PostgreSQL服务器崩溃。没有打过补丁的 Fedora 4 包含这个缺陷。在生产版本的 Python 中或者打过补丁的 Fedora 4 上不会发生该问题。
也支持有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);