PostgreSQL 数据值
- 45.3.1. 数据类型映射
- 45.3.2. Null, None
- 45.3.3. 数组、列表
- 45.3.4. 组合类型
- 45.3.5. 集合返回函数
一般来讲,PL/Python 的目标是提供在 PostgreSQL 和 Python 世界之间的一种“自然的”映射。这包括下面介绍的数据映射规则。
45.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 数据类型之间的逻辑失配不会被标志,无论怎样该值都会被转换。
45.3.2. Null, None
如果一个 SQL 空值
被传递给一个函数,该参数值将作为 Python 中的None
出现。例如,第 45.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
。不管该函数严格与否都可以这样做。
45.3.3. 数组、列表
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)
45.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
。当一个组合类型的数组被返回时,它不能被返回为列表,因为会弄不清该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);
45.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;
也支持有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);