异常处理 (PL/SQL)

缺省情况下,在 PL/SQL 程序中遇到的任何错误都将停止执行程序。您可以使用 EXCEPTION 节来捕获错误以及从出错状态恢复。

异常处理程序的语法是 BEGIN 块的语法扩展。

语法

阅读语法图跳过直观语法图DECLAREdeclarationBEGIN 语句 EXCEPTIONWHENexception-conditionORconditionTHENhandler-statementEND

如果未发生错误,那么此块仅仅执行 statement 并将控制权传递到 END 之后的语句。但是,如果在执行 statement 时发生错误,那么会放弃对 statement 的进一步处理,并且控制权会传递到 EXCEPTION 部分。会在 WHEN 子句中搜索与所发生错误相匹配的第一个异常。 如果找到匹配项,那么将执行相应的 处理语句 并将控制权传递到 END 之后的语句。如果找不到匹配项,那么程序将停止执行。

如果执行 处理语句 时发生新的错误,那么它只能由外层的 EXCEPTION 子句捕获。

WHEN 子句中的异常可以是用户定义的,也可以是内置的。可在当前块或其外层块的 DECLARE 部分中定义用户定义的异常,也可在 PL/SQL 程序包的 DECLARE 部分中定义用户定义的异常。可在异常定义后面直接使用语法 PRAGMA EXCEPTION_INIT 或 PRAGMA DB2_EXCEPTION_INIT,从而指定与用户定义的异常对应的 sqlcode 或 sqlstate。

在以下示例中,DECLARE 部分包含三个指定异常的定义。块的主体是对过程 MyApp.Main 的调用。EXCEPTION 部分包含用于下列三个异常的处理程序:
  1. exception1,与 sqlcode 或 sqlstate 不相关联。
  2. exception2,与 sqlcode -942(未定义名称)相关联。
  3. exception3,与 sqlstate 42601(语法错误)相关联。
DECLARE
  exception1 EXCEPTION;
  exception2 EXCEPTION;
  PRAGMA EXCEPTION_INIT(exception2,-942);
  exception3 EXCEPTION;
  PRAGMA DB2_EXCEPTION_INIT(exception3,'42601');
BEGIN      
  MyApp.Main(100);
EXCEPTION
  WHEN exception1 THEN
      DBMS_OUTPUT.PUT_LINE('User-defined exception1 caught');
  WHEN exception2 THEN
      DBMS_OUTPUT.PUT_LINE('User-defined exception2 (Undefined name) caught');
  WHEN exception3 THEN
      DBMS_OUTPUT.PUT_LINE('User-defined exception3 (Syntax error) caught');
END   
注: 数据服务器会接受有限数目的 Oracle sqlcode 作为 PRAGMA EXCEPTION_INIT 的自变量。请参阅 Oracle-IBM Db2 on Cloud、IBM Db2 Warehouse on Cloud 和 IBM Db2 Warehouse 错误映射 (PL/SQL),以获取完整列表。

当捕获了使用 PRAGMA EXCEPTION_INIT 初始化的异常时,由 SQLCODE 函数返回的值是与该异常相关联的 sqlcode,而不是 Oracle 值。在以上示例中,当捕获了 exception2 时,由 SQLCODE 返回的值将为 -204,它是与 Oracle sqlcode -942 对应的 sqlcode。如果 Oracle- 错误映射表中未列示在 PRAGMA EXCEPTION_INIT 中指定的 Oracle sqlcode,那么编译失败。可通过执行下列操作来避免发生此情况:将 PRAGMA EXCEPTION_INIT 替换为 PRAGMA DB2_EXCEPTION_INIT,并且指定与要识别的错误对应的 sqlstate。

表 1 对可使用的内置异常进行了概括。特殊异常名称 OTHERS 与每个异常都相匹配。条件名不区分大小写。
表 1. 内置异常名称
异常名称 描述
CASE_NOT_FOUND 在 CASE 语句中,没有任何情况求值为“true”,并且没有 ELSE 条件。
CURSOR_ALREADY_OPEN 试图打开已打开的游标。
DUP_VAL_ON_INDEX 索引键有重复的值。
INVALID_CURSOR 试图访问未打开的游标。
INVALID_NUMBER 数字值无效。
LOGIN_DENIED 用户名或密码无效。
NO_DATA_FOUND 没有满足选择标准的行。
NOT_LOGGED_ON 不存在数据库连接。
OTHERS 表示任何未被异常节中的先前条件捕获的异常。
SUBSCRIPT_BEYOND_COUNT 数组下标超出范围或不存在。
SUBSCRIPT_OUTSIDE_LIMIT 数组下标表达式的数据类型无法指定给数组下标类型。
TOO_MANY_ROWS 多行满足选择标准,但只允许返回一行。
VALUE_ERROR 值无效。
ZERO_DIVIDE 试图除零。