On this page
45.3. 数据值
一般来说,PL/Python 的目的是在 PostgreSQL 和 Python 世界之间提供“自然”的 Map。这通知了下面描述的数据 Map 规则。
45 .3.1. 数据类型 Map
调用 PL/Python 函数时,其参数将从其 PostgreSQL 数据类型转换为对应的 Python 类型:
PostgreSQL
boolean
转换为 Pythonbool
。PostgreSQL
smallint
和int
转换为 Pythonint
。 PostgreSQLbigint
和oid
在 Python 2 中转换为long
,在 Python 3 中转换为int
。PostgreSQL
real
和double
转换为 Pythonfloat
。PostgreSQL
numeric
转换为 PythonDecimal
。如果可用,则从cdecimal
包中导入此类型。否则,将使用标准库中的decimal.Decimal
。cdecimal
比decimal
快得多。但是,在 Python 3.3 及更高版本中,cdecimal
已以decimal
的名称集成到标准库中,因此不再有任何区别。PostgreSQL
bytea
在 Python 2 中转换为 Pythonstr
,在 Python 3 中转换为bytes
。在 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 数据类型的 Importing 函数。 (如果 Python 值为float
,则使用内置的repr
而不是str
进行转换,以避免精度下降.)
将 Python 2 中的字符串传递给 PostgreSQL 时,必须使用 PostgreSQL 服务器编码。在当前服务器编码中无效的字符串将引发错误,但并非可以检测到所有编码不匹配,因此,如果操作不正确,则仍会产生垃圾数据。 Unicode 字符串会自动转换为正确的编码,因此使用它们会更安全,更方便。在 Python 3 中,所有字符串都是 Unicode 字符串。
- 对于非标量数据类型,请参见下文。
请注意,声明的 PostgreSQL 返回类型与实际返回对象的 Python 数据类型之间的逻辑不匹配不会被标记。该值将在任何情况下转换。
45 .3.2. 空,无
如果将 SQL 空值传递给函数,则参数值在 Python 中将显示为None
。例如,在Section 45.2中显示的pymax
函数定义将为空 Importing 返回错误答案。我们可以在函数定义中添加STRICT
来使 PostgreSQL 做一些更合理的事情:如果传递了 null 值,则该函数将不会被调用,而只会自动返回 null 结果。或者,我们可以在函数体中检查空 Importing:
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 中。二维数组是例如列表的列表。从 PL/Python 函数返回多维 SQL 数组时,每个级别的内部列表都必须具有相同的大小。例如:
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)
当不支持多维数组时,其他 Python 序列(如 Tuples)也可以与 PostgreSQL 9.6 及更低版本兼容,以实现向后兼容。但是,它们始终被视为一维数组,因为它们与复合类型不明确。出于相同的原因,当在多维数组中使用复合类型时,它必须由 Tuples 而不是列表表示。
请注意,在 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. 复合类型
复合类型参数作为 PythonMap 传递给函数。Map 的元素名称是复合类型的属性名称。如果传递的行中的属性值为空,则 Map 中的值为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
);
综合结果可以返回为:
序列类型(Tuples 或列表,但不是集合,因为它不可索引)
- 返回的序列对象必须具有与复合结果类型的字段相同数量的项目。索引为 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 列表表示复合类型还是另一个数组维是不明确的。
Mapping (dictionary)
- 从结果中检索每个结果类型列的值,并将列名作为键。例:
CREATE FUNCTION make_pair (name text, value integer)
RETURNS named_value
AS $$
return { "name": name, "value": value }
$$ LANGUAGE plpythonu;
任何多余的字典键/值对都将被忽略。缺少键被视为错误。要为任何列返回 SQL 空值,请插入None
并以相应的列名作为键。
对象(任何提供对象的方法
__getattr__
)- 这与 Map 相同。例:
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 plpythonu;
还支持带有OUT
参数的功能。例如:
CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$
return (1, 2)
$$ LANGUAGE plpythonu;
SELECT * FROM multiout_simple();
45 .3.5. 返回设置功能
PL/Python 函数还可以返回标量或复合类型的集合。有多种方法可以实现此目的,因为返回的对象在内部变成了迭代器。以下示例假定我们具有复合类型:
CREATE TYPE greeting AS (
how text,
who text
);
可以从以下项返回设置结果:
- 序列类型(Tuples,列表,集合)
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 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;
- Generator(
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);