例外の明示的な呼出し

例外を明示的に呼び出すには、RAISE文またはRAISE_APPLICATION_ERRORプロシージャのいずれかを使用します。

ここでのトピック

RAISE文

RAISE文は、例外を明示的に呼び出します。例外ハンドラの外側では、例外名を指定する必要があります。例外ハンドラの内側で、例外名を省略すると、RAISE文は現行の例外を再度呼び出します。

ここでのトピック

ユーザー定義の例外のRAISE文による呼出し

例12-10のプロシージャでは、past_dueという名前の例外を宣言し、この例外をRAISE文で明示的に呼び出し、例外ハンドラで処理しています。

例12-10 ユーザー定義の例外の宣言、呼出しおよび処理

CREATE PROCEDURE account_status (
  due_date DATE,
  today    DATE
) AUTHID DEFINER
IS
  past_due  EXCEPTION;  -- declare exception
BEGIN
  IF due_date < today THEN
    RAISE past_due;  -- explicitly raise exception
  END IF;
EXCEPTION
  WHEN past_due THEN  -- handle exception
    DBMS_OUTPUT.PUT_LINE ('Account past due.');
END;
/
 
BEGIN
  account_status (TO_DATE('01-JUL-2010', 'DD-MON-YYYY'),
                  TO_DATE('09-JUL-2010', 'DD-MON-YYYY'));
END;
/

結果:

Account past due.

内部的に定義された例外のRAISE文による呼出し

内部的に定義された例外はランタイム・システムにより暗黙的に呼び出されますが、名前が付いている場合はRAISE文を使用して明示的に呼び出すことができます。表12-3に、事前定義の名前を持つ内部的に定義された例外を示します。内部的に定義された例外にユーザーが宣言した名前を指定する方法は、「内部的に定義された例外」を参照してください。

内部的に定義された名前付き例外の例外ハンドラは、その例外の呼出しが暗黙的か明示的かに関係なく、例外を処理します。

例12-11のプロシージャでは、事前定義の例外INVALID_NUMBERが明示的または暗黙的に呼び出され、必ずINVALID_NUMBER例外ハンドラによって処理されます。

例12-11 事前定義の例外の明示的な呼出し

DROP TABLE t;
CREATE TABLE t (c NUMBER);
 
CREATE PROCEDURE p (n NUMBER) AUTHID DEFINER IS
  default_number NUMBER := 0;
BEGIN
  IF n < 0 THEN
    RAISE INVALID_NUMBER;  -- raise explicitly
  ELSE
    INSERT INTO t VALUES(TO_NUMBER('100.00', '9G999'));  -- raise implicitly
  END IF;
EXCEPTION
  WHEN INVALID_NUMBER THEN
    DBMS_OUTPUT.PUT_LINE('Substituting default value for invalid number.');
    INSERT INTO t VALUES(default_number);
END;
/
 
BEGIN
  p(-1);
END;
/
 

結果:

Substituting default value for invalid number.
 
BEGIN
  p(1);
END;
/

結果:

Substituting default value for invalid number.

現行の例外のRAISE文による再呼出し

例外ハンドラでは、RAISE文を使用して処理中の例外を「再呼出し」できます。例外を再呼出しすると、外側のブロックに例外を渡してさらに処理することができます。(呼び出された例外を外側のブロックで処理できない場合は例外が伝播します。詳細は「例外の伝播」を参照してください。)現行の例外を再呼出しする場合、例外名を指定する必要はありません。

例12-12の例外処理は、内側のブロックから開始して外側のブロックで終了します。外側のブロックで例外を宣言しているため、両方のブロックに例外名が存在し、各ブロックにこの例外専用の例外ハンドラがあります。内部ブロックが例外を呼び出すと、内部ブロックの例外ハンドラは最初の処理を実行した後にこの例外を再度呼び出し、さらに処理するために外側のブロックに渡しています。

例12-12 例外の再呼出し

