一般来讲,PL/Python 的目标是提供在 PostgreSQL 和 Python 世界之间的一种“自然的”映射。这包括下面介绍的数据映射规则。
在调用一个 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 数据类型之间的逻辑失配不会被标志,无论怎样该值都会被转换。
如果一个 SQL 空值被传递给一个函数,该参数值将作为 Python 中的None
出现。例如,Section 46.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
。不管该函数严格与否都可以这样做。
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列表传入PL/Python。例如,一个2维数组是一个列表的列表。在把一个多维SQL数组从PL/Python函数返回出去时,每一层的内层列表都必须是相同的尺寸。例如:
CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$ plpy.info(x, type(x)) return x $$ LANGUAGE plpythonu; 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 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 ) # or alternatively, as tuple: return [ name, value ] $$ LANGUAGE plpythonu;
要为任意列返回一个 SQL 空,应在对应的位置插入None
。
当一个组合类型的数组被返回时,它不能被返回为列表,因为会弄不清该Python列表究竟是表示一个组合类型还是另一个数组维度。
用列名作为键从映射中检索每一个结果类型列的值。例如:
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();
过程的输出参数会以同样的方式传回。例如:
CREATE PROCEDURE python_triple(INOUT a integer, INOUT b integer) AS $$ return (a * 3, b * 3) $$ LANGUAGE plpythonu; 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 ( [ 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;
也支持有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);