Documentation Home
MySQL 8.0 リファレンスマニュアル
Download this Manual
PDF (US Ltr) - 36.1Mb
PDF (A4) - 36.2Mb


このページは機械翻訳したものです。

13.6.7.2 DECLARE ... HANDLER ステートメント

Press CTRL+C to copy
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 が実行されます。statementSET var_name = value などの単純なステートメントでも、BEGINEND を使用して記述された複合ステートメントでもかまいません (セクション13.6.1「BEGIN ... END 複合ステートメント」を参照してください)。

ハンドラ宣言は、変数または条件宣言のあとに指定する必要があります。

handler_action 値は、ハンドラステートメントの実行後にハンドラがどのようなアクションを実行するかを示します。

  • CONTINUE: 現在のプログラムの実行が続行されます。

  • EXIT: このハンドラが宣言されている BEGIN ... END 複合ステートメントの実行が終了します。 これは、この条件が内側のブロックで発生した場合にも当てはまります。

  • UNDO: サポートされていません。

condition_value for DECLARE ... HANDLER は、ハンドラをアクティブ化する特定の条件または条件のクラスを示します。 次の形式を使用できます:

  • mysql_error_code : MySQL エラーコードを示す整数リテラル (不明なテーブルを指定する 1051 など) :

    Press CTRL+C to copy
    DECLARE CONTINUE HANDLER FOR 1051 BEGIN -- body of handler END;

    MySQL エラーコード 0 はエラー条件ではなく成功を示すため、使用しないでください。 MySQL エラーコードのリストは、Server Error Message Reference を参照してください。

  • SQLSTATE [VALUE] sqlstate_value : SQLSTATE 値を示す 5 文字の文字列リテラル (不明なテーブルを指定する'42S01'など) :

    Press CTRL+C to copy
    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 値のクラスの短縮形。

    Press CTRL+C to copy
    DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN -- body of handler END;
  • NOT FOUND: '02'で始まる SQLSTATE 値のクラスの短縮形。 これは、カーソルのコンテキストに関係しており、カーソルがデータセットの最後に達したときの動作を制御するために使用します。 それ以上の行を取得できない場合は、SQLSTATE 値 '02000' で「データなし」状況が発生します。 この条件を検出するには、その条件または NOT FOUND 条件のハンドラを設定します。

    Press CTRL+C to copy
    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 値のクラスの短縮形。

    Press CTRL+C to copy
    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' のハンドラを使用します。

Press CTRL+C to copy
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)

このプロシージャーの実行後、@x3 になっていることを確認してください。これは、エラーが発生したあと、プロシージャーの最後まで実行が続行されたことを示しています。 DECLARE ... HANDLER ステートメントが存在しなかったとすると、PRIMARY KEY 制約のために 2 番目の INSERT が失敗したあとに MySQL はデフォルトのアクション (EXIT) を実行するため、SELECT @x2 を返していました。

条件を無視するには、その条件の CONTINUE ハンドラを宣言し、それを空のブロックに関連付けます。 例:

Press CTRL+C to copy
DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;

ブロックラベルのスコープには、そのブロック内で宣言されているハンドラのコードは含まれません。 そのため、ハンドラに関連付けられたステートメントは、ITERATE または LEAVE を使用して、そのハンドラ宣言を囲むブロックのラベルを参照することができません。 REPEAT ブロックに retry のラベルが含まれている次の例を考えてみます。

Press CTRL+C to copy
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 ハンドラのスコープ内にはないため、そこでの参照は無効であり、エラーが発生します。

Press CTRL+C to copy
ERROR 1308 (42000): LEAVE with no matching label: retry

ハンドラ内の外側のラベルへの参照を回避するには、次の方法のいずれかを使用します。

  • このブロックを離れるには、EXIT ハンドラを使用します。 ブロックのクリーンアップが必要ない場合は、BEGIN ... END ハンドラ本体を空にすることができます。

    Press CTRL+C to copy
    DECLARE EXIT HANDLER FOR SQLWARNING BEGIN END;

    そうでない場合は、ハンドラ本体内にクリーンアップステートメントを配置します。

    Press CTRL+C to copy
    DECLARE EXIT HANDLER FOR SQLWARNING BEGIN block cleanup statements END;
  • 実行を続行するには、CONTINUE ハンドラ内に、囲んでいるブロック内でチェックすることによってそのハンドラが呼び出されたかどうかを判定できるステータス変数を設定します。 次の例では、この目的のために変数 done を使用します。

    Press CTRL+C to copy
    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;