DECLAREhandler_typeHANDLER FORcondition_value[,condition_value] ...statementhandler_type: CONTINUE | EXIT | UNDOcondition_value: SQLSTATE [VALUE]sqlstate_value|condition_name| SQLWARNING | NOT FOUND | SQLEXCEPTION |mysql_error_code
DECLARE ... HANDLER
ステートメントは各々が複数の条件で処理することができるハンドラを規定します。もし、これらの条件の
1
つが起った場合、ステートメントが実行されます。statement
は、単純なステートメント
(たとえば、SET
) か、または
var_name =
valueBEGIN と
END
を使用して記述された複合ステートメントにすることができます
(項8.8.1. 「BEGIN ... END
複合ステートメント構文」 を参照)。
CONTINUE
ハンドラの場合、現在のプログラムの実行は、ハンドラステートメントの実行のあとも続行されます。EXIT
ハンドラに関しては、ハンドラが宣言された
BEGIN ... END
コンパウンドステートメントの中で実行が終了します。(これは、条件が内側にあるブロックの中に発生する場合でも同じです)。UNDO
ハンドラ型のステートメントはサポートされていません。
ハンドラがまだ宣言されていない条件がしている場合、デフォルトアクションは
EXIT となります。
DECLARE ... HANDLER の
condition_value
には、次の任意の値を指定できます。
SQLSTATE 値 (5 文字の文字列リテラル) または
MySQL エラーコード (番号)。SQLSTATE 値
'00000' または MySQL
エラーコード 0
は、エラー条件ではなく成功を示すため、使用しないでください。SQLSTATE
値および MySQL
エラーコードのリストについては、Server Error Codes and Messages
を参照してください。
すでに DECLARE ...
CONDITION
で指定されている条件名。項8.8.4.1. 「条件のための
DECLARE」
を参照してください。
SQLWARNING
は、'01' で始まる
SQLSTATE 値のクラスの短縮形です。
NOT FOUND
は、'02' で始まる
SQLSTATE
値のクラスの短縮形です。これはカーソルのコンテキストにのみ関連しており、カーソルがデータセットの最後に達したときに何が発生するかを制御するために使用されます。それ以上の行が使用できない場合は、データなしの条件が
SQLSTATE 値 02000
で発生します。この条件を検出するには、その条件
(または、NOT FOUND
条件) のハンドラを設定できます。
例が項8.8.5. 「カーソル」で紹介されています。また、この条件は、行を取り出さない
SELECT ... INTO
ステートメントでも発生します。
var_list
SQLEXCEPTION
は、'00'、'01'、または
'02' で始まらない
SQLSTATE 値のクラスの短縮形です。
例 :
mysql>CREATE TABLE test.t (s1 INT, PRIMARY KEY (s1));Query OK, 0 rows affected (0.00 sec) mysql>delimiter //mysql>CREATE PROCEDURE handlerdemo ()->BEGIN->DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;->SET @x = 1;->INSERT INTO test.t VALUES (1);->SET @x = 2;->INSERT INTO test.t VALUES (1);->SET @x = 3;->END;->//Query OK, 0 rows affected (0.00 sec) mysql>CALL handlerdemo()//Query OK, 0 rows affected (0.00 sec) mysql>SELECT @x//+------+ | @x | +------+ | 3 | +------+ 1 row in set (0.00 sec)
この例では、ハンドラを、重複キーエラーで発生する
SQLSTATE 値 '23000'
に関連付けます。プロシージャーが実行されたあと、@x
が、プロシージャーの最後まで実行が続行されたことを示す
3
になっていることに注意してください。
DECLARE ... HANDLER
ステートメントが存在しなかったとすると、PRIMARY
KEY 制約のために 2 番目の
INSERT
が失敗したあと MySQL がデフォルトパス
(EXIT)
を選択して、SELECT @x
は 2
を返していました。
条件を無視したい場合、ユーザーはそれに対して、CONTINUE
ハンドラと宣言して、それを空のブロックと関連させることができます。例
:
DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;
ハンドラに関連付けられたステートメントは、ITERATE
または
LEAVE
を使用して、ハンドラ宣言を囲むブロックのラベルを参照することができません。つまり、ブロックラベルのスコープに、そのブロック内で宣言されたハンドラのためのコードが含まれていません。REPEAT
ブロックに retry
のラベルが含まれている次の例を考えてみます。
CREATE PROCEDURE p ()
BEGIN
DECLARE i INT DEFAULT 3;
retry:
REPEAT
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
ITERATE retry; # illegal
END;
END;
IF i < 0 THEN
LEAVE retry; # legal
END IF;
SET i = i - 1;
UNTIL FALSE END REPEAT;
END;
このラベルは、ブロック内の
IF
ステートメントのスコープ内にあります。CONTINUE
ハンドラのスコープ内にはないため、そこでの参照は無効であり、エラーが発生します。
ERROR 1308 (42000): LEAVE with no matching label: retry
ハンドラで外側のラベルへの参照が使用されることを回避するには、次の方法を使用できます。
ブロックを離れるには、EXIT
ハンドラを使用します。
DECLARE EXIT HANDLER FOR SQLWARNING BEGIN END;
繰り返すには、ハンドラで、そのハンドラが呼び出されたかどうかを判定するために囲みブロック内で確認できるステータス変数を設定します。次の例では、この目的のための変数
done
を使用しています。
CREATE PROCEDURE p ()
BEGIN
DECLARE i INT DEFAULT 3;
DECLARE done INT DEFAULT FALSE;
retry:
REPEAT
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
SET done = TRUE;
END;
END;
IF NOT done AND i < 0 THEN
LEAVE retry;
END IF;
SET i = i - 1;
UNTIL FALSE END REPEAT;
END;
