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


13.6.7.5 SIGNAL ステートメント

SIGNAL 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)

SIGNAL は、エラーを返すための方法です。 SIGNAL は、ハンドラ、アプリケーションの外側の部分、またはクライアントにエラー情報を提供します。 また、エラーの特性 (エラー番号、SQLSTATE 値、メッセージ) に対する制御も提供します。 SIGNAL を使用しない場合は、存在しないテーブルを意図的に参照してルーチンがエラーを返すようにする、などの回避方法に頼る必要があります。

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

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

SIGNAL の概要

SIGNAL ステートメント内の condition_value は、返されるエラー値を示します。 これは、SQLSTATE 値 (5 文字の文字列リテラル) か、または以前に DECLARE ... CONDITION で定義された名前付き条件を参照する condition_name にすることができます (セクション13.6.7.1「DECLARE ... CONDITION ステートメント」を参照してください)。

SQLSTATE 値は、エラー、警告、または見つからないを示す場合があります。 シグナルの条件情報項目で説明されているように、この値の最初の 2 文字はそのエラークラスを示します。 一部のシグナル値はステートメントを終了させます。ハンドラ、カーソル、およびステートメントに対するシグナルの影響を参照してください。

'00' は成功を示し、エラーの通知には有効でないため、SIGNAL ステートメントの SQLSTATE 値をこのような値で始めるべきではありません。 これは、SQLSTATE 値が SIGNAL ステートメントで直接、またはこのステートメントで参照されている名前付き条件のどちらで指定されている場合にも当てはまります。 この値が無効である場合は、Bad SQLSTATE エラーが発生します。

一般的な SQLSTATE 値を通知するには、'45000' を使用します。これは、未処理のユーザー定義の例外を示します。

SIGNAL ステートメントには、オプションで、複数のシグナル項目を含む SET 句が condition_information_item_name = simple_value_specification 割当てのリストにカンマで区切られて含まれます。

condition_information_item_name は、SET 句内で 1 回だけ指定できます。 そうでない場合は、Duplicate condition information item エラーが発生します。

有効な simple_value_specification 指示子は、ストアドプロシージャーやストアドファンクションのパラメータ、DECLARE で宣言されたストアドプログラムのローカル変数、ユーザー定義変数、システム変数、またはリテラルを使用して指定できます。 文字リテラルには、_charset イントロデューサを含めることができます。

許可される condition_information_item_name 値については、シグナルの条件情報項目を参照してください。

次のプロシージャーは、その入力パラメータである pval の値に応じて、エラーまたは警告を通知します。

CREATE PROCEDURE p (pval INT)
BEGIN
  DECLARE specialty CONDITION FOR SQLSTATE '45000';
  IF pval = 0 THEN
    SIGNAL SQLSTATE '01000';
  ELSEIF pval = 1 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'An error occurred';
  ELSEIF pval = 2 THEN
    SIGNAL specialty
      SET MESSAGE_TEXT = 'An error occurred';
  ELSE
    SIGNAL SQLSTATE '01000'
      SET MESSAGE_TEXT = 'A warning occurred', MYSQL_ERRNO = 1000;
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'An error occurred', MYSQL_ERRNO = 1001;
  END IF;
END;

pval が 0 である場合、'01' で始まる SQLSTATE 値は警告クラス内のシグナルであるため、p() は警告を通知します。 この警告はプロシージャーを終了させず、そのプロシージャーから戻ったあとに SHOW WARNINGS で確認できます。

pval が 1 である場合、p() はエラーを通知し、MESSAGE_TEXT 条件情報項目を設定します。 このエラーはプロシージャーを終了させ、そのテキストがエラー情報とともに返されます。

pval が 2 である場合、この場合は名前付き条件を使用して SQLSTATE 値が指定されているにもかかわらず、同じエラーが通知されます。

pval がその他の任意の値である場合、p() は最初に警告を通知し、メッセージテキストとエラー番号の条件情報項目を設定します。 この警告はプロシージャーを終了させないため、実行が続行され、そのあと p() はエラーを通知します。 このエラーはプロシージャーを終了させます。 警告によって設定されたメッセージテキストとエラー番号は、エラーによって設定された値によって置き換えられ、それがエラー情報とともに返されます。

