Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17

44.2. 数据值 #

44.2.1. 数据类型映射
44.2.2. Null、None
44.2.3. 数组、列表
44.2.4. 复合类型
44.2.5. 返回集的函数

从整体而言,PL/Python 的目标是为 PostgreSQL 和 Python 世界提供一种自然映射。此目标促成了下面描述的数据映射规则。

44.2.1. 数据类型映射 #

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

  • PostgreSQL boolean 转换为 Python bool

  • PostgreSQL smallintintbigintoid 转换为 Python int

  • PostgreSQL realdouble 转换为 Python float

  • PostgreSQL numeric 转换为 Python Decimal。如果 cdecimal 包可用,此类型会从中导入。否则,会使用标准库中的 decimal.Decimalcdecimaldecimal 快很多。但在 Python 3.3 及更高版本中, cdecimal 已集成到名为 decimal 的标准库中,因此不再有区别。

  • PostgreSQL bytea 转换为 Python bytes

  • 所有其他数据类型(包括 PostgreSQL 字符串类型)均转换为 Python str(与所有 Python 字符串一样采用 Unicode)。

  • 有关非标量数据类型,请参见下文。

当 PL/Python 函数返回时,其返回值会按如下方式转换为函数声明的 PostgreSQL 返回数据类型

  • 当 PostgreSQL 返回类型为 boolean 时,将根据 Python 规则评估返回值的真假。即,0 和空字符串为假,但值得注意的是 'f' 为真。

  • 当 PostgreSQL 返回类型为 bytea 时,将使用相应的 Python 内置函数将返回值转换为 Python bytes,结果会转换为 bytea

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

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

  • 有关非标量数据类型,请参见下文。

请注意,已声明的 PostgreSQL 返回类型与实际返回对象的 Python 数据类型之间的逻辑不匹配不会得到标记;值在任何情况下都将被转换。

44.2.2. Null、None #

如果 SQL 空(null)值传递给函数,则参数值在 Python 中将显示为 None。例如,第 44.1 节 中显示的 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 plpython3u;

如上所示,要从 PL/Python 函数返回 SQL 空值,请返回 None 值。无论函数是否严格,都可以执行此操作。

44.2.3. 数组、列表 #

SQL 数组值作为 Python 列表传递给 PL/Python。要从 PL/Python 函数返回 SQL 数组值,请返回一个 Python 列表

CREATE FUNCTION return_arr()
  RETURNS int[]
AS $$
return [1, 2, 3, 4, 5]
$$ LANGUAGE plpython3u;

SELECT return_arr();
 return_arr
-------------
 {1,2,3,4,5}
(1 row)

多维数组作为嵌套 Python 列表传递给 PL/Python。例如,2 维数组是列表列表。从 PL/Python 函数返回多维 SQL 数组时,每个级别的内部列表必须都具有相同的大小。例如

CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$
plpy.info(x, type(x))
return x
$$ LANGUAGE plpython3u;

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 plpython3u;

SELECT return_str_arr();
 return_str_arr
----------------
 {h,e,l,l,o}
(1 row)

44.2.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 plpython3u;

有多种方法可以从 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 plpython3u;

对于任何列返回一个 SQL null,在相应的位置中插入 None

当返回复合类型的数组时,它无法作为列表返回,因为它含糊地表示 Python 列表表示一个复合类型,或者另一个数组维度。

映射(字典)

每列结果类型的值,使用名称作为键从映射中检索。示例

CREATE FUNCTION make_pair (name text, value integer)
  RETURNS named_value
AS $$
  return { "name": name, "value": value }
$$ LANGUAGE plpython3u;

任何额外的字典键值对会被忽略。缺少的键被视为错误。对于返回任何列的 SQL null 值,插入 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 plpython3u;

具有 OUT 参数的函数也受到支持。例如

CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$
return (1, 2)
$$ LANGUAGE plpython3u;

SELECT * FROM multiout_simple();

过程的输出参数,以相同的方式被传回。例如

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

CALL python_triple(5, 10);

44.2.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 plpython3u;
迭代器(提供 __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 plpython3u;
生成器(yield
CREATE FUNCTION greet (how text)
  RETURNS SETOF greeting
AS $$
  for who in [ "World", "PostgreSQL", "PL/Python" ]:
    yield ( how, who )
$$ LANGUAGE plpython3u;

具有 OUT 参数(使用 RETURNS SETOF record)的返回集函数也受到支持。例如

CREATE FUNCTION multiout_simple_setof(n integer, OUT integer, OUT integer) RETURNS SETOF record AS $$
return [(1, 2)] * n
$$ LANGUAGE plpython3u;

SELECT * FROM multiout_simple_setof(3);