返回介绍

I. 教程

II. SQL 语言

III. 服务器管理

IV. 客户端接口

V. 服务器端编程

VI. 参考手册

VII. 内部

VIII. 附录

40.1. PL/Python 函数

发布于 2019-09-30 03:09:48 字数 4810 浏览 1030 评论 0 收藏 0

PL/Python 写的函数用通常的 CREATE FUNCTION 语法声明。比如:

CREATE FUNCTION funcname (argument-list)
  RETURNS return-type
AS $$
  # PL/Python function body
$$ LANGUAGE plpythonu;

函数体是一个简单的 Python 脚本。当该函数被调用的时候,传递的参数将成为 args[] 数组的元素。命名参数也会被传递到脚本中并被当作普通变量。结果将使用 returnyield 照常返回。

例如,返回两个整数中较大者的函数:

CREATE FUNCTION pymax (a integer, b integer)
  RETURNS integer
AS $$
  if a > b:
    return a
  return b
$$ LANGUAGE plpythonu;

以函数体形式给出的 Python 转换成 Python 函数。比如,上面的转换成

def __plpython_procedure_pymax_23456():
  if a > b:
    return a
  return b

这里假设 23456 是 PostgreSQL 赋予这个函数的 OID 。

PostgreSQL 函数变量可以通过全局的 args 列表获取。在 pymax 例子里,args[0] 包含第一个参数的数值。args[1] 包含第二个。除此在外,还可以使用上例中演示的已命名的参数,这种方法的可读性更好。

如果向函数传递了一个 NULL 值,参数值将会显示为 None 。上述函数定义将对 NULL 输入产生错误的结果。我们可以通过添加 STRICT 来进行更合理的操作:如果传入 NULL 值,函数将根本不会被调用,而是立即返回 NULL 。当然,也可以在函数体中检查输入参数是否为 NULL :

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 函数中返回 NULL ,只要返回 None 即可。无论函数是否严格,这样做都有效。

复合类型参数将作为 Python 映射进行传递。映射的元素名是组合类型的元素名。如果被传递的行中某个属性值为 NULL ,它在映射中的值将是 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 的项将被分配给组合类型的第一个字段,其它依此类推,比如:

CREATE FUNCTION make_pair (name text, value integer)
  RETURNS named_value
AS $$
  return [ name, value ]
  # 或者作为元组返回( name, value )
$$ LANGUAGE plpythonu;

要为任何字段返回 NULL ,就在相应的位置插入 None

映射(字典)

每个结果类型字段的值都重新从映射中使用字段名作为键检索。例如:

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

任何额外的字典键/值对都将被忽略。丢失的键将被当作错误。要为任何字段返回 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)

  # 或者简单地
  class nv: pass
  nv.name = name
  nv.value = value
  return nv
$$ LANGUAGE plpythonu;

如果没有提供返回值,Python 将返回缺省的 None 。PL/Python 将把 None 翻译成 NULL 。

一个 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;

警告

当前,由于 Python bug #1483133 的原因,一些 Python 2.4 的调试版本(使用 --with-pydebug 选项编译)已知会让 PostgreSQL 服务器在使用迭代器返回集合时崩溃。原始的 Fedora 4 仍然包含这个臭虫,但是在生产版本的 Python 或已经修补的 Fedora 4 上没有这个问题。

全局字典 SD 可以用于在函数调用中间存储数据。这个变量是私有静态数据。全局字典 SD 是公共数据,可以在一个后端里的所有 Python 函数之间使用。但在使用时需要小心。

每个函数都在 Python 解释器里获得自己的受限制的执行对象,因此来自 myfunc 的全局数据很函数参数是 myfunc2 所看不到的。这里的例外是上面提到的 SD 字典。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文