PRAGMA EXCEPTION_INIT 将用户定义的错误代码与异常相关联。PRAGMA EXCEPTION_INIT 声明可包含在任何块、子块或包中。只能在声明异常后将错误代码分配给该异常(使用 PRAGMA EXCEPTION_INIT)。PRAGMA EXCEPTION_INIT 声明的格式如下:

PRAGMA EXCEPTION_INIT(exception_name,
                      {exception_number | exception_code})

其中:

  • exception_name 是关联异常的名称。
  • Exception_number是用户定义的错误代码,与 pragma 关联。如果您指定未映射的 exception_number,服务器将返回一条警告。
  • Exception_code 是预定义异常的名称。有关有效异常的完整列表,请参见Postgres 核心文档

用户定义的异常提供了一个示例,其中演示了如何在包中声明用户定义的异常。以下示例使用了相同的基本结构,但新增了 PRAGMA EXCEPTION_INIT 声明:

CREATE OR REPLACE PACKAGE ar AS
  overdrawn EXCEPTION;
  PRAGMA EXCEPTION_INIT (overdrawn, -20100);
  PROCEDURE check_balance(p_balance NUMBER, p_amount NUMBER);
END;

CREATE OR REPLACE PACKAGE BODY ar AS
   PROCEDURE check_balance(p_balance NUMBER, p_amount  NUMBER)
   IS
   BEGIN
       IF (p_amount > p_balance) THEN
         RAISE overdrawn;
       END IF;
    END;

以下存储过程 (purchase) 调用 check_balance 存储过程。如果 p_amount 大于 p_balance,则 check_balance 会引发异常;purchase 会捕获 ar.overdrawn 异常。

CREATE PROCEDURE purchase(customerID int, amount NUMERIC)
AS
  BEGIN
     ar.check_ balance(getcustomerbalance(customerid), amount);
       record_purchase(customerid, amount);
  EXCEPTION
     WHEN ar.overdrawn THEN
      DBMS_OUTPUT.PUT_LINE ('This account is overdrawn.');
      DBMS_OUTPUT.PUT_LINE ('SQLCode :'||SQLCODE||' '||SQLERRM );
END;

当 ar.check_balance 引发异常时,执行会跳到 purchase 中定义的异常处理程序。

EXCEPTION
     WHEN ar.overdrawn THEN
      DBMS_OUTPUT.PUT_LINE ('This account is overdrawn.');
      DBMS_OUTPUT.PUT_LINE ('SQLCode :'||SQLCODE||' '||SQLERRM );

该异常处理程序会返回一条错误消息,后跟 SQLCODE 信息:

This account is overdrawn.
SQLCODE: -20100 User-Defined Exception

以下示例演示了如何使用预定义的异常。代码为 no_data_found 异常创建了一个更有意义的名称;如果给定的客户不存在,代码会捕获异常,调用 DBMS_OUTPUT.PUT_LINE 以报告错误,然后重新引发原始异常:

CREATE OR REPLACE PACKAGE ar AS
  overdrawn EXCEPTION;
  PRAGMA EXCEPTION_INIT (unknown_customer, no_data_found);
  PROCEDURE check_balance(p_customer_id NUMBER);
END;

CREATE OR REPLACE PACKAGE BODY ar AS
   PROCEDURE check_balance(p_customer_id NUMBER)
   IS
   DECLARE
     v_balance NUMBER;
   BEGIN
     SELECT balance INTO v_balance FROM customer
       WHERE cust_id = p_customer_id;
   EXCEPTION WHEN unknown_customer THEN
     DBMS_OUTPUT.PUT_LINE('invalid customer id');
     RAISE;
   END;