例外とエラー・メッセージのサポート
NZPLSQL プロシージャーでエラーが発生した場合、プロシージャーの実行は中止され、外側のトランザクションも中止されます。 システムは、メイン・ループに戻り、クライアント・アプリケーションから次の照会を取得します。 すべての例外をキャッチすることは (特に、そのアクションがデータベースを不良な状態にしている場合には) 不可能です。
プロシージャー・ブロック内で発生したエラーをキャッチして処理するには、EXCEPTION キーワードを使用して、ブロックの最後に例外処理セクションを追加します。 エラーが発生しなかった場合、例外処理セクションは無視されます。 例外処理セクションの内部には、一致する例外および一致した場合に実行する文を指定する WHEN 節を使用して、1 つ以上の例外ハンドラーを指定できます。 EXCEPTION 文の形式は以下のとおりです。
EXCEPTION
WHEN clause THEN
statements
[ WHEN ... ]
NZPLSQL は、例外処理のために以下の 2 つの節をサポートしています。
- TRANSACTION_ABORTED
- TRANSACTION_ABORTED 節を使用して、トランザクションを中止するエラーが発生した場合に実行する文を指定します。 このような場合、続行するためには ROLLBACK が必要です。 必ず、例外処理文の最初のコマンドを ROLLBACK コマンドにしてください。
- その他
- OTHERS 節を使用して、プロシージャー・ブロック内でどのようなエラーが発生した場合にも実行する文を指定します。 SQL 構文解析エラーなどのエラーは、トランザクションを中止しないため、TRANSACTION_ABORTED 節には一致しません。
以下の例に示すように、1 つの例外ブロックに両方の節を指定することができます。 プロシージャー内でエラーが発生した場合、プロシージャー・コードは、最初に一致した例外節を使用してその節の文を実行します。 その一致節より後の節はすべて無視されます。 ベスト・プラクティスとして、OTHERS 節は最後に指定してください。この節は、どのタイプのエラーにも一致するからです。
EXCEPTION
WHEN TRANSACTION_ABORTED THEN
ROLLBACK;
statements_case1
RAISE ERROR 'Procedure failed: %', sqlerrm;
WHEN OTHERS THEN
statements_case2
RAISE NOTICE 'Caught error, continuing %', sqlerrm;
この例では、トランザクションを中止するエラーが発生した場合、TRANSACTION_ABORTED 節がトリガーされ、ストアード・プロシージャーは ROLLBACK、statements_case1 の文を実行してエラー・メッセージを生成します。 トランザクションを中止しないエラーの場合、例外処理は OTHERS 節にスキップし、ストアード・プロシージャーは、statements_case2 のセットを実行して通知メッセージを生成します。 ブロック内でエラーが発生しなかった場合、例外の文はスキップされます。
変数 SQLERRM には、キャッチされたエラー・メッセージのテキストが含まれます。 例外ブロックがない場合、例外は、呼び出しスタック内の次のストアード・プロシージャーまで伝播されます。 sproc1 が sproc2 を呼び出して例外が発生した場合、sproc2 に例外ハンドラーがなければ、システムは sproc1 のハンドラーを探します。 また、システムは、封入ブロックの宣言も確認します。
create or replace procedure sp_except01() returns BOOL LANGUAGE
NZPLSQL AS
BEGIN_PROC
DECLARE
r record;
BEGIN
<<inner>>
BEGIN
SELECT * INTO r FROM NONEXISTENT;
END;
END;
END_PROC;
create or replace procedure sp_except02() returns BOOL LANGUAGE
NZPLSQL AS
BEGIN_PROC
BEGIN
CALL sp_except01();
END;
END_PROC;
create or replace procedure sp_except03() returns BOOL LANGUAGE
NZPLSQL AS
BEGIN_PROC
BEGIN
CALL sp_except02();
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Caught exception';
END;
END_PROC;
上記の例では、例外は inner ブロックの sp_except01 で生成されます。 システムは、最初に inner ブロックの例外ハンドラーを確認しますが、例外ハンドラーは見つかりません。 コントロールは親コンテキストのプロシージャー sp_except01 に移動しますが、ここでも例外ハンドラーは見つかりません。 さらに、コントロールは sp_except02 に移動し、最後に sp_except03 移動すると、例外ハンドラーが見つかり、これを使用します。
例外がいずれのレベルでもキャッチされない場合、追加の NOTICE レベルのログ・メッセージが送信され、エラーに関する状況と発生場所 (行番号と文のタイプ、ただし RAISE EXCEPTION 文によるエラーの場合は除く) が提供されます。
CREATE PROCEDURE sp() RETURNS INTEGER LANGUAGE NZPLSQL AS
BEGIN_PROC
BEGIN
EXECUTE IMMEDIATE 'insert into NOTEXIST' || 'values(1,1)';
EXCEPTION WHEN OTHERS THEN
END;
END_PROC;
NOTEXIST がデータベースに存在しないと仮定すると、エラーは例外ハンドラーで処理されるため、照会はエラーを表示しません。
CREATE PROCEDURE sp() RETURNS INTEGER LANGUAGE NZPLSQL AS
BEGIN_PROC
BEGIN
EXECUTE IMMEDIATE 'insert into NOTEXIST' || ' values(1,1)';
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Got exception: %', SQLERRM;
END;
END_PROC;NOTICE: Got exception: ERROR: Relation 'NOTEXIST' does not exist