DECLARE handler_action HANDLER
FOR condition_value [, condition_value] ...
statement
handler_action: {
CONTINUE
| EXIT
| UNDO
}
condition_value: {
mysql_error_code
| SQLSTATE [VALUE] sqlstate_value
| condition_name
| SQLWARNING
| NOT FOUND
| SQLEXCEPTION
}
DECLARE ... HANDLER
ステートメントは、1 つ以上の条件を処理するハンドラを指定します。 これらの条件のいずれかが発生した場合は、指定された statement
が実行されます。statement
は SET
などの単純なステートメントでも、var_name
= value
BEGIN
と END
を使用して記述された複合ステートメントでもかまいません (セクション13.6.1「BEGIN ... END 複合ステートメント」を参照してください)。
ハンドラ宣言は、変数または条件宣言のあとに指定する必要があります。
handler_action
値は、ハンドラステートメントの実行後にハンドラがどのようなアクションを実行するかを示します。
CONTINUE
: 現在のプログラムの実行が続行されます。EXIT
: このハンドラが宣言されているBEGIN ... END
複合ステートメントの実行が終了します。 これは、この条件が内側のブロックで発生した場合にも当てはまります。UNDO
: サポートされていません。
condition_value
for DECLARE ... HANDLER
は、ハンドラをアクティブ化する特定の条件または条件のクラスを示します。 次の形式を使用できます:
-
mysql_error_code
: MySQL エラーコードを示す整数リテラル (「不明なテーブル」を指定する 1051 など) :DECLARE CONTINUE HANDLER FOR 1051 BEGIN -- body of handler END;
MySQL エラーコード 0 はエラー条件ではなく成功を示すため、使用しないでください。 MySQL エラーコードのリストは、Server Error Message Reference を参照してください。
-
SQLSTATE [VALUE]
sqlstate_value
: SQLSTATE 値を示す 5 文字の文字列リテラル (「不明なテーブル」を指定する'42S01'
など) :DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' BEGIN -- body of handler END;
'00'
で始まる SQLSTATE 値は、エラー条件ではなく成功を示すため、使用しないでください。 SQLSTATE 値のリストについては、Server Error Message Reference を参照してください。 condition_name
:DECLARE ... CONDITION
で以前に指定された条件名。 条件名は MySQL エラーコードまたは SQLSTATE 値に関連付けることができます。 セクション13.6.7.1「DECLARE ... CONDITION ステートメント」を参照してください。-
SQLWARNING
:'01'
で始まる SQLSTATE 値のクラスの短縮形。DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN -- body of handler END;
-
NOT FOUND
:'02'
で始まる SQLSTATE 値のクラスの短縮形。 これは、カーソルのコンテキストに関係しており、カーソルがデータセットの最後に達したときの動作を制御するために使用します。 それ以上の行を取得できない場合は、SQLSTATE 値'02000'
で「データなし」状況が発生します。 この条件を検出するには、その条件またはNOT FOUND
条件のハンドラを設定します。DECLARE CONTINUE HANDLER FOR NOT FOUND BEGIN -- body of handler END;
別の例については、セクション13.6.6「カーソル」 を参照してください。
NOT FOUND
条件は、行を取得しないSELECT ... INTO
ステートメントにも発生します。var_list
-
SQLEXCEPTION
:'00'
、'01'
または'02'
で始まらない SQLSTATE 値のクラスの短縮形。DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN -- body of handler END;
条件が発生したときにサーバーがハンドラを選択する方法については、セクション13.6.7.6「ハンドラのスコープに関するルール」を参照してください。
対応するハンドラが宣言されていない条件が発生した場合、実行されるアクションはその条件のクラスによって異なります。
SQLEXCEPTION
条件の場合は、EXIT
ハンドラが存在するかのように、ストアドプログラムはその条件を発生させたステートメントで終了します。 そのプログラムが別のストアドプログラムから呼び出されていた場合は、呼び出し元プログラムが、独自のハンドラに適用されるハンドラ選択ルールを使用してその条件を処理します。SQLWARNING
条件の場合は、CONTINUE
ハンドラが存在するかのように、プログラムは実行を続行します。NOT FOUND
条件では、その条件が正常に発生した場合、アクションはCONTINUE
です。SIGNAL
またはRESIGNAL
によって発生した場合、アクションはEXIT
です。
次の例では、重複キーエラーに対して発生する SQLSTATE '23000'
のハンドラを使用します。
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)
このプロシージャーの実行後、@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;
IF i < 0 THEN
LEAVE retry; # legal
END IF;
SET i = i - 1;
END;
UNTIL FALSE END REPEAT;
END;
retry
ラベルは、そのブロック内の IF
ステートメントのスコープ内にあります。 CONTINUE
ハンドラのスコープ内にはないため、そこでの参照は無効であり、エラーが発生します。
ERROR 1308 (42000): LEAVE with no matching label: retry
ハンドラ内の外側のラベルへの参照を回避するには、次の方法のいずれかを使用します。
-
このブロックを離れるには、
EXIT
ハンドラを使用します。 ブロックのクリーンアップが必要ない場合は、BEGIN ... END
ハンドラ本体を空にすることができます。DECLARE EXIT HANDLER FOR SQLWARNING BEGIN END;
そうでない場合は、ハンドラ本体内にクリーンアップステートメントを配置します。
DECLARE EXIT HANDLER FOR SQLWARNING BEGIN block cleanup statements END;
-
実行を続行するには、
CONTINUE
ハンドラ内に、囲んでいるブロック内でチェックすることによってそのハンドラが呼び出されたかどうかを判定できるステータス変数を設定します。 次の例では、この目的のために変数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; IF done OR i < 0 THEN LEAVE retry; END IF; SET i = i - 1; END; UNTIL FALSE END REPEAT; END;