选择 打开 改范围 完整检索页
受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10
当前 PostgreSQL 版本不在支持生命周期内。
您可以参阅当前版本的对应页面,或其他在上面列出的活跃大版本。

46.3. 数据值 #

一般来说,PL/Python 的目标是在 PostgreSQL 世界和 Python 世界之间提供一种自然的映射。下面描述的数据映射规则就是基于这一目标。

46.3.1. 数据类型映射

调用 PL/Python 函数时,参数会从 PostgreSQL 数据类型转换为相应的 Python 类型:

  • PostgreSQL boolean 会转换为 Python bool

  • PostgreSQL 的 smallintint 转换为 Python 的 int。PostgreSQL 的 bigintoid 在 Python 2 中转换为 long,在 Python 3 中转换为 int

  • PostgreSQL realdouble 会转换为 Python float

  • PostgreSQL numeric 会转换为 Python Decimal。如果可用,将从 cdecimal 包导入这种类型。 否则,将使用标准库中的 decimal.Decimalcdecimal 明显快于 decimal。 不过在 Python 3.3 及更高版本中, cdecimal 已经以 decimal 这一名称并入标准库, 因此不再有区别。

  • PostgreSQL 的 bytea 在 Python 2 中转换为 str,在 Python 3 中转换为 bytes。在 Python 2 中,应将该字符串视为不带任何字符编码的字节序列。

  • 所有其他数据类型,包括 PostgreSQL 字符串类型, 都会转换为 Python str(和所有 Python 字符串一样,都是 Unicode)。

  • 对于非标量数据类型,请参见下文。

PL/Python 函数返回时,返回值按以下规则转换为该函数声明的 PostgreSQL 返回数据类型:

  • 当 PostgreSQL 返回类型为boolean时,返回值会按照Python规则进行真值判定。也就是说,0 和空字符串为假,但值得注意的是,'f' 为真。

  • 如果 PostgreSQL 返回类型是 bytea,会先使用相应的 Python 内置函数,将返回值转换为字符串(Python 2)或 bytes(Python 3),再将结果转换为 bytea

  • 对于所有其他 PostgreSQL 返回类型,返回值会使用 Python 内置函数str转换为字符串,然后将结果传给 PostgreSQL 数据类型的输入函数。(如果 Python 值是float,则会使用repr内置函数而不是str来转换,以避免精度损失。)

    字符串在传给 PostgreSQL 时,会自动转换为 PostgreSQL 服务器编码。

  • 对于非标量数据类型,请参见下文。

注意,如果声明的 PostgreSQL 返回类型与实际返回对象的 Python 数据类型在逻辑上不匹配,系统不会提示;无论如何都会转换该值。

46.3.2. 空值、None

如果将 SQL 空值传递给函数,该参数值在 Python 中会表现为 None。例如,函数 pymax 的定义(见 Section 46.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。无论函数是否严格,都可以这样做。

46.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 序列(如元组)也可被接受,这是为了与 PostgreSQL 9.6 及以下版本保持向后兼容,因为那时尚不支持多维数组。不过,它们始终被视为一维数组,因为它们与复合类型存在歧义。出于同样原因,当在多维数组中使用复合类型时,必须用元组而不是列表来表示。

请注意,在 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)

46.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 list: 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)

  # 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();

过程的输出参数也以同样的方式传回。例如:

CREATE PROCEDURE python_triple(INOUT a integer, INOUT b integer) AS $$
return (a * 3, b * 3)
$$ LANGUAGE plpythonu;

CALL python_triple(5, 10);

46.3.5. 返回集合的函数

一个 PL/Python 函数也可以返回标量类型或复合类型的集合。实现方式有多种,因为返回对象在内部会被转换为迭代器。以下示例假定已定义复合类型:

CREATE TYPE greeting AS (
  how text,
  who text
);

集合结果可以通过以下形式返回:

序列类型(元组、列表、集合)
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;
生成器(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);