SIGNAL は通常、ストアドプログラム内で使用されますが、これはハンドラのコンテキストの外部で許可される MySQL 拡張です。 たとえば、mysql クライアントプログラムを呼び出す場合は、プロンプトで次のステートメントのいずれかを入力できます。

SIGNAL SQLSTATE '77777';

CREATE TRIGGER t_bi BEFORE INSERT ON t
  FOR EACH ROW SIGNAL SQLSTATE '77777';

CREATE EVENT e ON SCHEDULE EVERY 1 SECOND
  DO SIGNAL SQLSTATE '77777';

SIGNAL は、次のルールに従って実行されます。

SIGNAL ステートメントが特定の SQLSTATE 値を示している場合、その値は、指定された条件を通知するために使用されます。 例:

CREATE PROCEDURE p (divisor INT)
BEGIN
  IF divisor = 0 THEN
    SIGNAL SQLSTATE '22012';
  END IF;
END;

SIGNAL ステートメントが名前付き条件を使用している場合、その条件は SIGNAL ステートメントに適用される何らかのスコープ内で宣言される必要があり、また MySQL エラー番号ではなく SQLSTATE 値を使用して定義される必要があります。 例:

CREATE PROCEDURE p (divisor INT)
BEGIN
  DECLARE divide_by_zero CONDITION FOR SQLSTATE '22012';
  IF divisor = 0 THEN
    SIGNAL divide_by_zero;
  END IF;
END;

その名前付き条件が SIGNAL ステートメントのスコープ内に存在しない場合は、Undefined CONDITION エラーが発生します。

SIGNAL が、SQLSTATE 値ではなく MySQL エラー番号で定義された名前付き条件を参照している場合は、SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE エラーが発生します。 次のステートメントを発行すると、名前付き条件が MySQL エラー番号に関連付けられているため、そのエラーが発生します。

DECLARE no_such_table CONDITION FOR 1051;
SIGNAL no_such_table;

特定の名前を持つ条件が異なるスコープで複数回宣言されている場合は、もっともローカルなスコープを持つ宣言が適用されます。 次のプロシージャーを考えてみます。

CREATE PROCEDURE p (divisor INT)
BEGIN
  DECLARE my_error CONDITION FOR SQLSTATE '45000';
  IF divisor = 0 THEN
    BEGIN
      DECLARE my_error CONDITION FOR SQLSTATE '22012';
      SIGNAL my_error;
    END;
  END IF;
  SIGNAL my_error;
END;

divisor が 0 である場合は、最初の SIGNAL ステートメントが実行されます。 もっとも内側の my_error 条件宣言が適用され、SQLSTATE '22012' が発生します。

divisor が 0 でない場合は、2 番目の SIGNAL ステートメントが実行されます。 もっとも外側の my_error 条件宣言が適用され、SQLSTATE '45000' が発生します。

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

シグナルが例外ハンドラ内で発生する場合があります。

CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SIGNAL SQLSTATE VALUE '99999'
      SET MESSAGE_TEXT = 'An error occurred';
  END;
  DROP TABLE no_such_table;
END;

CALL p()DROP TABLE ステートメントに達します。 no_such_table という名前のテーブルが存在しないため、エラーハンドラがアクティブ化されます。 エラーハンドラは元のエラー (このようなテーブルがない) を破棄し、SQLSTATE '99999' の新しいエラーとメッセージ An error occurred を作成します。

シグナルの条件情報項目

次の表は、SIGNAL (または RESIGNAL) ステートメントで設定できる診断領域条件情報項目の名前を一覧表示しています。 MySQL 拡張である MYSQL_ERRNO を除き、すべての項目が標準 SQL です。 これらの項目の詳細は、セクション13.6.7.7「MySQL の診断領域」を参照してください。

Item Name             Definition
---------             ----------
CLASS_ORIGIN          VARCHAR(64)
SUBCLASS_ORIGIN       VARCHAR(64)
CONSTRAINT_CATALOG    VARCHAR(64)
CONSTRAINT_SCHEMA     VARCHAR(64)
CONSTRAINT_NAME       VARCHAR(64)
CATALOG_NAME          VARCHAR(64)
SCHEMA_NAME           VARCHAR(64)
TABLE_NAME            VARCHAR(64)
COLUMN_NAME           VARCHAR(64)
CURSOR_NAME           VARCHAR(64)
MESSAGE_TEXT          VARCHAR(128)
MYSQL_ERRNO           SMALLINT UNSIGNED

