11.7 例外の明示的な呼出し
例外を明示的に呼び出すには、RAISE文またはRAISE_APPLICATION_ERRORプロシージャのいずれかを使用します。
ここでのトピック
11.7.1 RAISE文
RAISE文は、例外を明示的に呼び出します。例外ハンドラの外側では、例外名を指定する必要があります。例外ハンドラの内側で、例外名を省略すると、RAISE文は現行の例外を再度呼び出します。
ここでのトピック
11.7.1.1 ユーザー定義の例外のRAISE文による呼出し
例11-10のプロシージャでは、past_dueという名前の例外を宣言し、この例外をRAISE文で明示的に呼び出し、例外ハンドラで処理しています。
例11-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.
11.7.1.2 内部的に定義された例外のRAISE文による呼出し
内部的に定義された例外はランタイム・システムにより暗黙的に呼び出されますが、名前が付いている場合はRAISE文を使用して明示的に呼び出すことができます。表11-3に、事前定義の名前を持つ内部的に定義された例外を示します。内部的に定義された例外にユーザーが宣言した名前を指定する方法は、「内部的に定義された例外」を参照してください。
内部的に定義された名前付き例外の例外ハンドラは、その例外の呼出しが暗黙的か明示的かに関係なく、例外を処理します。
例11-11のプロシージャでは、事前定義の例外INVALID_NUMBERが明示的または暗黙的に呼び出され、必ずINVALID_NUMBER例外ハンドラによって処理されます。
例11-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.
11.7.1.3 現行の例外のRAISE文による再呼出し
例外ハンドラでは、RAISE文を使用して処理中の例外を「再呼出し」できます。例外を再呼出しすると、外側のブロックに例外を渡してさらに処理することができます。(呼び出された例外を外側のブロックで処理できない場合は例外が伝播します。詳細は「例外の伝播」を参照してください。) 現行の例外を再呼出しする場合、例外名を指定する必要はありません。
例11-12の例外処理は、内側のブロックから開始して外側のブロックで終了します。外側のブロックで例外を宣言しているため、両方のブロックに例外名が存在し、各ブロックにこの例外専用の例外ハンドラがあります。内部ブロックが例外を呼び出すと、内部ブロックの例外ハンドラは最初の処理を実行した後にこの例外を再度呼び出し、さらに処理するために外側のブロックに渡しています。
例11-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.
11.7.2 RAISE_APPLICATION_ERRORプロシージャ
(DBMS_STANDARDパッケージで定義されている)RAISE_APPLICATION_ERRORプロシージャは、ストアド・サブプログラムまたはメソッドからのみ起動できます。このプロシージャを起動する通常の目的は、ユーザー定義の例外を呼び出してそのエラー・コードとエラー・メッセージを起動元に戻すことです。
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に置き換えられます。
例11-13の無名ブロックでは、past_dueという名前の例外を宣言し、この例外にエラー・コード-20000を代入し、ストアド・プロシージャを起動しています。このストアド・プロシージャは、エラー・コード-20000とメッセージを使用してRAISE_APPLICATION_ERRORプロシージャを起動し、制御が無名ブロックに戻ったところで例外を処理します。例外に関連付けられているメッセージを取得するために、無名ブロックの例外ハンドラがSQLERRMファンクション(詳細は、「エラー・コードとエラー・メッセージの取得」を参照)を起動しています。
例11-13 RAISE_APPLICATION_ERRORによるユーザー定義の例外の呼出し
CREATE 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.