MySQL 8.0 リファレンスマニュアル


13.6.7.4 RESIGNAL ステートメント

RESIGNAL [condition_value]
    [SET signal_information_item
    [, signal_information_item] ...]

condition_value: {
    SQLSTATE [VALUE] sqlstate_value
  | condition_name
}

signal_information_item:
    condition_information_item_name = simple_value_specification

condition_information_item_name: {
    CLASS_ORIGIN
  | SUBCLASS_ORIGIN
  | MESSAGE_TEXT
  | MYSQL_ERRNO
  | CONSTRAINT_CATALOG
  | CONSTRAINT_SCHEMA
  | CONSTRAINT_NAME
  | CATALOG_NAME
  | SCHEMA_NAME
  | TABLE_NAME
  | COLUMN_NAME
  | CURSOR_NAME
}

condition_name, simple_value_specification:
    (see following discussion)

RESIGNAL は、ストアドプロシージャーやストアドファンクションの内部にある複合ステートメント内の条件ハンドラ、トリガー、またはイベントの実行中に使用可能なエラー条件情報を渡します。 RESIGNAL は、その情報の一部またはすべてを、渡す前に変更する可能性があります。 RESIGNALSIGNAL に関連していますが、SIGNAL のように条件を発信する代わりに、RESIGNAL は既存の条件情報を (おそらく、変更してから) 中継します。

RESIGNAL は、エラーを処理することと、エラー情報を返すことの両方を可能にします。 それ以外の場合は、ハンドラ内の SQL ステートメントを実行することによって、そのハンドラのアクティブ化を発生させた情報が破棄されます。 RESIGNAL は、指定されたハンドラが状況の一部を処理できる場合はプロシージャーの一部を短くしてから、条件を遡って別のハンドラに渡すことができます。

RESIGNAL ステートメントの実行に必要な権限はありません。

RESIGNAL のすべての形式で、現在のコンテキストが条件ハンドラである必要があります。 そうでない場合、RESIGNAL は不正であり、RESIGNAL when handler not active エラーが発生します。

診断領域から情報を取得するには、GET DIAGNOSTICS ステートメントを使用します (セクション13.6.7.3「GET DIAGNOSTICS ステートメント」を参照してください)。 診断領域については、セクション13.6.7.7「MySQL の診断領域」を参照してください。

RESIGNAL の概要

RESIGNAL に対する condition_valuesignal_information_item の定義やルールは、SIGNAL に対するものと同じです。 たとえば、condition_valueSQLSTATE 値にすることができ、この値は、エラー、警告、または見つからないを示す場合があります。 詳細は、セクション13.6.7.5「SIGNAL ステートメント」を参照してください。

RESIGNAL ステートメントは、どちらもオプションである condition_valueSET 句を受け取ります。 このため、次のいくつかの使用法が考えられます。

  • RESIGNAL のみ:

    RESIGNAL;
  • 新しいシグナル情報を含む RESIGNAL:

    RESIGNAL SET signal_information_item [, signal_information_item] ...;
  • 条件値と場合によっては新しいシグナル情報を含む RESIGNAL:

    RESIGNAL condition_value
        [SET signal_information_item [, signal_information_item] ...];

これらのユースケースはすべて、診断および条件領域の変更を発生させます。

  • 診断領域には 1 つ以上の条件領域が含まれています。

  • 条件領域には、SQLSTATE 値、MYSQL_ERRNOMESSAGE_TEXT などの条件情報項目が含まれています。

診断領域のスタックがあります。 ハンドラは制御を取得すると、診断領域をスタックの最上部にプッシュするため、ハンドラの実行中に次の 2 つの診断領域があります:

  • 最初の (現在の) 診断領域。最後の診断領域のコピーとして開始されますが、ハンドラ内の現在の診断領域を変更する最初のステートメントによって上書きされます。

  • ハンドラが制御を取得する前に設定された条件領域を持つ最後の (スタックされた) 診断領域。

診断領域内の条件領域の最大数は、max_error_count システム変数の値によって決定されます。 診断領域関連のシステム変数を参照してください。

RESIGNAL のみ

単純な RESIGNAL のみとは、エラーを変更せずに渡すことを示します。 これは最後の診断領域をリストアし、それを現在の診断領域にします。 つまり、診断領域スタックをポップします

条件をキャッチする条件ハンドラ内での RESIGNAL のみの 1 つの使用法として、ほかのいくつかのアクションを実行したあと、元の条件情報 (ハンドラに入る前に存在していた情報) を変更せずに渡す方法があります。

例:

DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SET @error_count = @error_count + 1;
    IF @a = 0 THEN RESIGNAL; END IF;
  END;
  DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
CALL p();

DROP TABLE xx ステートメントが失敗したとします。 診断領域スタックは次のようになります。

DA 1. ERROR 1051 (42S02): Unknown table 'xx'

次に、実行が EXIT ハンドラに入ります。 このハンドラは最初に、診断領域をスタックの先頭にプッシュします。これで、診断領域スタックは次のようになります。

DA 1. ERROR 1051 (42S02): Unknown table 'xx'
DA 2. ERROR 1051 (42S02): Unknown table 'xx'

この時点で、最初の (現在の) 診断領域と 2 番目の (スタックされた) 診断領域の内容は同じです。 最初の診断領域は、そのあとにハンドラ内で実行されるステートメントによって変更される可能性があります。