DECLARE
  salary_too_high   EXCEPTION;
  current_salary    NUMBER := 20000;
  max_salary        NUMBER := 10000;
  erroneous_salary  NUMBER;
BEGIN

  BEGIN
    IF current_salary > max_salary THEN
      RAISE salary_too_high;   -- raise exception
    END IF;
  EXCEPTION
    WHEN salary_too_high THEN  -- start handling exception
      erroneous_salary := current_salary;
      DBMS_OUTPUT.PUT_LINE('Salary ' || erroneous_salary ||' is out of range.');
      DBMS_OUTPUT.PUT_LINE ('Maximum salary is ' || max_salary || '.');
      RAISE;  -- reraise current exception (exception name is optional)
  END;

EXCEPTION
  WHEN salary_too_high THEN    -- finish handling exception
    current_salary := max_salary;

    DBMS_OUTPUT.PUT_LINE (
      'Revising salary from ' || erroneous_salary ||
      ' to ' || current_salary || '.'
    );
END;
/

結果:

Salary 20000 is out of range.
Maximum salary is 10000.
Revising salary from 20000 to 10000.

RAISE_APPLICATION_ERRORプロシージャ

(DBMS_STANDARDパッケージで定義されている)RAISE_APPLICATION_ERRORプロシージャは、ストアド・サブプログラムまたはメソッドからのみ起動できます。このプロシージャを起動する通常の目的は、ユーザー定義の例外を呼び出してそのエラー・コードとエラー・メッセージを起動元に戻すことです。

RAISE_APPLICATION_ERRORプロシージャには、SUPPRESSES_WARNING_6009プラグマのマークが付いています。

セマンティクスの詳細は、「SUPPRESSES_WARNING_6009プラグマを参照してください。

RAISE_APPLICATION_ERRORを起動するには、次の構文を使用します。

RAISE_APPLICATION_ERROR (error_code, message[, {TRUE | FALSE}]);

EXCEPTION_INITプラグマを使用してerror_codeをユーザー定義の例外に代入しておく必要があります。構文は次のとおりです:

PRAGMA EXCEPTION_INIT (exception_name, error_code)

error_codeは-20000から-20999の範囲の整数で、messageは長さが2048バイト以内の文字列です。

セマンティクスの詳細は、「EXCEPTION_INITプラグマ」を参照してください。

messageは長さが2048バイト以内の文字列です。

TRUEを指定すると、PL/SQLによりerror_codeがエラー・スタックの最上位に配置されます。それ以外の場合は、PL/SQLによりエラー・スタックがerror_codeに置き換えられます。

例12-13の無名ブロックでは、past_dueという名前の例外を宣言し、この例外にエラー・コード-20000を代入し、ストアド・プロシージャを起動しています。このストアド・プロシージャは、エラー・コード-20000とメッセージを使用してRAISE_APPLICATION_ERRORプロシージャを起動し、制御が無名ブロックに戻ったところで例外を処理します。例外に関連付けられているメッセージを取得するために、無名ブロックの例外ハンドラがSQLERRMファンクション(詳細は、「エラー・コードとエラー・メッセージの取得」を参照)を起動しています。

例12-13 RAISE_APPLICATION_ERRORによるユーザー定義の例外の呼出し

CREATE OR REPLACE PROCEDURE account_status (
  due_date DATE,
  today    DATE
) AUTHID DEFINER
IS
BEGIN
  IF due_date < today THEN                   -- explicitly raise exception
    RAISE_APPLICATION_ERROR(-20000, 'Account past due.');
  END IF;
END;
/
 
DECLARE
  past_due  EXCEPTION;                       -- declare exception
  PRAGMA EXCEPTION_INIT (past_due, -20000);  -- assign error code to exception
BEGIN
  account_status (TO_DATE('01-JUL-2010', 'DD-MON-YYYY'),
                  TO_DATE('09-JUL-2010', 'DD-MON-YYYY'));   -- invoke procedure

EXCEPTION
  WHEN past_due THEN                         -- handle exception
    DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20000)));
END;
/

結果:

ORA-20000: Account past due.