本章我们将讨论 PL/pgSQL 的错误和异常处理。
报告消息
使用 raise
语句可以发出消息:
级别
:指定严重性,可选值为:debug
log
notice
info
warning
exception
(默认值)
格式
:消息的字符串,其中的占位符%
将被参数的值替换- 占位符的数量必须和参数的数量一致
以下示例演示了不同级别下,显示当前时间的消息:
do $$
begin
raise info 'information message %', now() ;
raise log 'log message %', now();
raise debug 'debug message %', now();
raise warning 'warning message %', now();
raise notice 'notice message %', now();
end $$;
并非所有消息都会报告给客户端。默认情况下,PostgreSQL 仅报告 info
、warning
和 notice
级别的消息。这是由 client_min_messages
和 log_min_message
配置决定的。
抛出错误
使用 raise exception
即可抛出错误,这也是 raise
的默认级别(如果没有提供 级别
参数的话)。
raise
还可以使用以下可选子句来附加更多信息:
USING 选项 = 表达式;
选项
的可选值有:
message
:设置错误消息hint
:提供提示信息,以便容易定位错误detail
:给出有关错误的详细信息errcode
:错误代码
do $$
declare
email varchar(255) := '[email protected]';
begin
-- 检查邮箱是否重复
-- ...
-- 报告邮箱重复
raise exception '邮箱重复:%', email
using hint = '请检查邮箱地址';
end $$;
断言
ASSERT
语句是将调试检查插入到 PL/pgSQL 的实用的简便方法。语法如下:
assert 条件 [, 提示信息];
条件
:是一个布尔表达式,预期返回TRUE
。如果它的计算结果为TRUE
,则ASSERT
不执行任何操作;否则(NULL
或FALSE
),会引发assert_failure
异常提示信息
:可选参数。如果不传递该参数,PostgreSQL 使用默认的assertion failed
消息;否则使用该参数作为提示信息。
assert
应该只用于检测错误,而不是报告错误。如果要报告错误,应使用raise
通过 plpgsql.check_asserts
配置来启用或关闭断言。如果将该配置项设置为 off
,将关闭断言。
以下示例使用 assert
来检查示例数据中 film
表是否有数据:
do $$
declare
film_count integer;
begin
select count(*)
into film_count
from film;
assert film_count > 0, '没有影片';
end$$;
异常处理
当块中发生错误时,PostgreSQL 将中止该块及周围事务的执行。要从错误中恢复,可以在 BEGIN...END
块中使用 EXCEPTION
子句。
其语法如下:
<<label>>
declare
begin
statements;
exception
when condition [or condition...] then
handle_exception;
[when condition [or condition...] then
handle_exception;]
[when others then
handle_other_exceptions;
]
end;
以下示例会发生错误,因为 ID 为 2000 的电影不存在,它会抛出 no_data_found
异常。通过使用 EXCEPTION
捕获后,进行更有意义的处理:
do $$
declare
rec record;
v_film_id int = 2000;
begin
select film_id, title
into strict rec
from film
where film_id = v_film_id;
-- 捕获异常
exception
when no_data_found then
raise exception '电影 % 不存在', v_film_id;
end $$;
以下示例演示了如何处理 too_mary_rows
异常:
do $$
declare
rec record;
begin
select film_id, title
into strict rec
from film
where title LIKE 'A%';
exception
when too_many_rows then
raise exception '查询结果返回多行';
end $$;
以下示例演示了如何捕获多个异常:
do $$
declare
rec record;
v_length int = 90;
begin
select film_id, title
into strict rec
from film
where length = v_length;
exception
when sqlstate 'P0002' then
raise exception 'film with length % not found', v_length;
when sqlstate 'P0003' then
raise exception 'The with length % is not unique', v_length;
end $$;