MySQL 8.0 リファレンスマニュアル MySQL NDB Cluster 8.0 を含む

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

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

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 値は、ハンドラステートメントの実行後にハンドラがどのようなアクションを実行するかを示します。

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

条件が発生したときにサーバーがハンドラを選択する方法については、セクション13.6.7.6「ハンドラのスコープに関するルール」を参照してください。

対応するハンドラが宣言されていない条件が発生した場合、実行されるアクションはその条件のクラスによって異なります。

次の例では、重複キーエラーに対して発生する 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)

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

条件を無視するには、その条件の 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

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