通常、プロシージャーステートメントは最初の診断領域をクリアします。 BEGIN は例外です。これはクリアせず、何も行いません。 SET は例外ではありません。これはクリアし、操作を実行して、成功の結果を生成します。 これで、診断領域スタックは次のようになります。

DA 1. ERROR 0000 (00000): Successful operation
DA 2. ERROR 1051 (42S02): Unknown table 'xx'

この時点で、@a = 0 の場合、RESIGNAL は診断領域スタックをポップします。これで、診断領域スタックは次のようになります。

DA 1. ERROR 1051 (42S02): Unknown table 'xx'

そして、これが呼び出し元に表示される内容です。

@a が 0 でない場合、このハンドラは単純に終了します。つまり、現在の診断領域はそれ以上使用されなくなる (処理済みになった) ため、破棄することが可能になり、スタックされた診断領域がふたたび現在の診断領域になります。 診断領域スタックは次のようになります。

DA 1. ERROR 0000 (00000): Successful operation

詳細を調べると複雑に見えますが、最終結果はきわめて有効です。ハンドラは、そのハンドラのアクティブ化を発生させた条件に関する情報を破棄することなく実行できます。

新しいシグナル情報を含む RESIGNAL

SET 句を含む RESIGNAL は新しいシグナル情報を指定するため、このステートメントは、エラーを変更してから渡すことを示します。

RESIGNAL SET signal_information_item [, signal_information_item] ...;

RESIGNAL のみと同様に、アイデアは、元の情報が出力されるように診断領域スタックをポップすることです。 RESIGNAL のみとは異なり、SET 句で指定されたものはすべて変更されます。

例:

DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SET @error_count = @error_count + 1;
    IF @a = 0 THEN RESIGNAL SET MYSQL_ERRNO = 5; END IF;
  END;
  DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
CALL p();

前の説明から、RESIGNAL のみによって、診断領域スタックが次のようになることを思い出してください。

DA 1. ERROR 1051 (42S02): Unknown table 'xx'

RESIGNAL SET MYSQL_ERRNO = 5 ステートメントでは、代わりに、スタックが次のようになります。これが呼び出し元に表示される内容です。

DA 1. ERROR 5 (42S02): Unknown table 'xx'

つまり、エラー番号だけが変更され、ほかは何も変更されません。

RESIGNAL ステートメントはシグナル情報項目のいずれかまたはすべてを変更できるため、診断領域の最初の条件領域がまったく異なっているように見えます。

条件値とオプションの新しいシグナル情報を含む RESIGNAL

条件値を含む RESIGNAL は、条件を現在の診断領域にプッシュすることを示します。 SET 句が存在する場合は、エラー情報も変更されます。

RESIGNAL condition_value
    [SET signal_information_item [, signal_information_item] ...];

この形式の RESIGNAL は最後の診断領域をリストアし、それを現在の診断領域にします。 つまり、診断領域スタックをポップします。これは、単純な RESIGNAL のみが行う動作と同じです。 ただし、条件値またはシグナル情報に応じて、診断領域も変更されます。

例:

DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SET @error_count = @error_count + 1;
    IF @a = 0 THEN RESIGNAL SQLSTATE '45000' SET MYSQL_ERRNO=5; END IF;
  END;
  DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
SET @@max_error_count = 2;
CALL p();
SHOW ERRORS;

これは前の例に似ていて、その効果も同じですが、RESIGNAL が発生した場合は、現在の条件領域が最後には異なっているように見える点が異なります。 (この条件が既存の条件を置き換えるのではなく、それに追加される理由は、条件値が使用されているためです。)

この RESIGNAL ステートメントには条件値 (SQLSTATE '45000') が含まれているため、新しい条件領域が追加され、診断領域スタックは次のようになります。

DA 1. (condition 2) ERROR 1051 (42S02): Unknown table 'xx'
      (condition 1) ERROR 5 (45000) Unknown table 'xx'

この例での CALL p()SHOW ERRORS の結果は次のとおりです。

mysql> CALL p();
ERROR 5 (45000): Unknown table 'xx'
mysql> SHOW ERRORS;
+-------+------+----------------------------------+
| Level | Code | Message                          |
+-------+------+----------------------------------+
| Error | 1051 | Unknown table 'xx'               |
| Error |    5 | Unknown table 'xx'               |
+-------+------+----------------------------------+
RESIGNAL には条件ハンドラのコンテキストが必要

RESIGNAL のすべての形式で、現在のコンテキストが条件ハンドラである必要があります。 そうでない場合、RESIGNAL は不正であり、RESIGNAL when handler not active エラーが発生します。 例:

mysql> CREATE PROCEDURE p () RESIGNAL;
Query OK, 0 rows affected (0.00 sec)

mysql> CALL p();
ERROR 1645 (0K000): RESIGNAL when handler not active

さらに難しい例を次に示します。

delimiter //
CREATE FUNCTION f () RETURNS INT
BEGIN
  RESIGNAL;
  RETURN 5;
END//
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @a=f();
  SIGNAL SQLSTATE '55555';
END//
delimiter ;
CALL p();

RESIGNAL がストアドファンクション f() 内に現れています。 f() 自体は EXIT ハンドラのコンテキスト内で呼び出されますが、f() 内での実行は独自のコンテキストを持ち、それはハンドラのコンテキストではありません。 そのため、f() 内での RESIGNAL によって、handler not active エラーが発生します。


関連キーワード:  ステートメント, RESIGNAL, 領域, 診断, CREATE, 条件, TABLE, DROP, ハンドラ, 情報