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
は、その情報の一部またはすべてを、渡す前に変更する可能性があります。 RESIGNAL
は SIGNAL
に関連していますが、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
に対する condition_value
と signal_information_item
の定義やルールは、SIGNAL
に対するものと同じです。 たとえば、condition_value
を SQLSTATE
値にすることができ、この値は、エラー、警告、または「見つからない」を示す場合があります。 詳細は、セクション13.6.7.5「SIGNAL ステートメント」を参照してください。
RESIGNAL
ステートメントは、どちらもオプションである condition_value
と SET
句を受け取ります。 このため、次のいくつかの使用法が考えられます。
-
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_ERRNO
、MESSAGE_TEXT
などの条件情報項目が含まれています。
診断領域のスタックがあります。 ハンドラは制御を取得すると、診断領域をスタックの最上部にプッシュするため、ハンドラの実行中に次の 2 つの診断領域があります:
最初の (現在の) 診断領域。最後の診断領域のコピーとして開始されますが、ハンドラ内の現在の診断領域を変更する最初のステートメントによって上書きされます。
ハンドラが制御を取得する前に設定された条件領域を持つ最後の (スタックされた) 診断領域。
診断領域内の条件領域の最大数は、max_error_count
システム変数の値によって決定されます。 診断領域関連のシステム変数を参照してください。
単純な 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
詳細を調べると複雑に見えますが、最終結果はきわめて有効です。ハンドラは、そのハンドラのアクティブ化を発生させた条件に関する情報を破棄することなく実行できます。
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
は、「条件を現在の診断領域にプッシュする」ことを示します。 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 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」 エラーが発生します。