文字項目の文字セットは UTF-8 です。

SIGNAL ステートメント内で条件情報項目に NULL を割り当てることはできません。

SIGNAL ステートメントは直接にか、または SQLSTATE 値で定義された名前付き条件を参照することによって間接的にかにかかわらず、常に SQLSTATE 値を指定します。 SQLSTATE 値の最初の 2 文字はそのクラスであり、このクラスによって、その条件情報項目のデフォルト値が決定されます。

  • クラス = '00' (成功)

    不正です。 '00' で始まる SQLSTATE 値は成功を示すため、SIGNAL には有効でありません。

  • クラス = '01' (警告)

    MESSAGE_TEXT = 'Unhandled user-defined warning condition';
    MYSQL_ERRNO = ER_SIGNAL_WARN
  • クラス = '02' (見つからない)

    MESSAGE_TEXT = 'Unhandled user-defined not found condition';
    MYSQL_ERRNO = ER_SIGNAL_NOT_FOUND
  • クラス > '02' (例外)

    MESSAGE_TEXT = 'Unhandled user-defined exception condition';
    MYSQL_ERRNO = ER_SIGNAL_EXCEPTION

正当なクラスの場合は、その他の条件情報項目が次のように設定されます。

CLASS_ORIGIN = SUBCLASS_ORIGIN = '';
CONSTRAINT_CATALOG = CONSTRAINT_SCHEMA = CONSTRAINT_NAME = '';
CATALOG_NAME = SCHEMA_NAME = TABLE_NAME = COLUMN_NAME = '';
CURSOR_NAME = '';

SIGNAL が実行されたあとにアクセスできるエラー値は、SIGNAL ステートメントによって発生した SQLSTATE 値と、MESSAGE_TEXT および MYSQL_ERRNO 項目です。 これらの値は、次の C API から取得できます。

  • mysql_sqlstate() は、SQLSTATE 値を返します。

  • mysql_errno() は、MYSQL_ERRNO 値を返します。

  • mysql_error() は、MESSAGE_TEXT 値を返します。

SQL レベルでは、SHOW WARNINGS および SHOW ERRORS からの出力に、Code および Message カラムの MYSQL_ERRNO および MESSAGE_TEXT の値が示されます。

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

ハンドラ、カーソル、およびステートメントに対するシグナルの影響

ステートメントの実行に対するシグナルの影響は、そのシグナルのクラスによって異なります。 このクラスによって、エラーの重大性が決定されます。 MySQL は、sql_mode システム変数の値を無視します。特に、厳密な SQL モードは問題になりません。 MySQL は IGNORE も無視します。SIGNAL の目的はユーザーが生成したエラーを明示的に発生させることであるため、シグナルが無視されることはありません。

次の説明で、未処理は、通知された SQLSTATE 値に対するハンドラが DECLARE ... HANDLER で定義されていないことを示します。

  • クラス = '00' (成功)

    不正です。 '00' で始まる SQLSTATE 値は成功を示すため、SIGNAL には有効でありません。

  • クラス = '01' (警告)

    warning_count システム変数の値が増やされます。 SHOW WARNINGS がシグナルを示します。 SQLWARNING ハンドラがシグナルをキャッチします。

    ストアドファンクションから警告を返すことはできません。関数を戻す RETURN ステートメントによって診断領域がクリアされるためです。 したがって、このステートメントはそこに存在する可能性のある警告をすべてクリアします (さらに、warning_count を 0 にリセットします)。

  • クラス = '02' (見つからない)

    NOT FOUND ハンドラがシグナルをキャッチします。 カーソルには影響しません。 ストアドファンクションでシグナルが処理されない場合、ステートメントは終了します。

  • クラス > '02' (例外)

    SQLEXCEPTION ハンドラがシグナルをキャッチします。 ストアドファンクションでシグナルが処理されない場合、ステートメントは終了します。

  • クラス = '40'

    通常の例外として処理されます。


関連キーワード:  ステートメント, SQLSTATE, CREATE, エラー, TABLE, 条件, シグナル, DROP, NAME, 情報