DECLARE HANDLER ステートメントは、例外を処理するエラー・ハンドラーを作成します。
>>-DECLARE--+-CONTINUE-+--HANDLER FOR--| State |--Stmt--------->< '-EXIT-----' State .-<<-- , --<<------------------------------------------------. V | |------SQLSTATE--+-+-------+--' Text '----------------------+---+--| | '-VALUE-' | '---LIKE--' Text '--+------------------+---' '-ESCAPE--' Text '-'
ハンドラーを宣言する際には、有効範囲を明示的に宣言することもできますし (BEGIN...END)、暗黙的に宣言することもできます (IF ステートメントの ELSE 節など)。しかし、すべてのハンドラー宣言を、有効範囲の先頭つまり他のステートメントの前に一緒に置かなければなりません。
例外がない場合は、ハンドラーがあっても SQL プログラムの動作やパフォーマンスには影響しません。例外が起きると、WebSphere® Message Broker は例外の SQL 状態を、関係のあるハンドラーに関連した SQL 状態と比較します。この比較は、例外がノードからなくなる (この場合はハンドラーがない場合と全く同様になる) か、一致するハンドラーが検出されるまで行われます。ハンドラーは、1 つの有効範囲内で、宣言されている順序で最初のハンドラーから最後のハンドラーに向かって検索されます。有効範囲は最内部から最外部に向かって検索されます。
DECLARE... HANDLER... ステートメントで指定された SQL 状態値は、例外の SQL 状態と直接比較するか、またはワイルドカード文字を使用して比較できます。 状態値を直接比較するには、VALUE を指定するか、または条件演算子を指定しません。ワイルドカード比較を行うには、下線文字を使用して 1 文字ワイルドカードを表すかパーセント文字を使用して複数文字ワイルドカードを表し、LIKE 演算子を指定します。 ワイルドカードの方式を使用すると、漏れなくリストしなくても、一般的なタイプの例外をすべて処理できます。
一致しているハンドラーが検出されると、SQLSTATE およびその他の特殊レジスターが (このセクションで後ほど取り上げられている規則に従って) 更新され、ハンドラーのステートメントが処理されます。
ハンドラーのステートメントは単一のステートメントでなければならないので、通常は複数の他のステートメントを含む 1 つの複合ステートメント (BEGIN...END など) になります。これらの内部ステートメントに関連した特殊な動作はないので、特別な制約事項はありません。例えば、RETURN、ITERATE、または LEAVE を組み込むことができます。この場合、有効範囲自体に含まれている場合と同様の影響を、含まれているルーチンやループ構成体に及ぼします。
ハンドラーには、そのハンドラー自体の内部で起きる例外のハンドラーを含めることができます。
個々のハンドラーには、それぞれの SQLCODE、SQLSTATE、SQLNATIVEERROR、および SQLERRORTEXT 特殊レジスターがあります。これらは有効範囲入り、その値はハンドラーの最初のステートメントが実行される直前に設定されます。 これらの値は、ハンドラーの最後のステートメントが実行されるまで有効です。 SQLSTATE 値はハンドラー間で持ち越されないので、ハンドラーは個別に作成できます。
ハンドラーが例外を吸収し、例外は入力ノードに達しないので、トランザクションはロールバックされずにコミットされます。 このようにならないようにするには、ハンドラーで RESIGNAL ステートメントか THROW ステートメントを使用できます。
HANDLER で使用できる有効な SQLSTATES のリストについては、SQLSTATE 関数を参照してください。
DECLARE retryCount INTEGER 0;
DECLARE afterCount INTEGER 0;
WHILE retryCount <= 10 DO
DECLARE EXIT HANDLER FOR SQLSTATE VALUE 'U11222'
BEGIN
/* This demonstrates how to pass data to the HANDLER in the SQL
special registers */
SET OutputRoot.XMLNSC.Top.WHILE.mySQLCODE = SQLCODE;
SET OutputRoot.XMLNSC.Top.WHILE.mySQLSTATE = SQLSTATE;
SET OutputRoot.XMLNSC.Top.WHILE.mySQLNATIVEERROR = SQLNATIVEERROR;
SET OutputRoot.XMLNSC.Top.WHILE.mySQLERRORTEXT = SQLERRORTEXT;
SET retryCount = retryCount + 1;
/* If we are an EXIT HANDLER, control is now passed to back to the
WHILE statement */
END;
/* In a real scenario this could be a PROPAGATE statement, and the exception
could be thrown by a 'downstream' node. In this case the HANDLER would
normally cope with a wider range of exception, for example, using LIKE '%' */
THROW USER EXCEPTION VALUES( -1, 'U11222', 42, 'error text' );
/* This is the next statement executed if it is a CONTINUE HANDLER */
SET afterCount = afterCount + 1;
END WHILE;
SET OutputRoot.XMLNSC.Top.WHILE.retryCount = retryCount;
SET OutputRoot.XMLNSC.Top.WHILE.afterCount = afterCount;
上記の EXIT の場合、出力は次のようになります:
<Top>
<WHILE>
<mySQLCODE>-1</mySQLCODE>
<mySQLSTATE>U11222</mySQLSTATE>
<mySQLNATIVEERROR>42</mySQLNATIVEERROR>
<mySQLERRORTEXT>error text</mySQLERRORTEXT>
<retryCount>11</retryCOUNT>
<afterCount>0</afterCOUNT>
</WHILE>
</Top>
HANDLER を変更して CONTINUE (DECLARE CONTINUE HANDLER FOR SQLSTATE VALUE 'U11222') にした場合、出力は次のようになります:
<Top>
<WHILE>
<mySQLCODE>-1</mySQLCODE>
<mySQLSTATE>U11222</mySQLSTATE>
<mySQLNATIVEERROR>42</mySQLNATIVEERROR>
<mySQLERRORTEXT>error text</mySQLERRORTEXT>
<retryCount>11</retryCOUNT>
<afterCount>11</afterCOUNT>
</WHILE>
</Top>
このように、出力メッセージの afterCount の部分が異なります。-- Drop the tables so that they can be re-created with the latest definition.
-- If the program has never been run before, errors will occur because you
-- can't drop tables that don't exist. We ignore these.
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE LIKE'%' BEGIN END;
PASSTHRU 'DROP TABLE Shop.Customers' TO Database.DSN1;
PASSTHRU 'DROP TABLE Shop.Invoices' TO Database.DSN1;
PASSTHRU 'DROP TABLE Shop.Sales' TO Database.DSN1;
PASSTHRU 'DROP TABLE Shop.Parts' TO Database.DSN1;
END;