PL/Python 语言模块会自动导入一个名为 plpy 的 Python 模块。此模块中的函数和常量可以在 Python 代码中以 plpy. 的形式使用。foo
plpy 模块提供多个函数来执行数据库命令
plpy.execute(query [, limit])使用查询字符串和一个可选的行限制参数调用 plpy.execute 会导致该查询被运行,并将结果返回到一个结果对象中。
如果指定了 limit 并且大于零,则 plpy.execute 最多检索 limit 行,就像查询包含 LIMIT 子句一样。省略 limit 或将其指定为零不会导致行限制。
结果对象模拟列表或字典对象。 可以通过行号和列名访问结果对象。 例如
rv = plpy.execute("SELECT * FROM my_table", 5)
从 my_table 返回最多 5 行。 如果 my_table 有一个列 my_column,则可以这样访问它
foo = rv[i]["my_column"]
可以使用内置的 len 函数获取返回的行数。
结果对象具有以下附加方法
nrows()返回命令处理的行数。 请注意,这不一定与返回的行数相同。 例如,UPDATE 命令将设置此值,但不会返回任何行(除非使用了 RETURNING)。
status()SPI_execute() 的返回值。
colnames()coltypes()coltypmods()分别返回列名的列表、列类型 OID 的列表和列的类型特定的类型修饰符的列表。
当对未生成结果集的命令(例如,不带 RETURNING 的 UPDATE 或 DROP TABLE)的结果对象调用这些方法时,这些方法会引发异常。 但是,在包含零行的结果集上使用这些方法是可以的。
__str__()定义了标准 __str__ 方法,因此例如可以使用 plpy.debug(rv) 调试查询执行结果。
可以修改结果对象。
请注意,调用 plpy.execute 会导致将整个结果集读入内存。 仅当您确定结果集相对较小时才使用该函数。 如果在获取大型结果时不想承担过多的内存使用风险,请使用 plpy.cursor 而不是 plpy.execute。
plpy.prepare(query [, argtypes])plpy.execute(plan [, arguments [, limit]])plpy.prepare 准备查询的执行计划。 使用查询字符串和参数类型列表调用它(如果查询中有参数引用)。 例如
plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", ["text"])
text 是将为 $1 传递的变量的类型。 如果您不想将任何参数传递给查询,则第二个参数是可选的。
准备好语句后,您可以使用 plpy.execute 函数的变体来运行它
rv = plpy.execute(plan, ["name"], 5)
将计划作为第一个参数传递(而不是查询字符串),并将要替换到查询中的值列表作为第二个参数传递。 如果查询不期望任何参数,则第二个参数是可选的。 第三个参数是可选的行限制,与之前一样。
或者,您可以在计划对象上调用 execute 方法
rv = plan.execute(["name"], 5)
查询参数和结果行字段在 PostgreSQL 和 Python 数据类型之间转换,如第 44.2 节中所述。
当您使用 PL/Python 模块准备计划时,它会自动保存。 阅读 SPI 文档(第 45 章)以了解这意味着什么。 为了在函数调用中有效地利用此功能,需要使用持久存储字典 SD 或 GD 之一(请参阅第 44.3 节)。 例如
CREATE FUNCTION usesavedplan() RETURNS trigger AS $$
if "plan" in SD:
plan = SD["plan"]
else:
plan = plpy.prepare("SELECT 1")
SD["plan"] = plan
# rest of function
$$ LANGUAGE plpython3u;
plpy.cursor(query)plpy.cursor(plan [, arguments])plpy.cursor 函数接受与 plpy.execute 相同的参数(行限制除外),并返回一个游标对象,该对象允许您以较小的块处理大型结果集。 与 plpy.execute 一样,可以使用查询字符串或计划对象以及参数列表,或者可以将 cursor 函数作为计划对象的方法调用。
游标对象提供了一个 fetch 方法,该方法接受一个整数参数并返回一个结果对象。 每次调用 fetch 时,返回的对象将包含下一批行,永远不会大于参数值。 一旦所有行都被用尽,fetch 将开始返回一个空的结果对象。 游标对象还提供一个迭代器接口,一次生成一行,直到所有行都被用尽。 以这种方式获取的数据不会作为结果对象返回,而是作为字典返回,每个字典对应于一个结果行。
以下是从大型表中处理数据的两种方法的示例
CREATE FUNCTION count_odd_iterator() RETURNS integer AS $$
odd = 0
for row in plpy.cursor("select num from largetable"):
if row['num'] % 2:
odd += 1
return odd
$$ LANGUAGE plpython3u;
CREATE FUNCTION count_odd_fetch(batch_size integer) RETURNS integer AS $$
odd = 0
cursor = plpy.cursor("select num from largetable")
while True:
rows = cursor.fetch(batch_size)
if not rows:
break
for row in rows:
if row['num'] % 2:
odd += 1
return odd
$$ LANGUAGE plpython3u;
CREATE FUNCTION count_odd_prepared() RETURNS integer AS $$
odd = 0
plan = plpy.prepare("select num from largetable where num % $1 <> 0", ["integer"])
rows = list(plpy.cursor(plan, [2])) # or: = list(plan.cursor([2]))
return len(rows)
$$ LANGUAGE plpython3u;
游标会自动释放。 但是,如果您想显式释放游标持有的所有资源,请使用 close 方法。 关闭后,游标将不再可以从中获取数据。
不要将 plpy.cursor 创建的对象与 Python 数据库 API 规范定义的 DB-API 游标混淆。 除了名称之外,它们没有任何共同之处。
访问数据库的函数可能会遇到错误,这将导致它们中止并引发异常。 plpy.execute 和 plpy.prepare 都可以引发 plpy.SPIError 子类的实例,默认情况下,该实例将终止该函数。 可以像处理任何其他 Python 异常一样处理此错误,方法是使用 try/except 构造。 例如
CREATE FUNCTION try_adding_joe() RETURNS text AS $$
try:
plpy.execute("INSERT INTO users(username) VALUES ('joe')")
except plpy.SPIError:
return "something went wrong"
else:
return "Joe added"
$$ LANGUAGE plpython3u;
引发的异常的实际类对应于导致错误的特定条件。 有关可能条件的列表,请参阅表 A.1。 模块 plpy.spiexceptions 为每个 PostgreSQL 条件定义一个异常类,其名称来自条件名称。 例如,division_by_zero 变为 DivisionByZero,unique_violation 变为 UniqueViolation,fdw_error 变为 FdwError,依此类推。 这些异常类中的每一个都继承自 SPIError。 这种分离使得处理特定错误更容易,例如
CREATE FUNCTION insert_fraction(numerator int, denominator int) RETURNS text AS $$
from plpy import spiexceptions
try:
plan = plpy.prepare("INSERT INTO fractions (frac) VALUES ($1 / $2)", ["int", "int"])
plpy.execute(plan, [numerator, denominator])
except spiexceptions.DivisionByZero:
return "denominator cannot equal zero"
except spiexceptions.UniqueViolation:
return "already have that fraction"
except plpy.SPIError as e:
return "other error, SQLSTATE %s" % e.sqlstate
else:
return "fraction inserted"
$$ LANGUAGE plpython3u;
请注意,由于 plpy.spiexceptions 模块中的所有异常都继承自 SPIError,因此处理它的 except 子句将捕获任何数据库访问错误。
作为处理不同错误条件的另一种方法,您可以捕获 SPIError 异常,并通过查看异常对象的 sqlstate 属性来确定 except 块内的特定错误条件。 此属性是一个字符串值,其中包含 “SQLSTATE” 错误代码。 此方法提供大致相同的功能
如果您发现文档中的任何内容不正确、与您使用特定功能的体验不符或需要进一步说明,请使用此表单报告文档问题。