# 46.7.数据库访问
PL/Python语言模块自动导入一个名为plpy
。本模块中的函数和常量在Python代码中可用,如下所示:plpy*
福*
.
# 46.7.1.数据库访问功能
这个plpy
模块提供了几个执行数据库命令的功能:
plpy。
处决(*
查询* [, *
最大行数*])
使命感plpy。处决
使用查询字符串和可选的行限制参数可以运行该查询,并在结果对象中返回结果。
结果对象模拟列表或字典对象。结果对象可以通过行号和列名访问。例如:
rv = plpy.execute("SELECT * FROM my_table", 5)
从中返回最多5行我的桌子
如果我的桌子
他有一个专栏我的专栏
,可通过以下方式访问:
foo = rv[i]["my_column"]
返回的行数可以使用内置的伦恩
作用
结果对象具有以下附加方法:
``nrows()
返回命令处理的行数。请注意,这不一定与返回的行数相同。例如使现代化
命令将设置此值,但不会返回任何行(除非返回
(已使用)。
``地位()
这个SPI_execute()
返回值。
colnames`()`
coltypes()
``coltypmods()
分别返回列名列表、列类型OID列表和列的类型特定类型修饰符列表。
当从未生成结果集的命令调用结果对象时,这些方法会引发异常,例如。,使现代化
没有返回
或升降台
.但在包含零行的结果集上使用这些方法是可以的。
``str()
标准__str__
方法的定义使得可以使用plpy。调试(rv)
.
可以修改结果对象。
请注意plpy。处决
将导致整个结果集被读入内存。只有在确定结果集相对较小时才使用该功能。如果您不想在获取大型结果时冒内存过度使用的风险,请使用plpy。光标
而不是plpy。处决
.
plpy。
准备(*
查询* [, *
argtypes*])
plpy。
处决(*
计划* [, *
论据* [, *
最大行数*]])
plpy。准备
为查询准备执行计划。如果查询中有参数引用,则使用查询字符串和参数类型列表调用它。例如:
plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", ["text"])
文本
是要传递的变量的类型$1
。如果不想向查询传递任何参数,则第二个参数是可选的。
在准备一条语句后,使用函数的变体plpy。处决
要运行它:
rv = plpy.execute(plan, ["name"], 5)
将计划作为第一个参数(而不是查询字符串)传递,并将要替换到查询中的值列表作为第二个参数传递。如果查询不需要任何参数,则第二个参数是可选的。第三个参数是与前面一样的可选行限制。
或者,你可以打电话给处决
计划对象上的方法:
rv = plan.execute(["name"], 5)
查询参数和结果行字段在PostgreSQL和Python数据类型之间转换,如中所述第46.3节.
当您使用PL/Python模块准备计划时,它会自动保存。阅读SPI文档(第47章)来描述这意味着什么。为了在函数调用中有效地利用这个功能,需要使用一个持久存储字典SD
或GD
(见第46.4节).例如:
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 plpythonu;
plpy。
光标(*
查询*)
plpy。
光标(*
计划* [, *
论据*])
这个plpy。光标
函数接受的参数与plpy。处决
(除了行限制)并返回游标对象,该对象允许您在较小的块中处理较大的结果集。就像plpy。处决
,可以使用查询字符串或带有参数列表的计划对象,或者光标
函数可以作为plan对象的方法调用。
游标对象提供了一个取来
方法,该方法接受整数参数并返回结果对象。每次你打电话取来
,返回的对象将包含下一批行,永远不会大于参数值。一旦所有的行都用完了,取来
开始返回空的结果对象。游标对象还提供迭代接口 (opens new window),一次产生一行,直到所有行都用完。以这种方式获取的数据不会作为结果对象返回,而是作为字典返回,每个字典对应一个结果行。
处理大型表中数据的两种方法的示例如下:
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 plpythonu;
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 plpythonu;
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 plpythonu;
游标会自动处理。但是,如果要显式释放游标所持有的所有资源,请使用关
方法一旦关闭,就无法再从中提取光标。
# 提示
不要混淆由创建的对象plpy。光标
使用Python数据库API规范 (opens new window).除了名字,他们没有任何共同之处。
# 46.7.2.陷阱错误
访问数据库的函数可能会遇到错误,这将导致它们中止并引发异常。二者都plpy。处决
和plpy。准备
可以引发plpy。斯皮尔罗
,默认情况下将终止该函数。通过使用尝试/例外
建筑例如:
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 plpythonu;
引发的异常的实际类对应于导致错误的特定条件。提到表A.1查看可能的条件列表。模块plpy。特例
为每个PostgreSQL条件定义一个异常类,从条件名称派生它们的名称。例如,除法
变成除法归零
, 唯一违反
变成独一无二的侵犯
, fdw_错误
变成弗德沃罗
等等每个异常类都继承自斯皮尔罗
。这种分离使处理特定错误变得更容易,例如:
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 plpythonu;
请注意,因为plpy。特例
模块继承自斯皮尔罗
一除了
子句处理它将捕获任何数据库访问错误。
作为处理不同错误条件的另一种方法,您可以捕获斯皮尔罗
异常,并确定除了
通过查看sqlstate
异常对象的属性。此属性是一个字符串值,包含“SQLSTATE”错误代码。这种方法提供了大致相同的功能