GET DIAGNOSTICS ステートメントにより、アプリケーションは診断領域内にあるSQLステートメントが生成した診断情報を確認できます。
構文とパラメータの説明
GET DIAGNOSTICS の実行には特別な権限は必要ありません。異常状態やエラーを確認するには、SHOW WARNINGS または SHOW ERRORS も使用できます。
GET DIAGNOSTICS ステートメントの構文は次のとおりです:
GET [CURRENT | STACKED] DIAGNOSTICS {
statement_information_item
[, statement_information_item] ...
| CONDITION condition_number
condition_information_item
[, condition_information_item] ...
}
statement_information_item:
target = statement_information_item_name
condition_information_item:
target = condition_information_item_name
statement_information_item_name: {
NUMBER
| ROW_COUNT
}
condition_information_item_name: {
RETURNED_SQLSTATE
| MESSAGE_TEXT
| MYSQL_ERRNO
}
キーワード CURRENT は、現在の診断領域から情報を取得することを示します。キーワード STACKED は、2番目の診断領域から情報を取得することを示します。この領域は、現在のコンテキストが条件ハンドラーの場合にのみ利用可能です。いずれのキーワードも指定しない場合、デフォルトは現在の診断領域です。
検索リストでは、1つ以上の target = item_name の代入等式をカンマ区切りで指定します。各代入等式は、ターゲット変数と statement_information_item_name または condition_information_item_name のインデックサー(検索する情報がステートメント情報か条件情報かに応じて決まります)を名付けます。
アイテム情報を格納するための target インデックサーは、ストアドプロシージャや関数のパラメータ、DECLARE で宣言されたストアドプログラムの局所変数、またはユーザー定義の変数にすることができます。
condition_number インデックサーは、ストアドプロシージャや関数のパラメータ、DECLARE で宣言されたストアドプログラムの局所変数、ユーザー定義変数、システム変数、またはリテラルにすることができます。条件番号が1から情報を持つ条件領域の数の範囲内にない場合、警告が発生し、その警告は診断領域に追加され、クリアされません。
GET DIAGNOSTICS ステートメントは通常、ストアドプログラム内のハンドラーで使用されます。拡張機能として、OceanBaseデータベースは GET [CURRENT] DIAGNOSTICS がハンドラーのコンテキスト外でSQLステートメントの実行状況をチェックできるようにします。例えば、OBClientクライアントプログラムを起動した場合、プロンプトに次のステートメントを入力できます:
obclient> DROP TABLE test.no_table_found;
ERROR 1051 (42S02): Unknown table 'test.no_table_found'
obclient> GET DIAGNOSTICS CONDITION 1
@c1 = RETURNED_SQLSTATE, @c2 = MESSAGE_TEXT;
Query OK, 0 rows affected
obclient> SELECT @c1, @c2;
+-------+------------------------------------+
| @c1 | @c2 |
+-------+------------------------------------+
| 42S02 | Unknown table 'test.no_table_found' |
+-------+------------------------------------+
この拡張機能は現在の診断領域にのみ適用され、2番目の診断領域には適用されません。これは、GET STACKED DIAGNOSTICS が現在のコンテキストが条件ハンドラーの場合にのみ実行されるためです。この条件を満たさない場合、GET STACKED DIAGNOSTICS when handler not active エラーが発生します。
診断領域情報の取得
一般的に、診断領域には以下の2種類の情報が含まれます:
ステートメント情報。発生した条件の数や影響を受けた行数などです。
条件情報。エラーコードやメッセージなどです。1つのステートメントが複数の条件を引き起こした場合、診断領域には各条件に対応する条件領域があります。ステートメントがいずれの条件も引き起こさなかった場合、診断領域の条件情報部分は空になります。
以下の例では、3つの条件を生成したステートメントに関する情報が診断領域に含まれています:
Statement information:
row count
... other statement information items ...
Condition area list:
Condition area 1:
error code for condition 1
error message for condition 1
... other condition information items ...
Condition area 2:
error code for condition 2:
error message for condition 2
... other condition information items ...
Condition area 3:
error code for condition 3
error message for condition 3
... other condition information items ...
診断領域の詳細については、診断領域を参照してください。
GET DIAGNOSTICS はステートメントまたは条件情報を取得できますが、同一のステートメントで両方の情報を取得することはできません:
ステートメント情報を取得するには、必要なステートメント項目をターゲット変数に格納する必要があります。以下の例では、
GET DIAGNOSTICSのインスタンスは利用可能な条件の数と影響を受けた行数をユーザー変数@c1および@c2に割り当てています:GET DIAGNOSTICS @c1 = NUMBER, @c2 = ROW_COUNT;条件情報を取得するには、条件番号を指定し、必要な条件項目をターゲット変数に格納する必要があります。以下の例では、
GET DIAGNOSTICSのインスタンスはSQLSTATE値とエラーメッセージをユーザー変数@c3および@c4に割り当てています:GET DIAGNOSTICS CONDITION 3 @c3 = RETURNED_SQLSTATE, @c4 = MESSAGE_TEXT;
条件が発生した場合でも、GET DIAGNOSTICS が認識するすべての条件項目が埋められるとは限りません。以下の例のように:
obclient> GET DIAGNOSTICS CONDITION 1
@c5 = SCHEMA_NAME, @c6 = TABLE_NAME;
obclient> SELECT @c5, @c6;
+------+------+
| @c5 | @c6 |
+------+------+
| NULL | NULL |
+------+------+
GET STACKED DIAGNOSTICSの使用
条件ハンドラーがアクティブになると、診断領域スタックにプッシュされます。最初の(現在の)診断領域が2番目の(スタック上の)診断領域となり、新しい現在の診断領域がそのコピーとして作成されます。
GET [CURRENT] DIAGNOSTICS および GET STACKED DIAGNOSTICS は、ハンドラー内で現在およびスタック上の診断領域の内容にアクセスするために使用できます。最初は、2つの診断領域が同じ結果を返します。したがって、ハンドラー内で現在の診断領域を変更するステートメントを実行しない限り、現在の診断領域からハンドラーのアクティベーション条件に関する情報を取得できます。
しかし、ハンドラー内で実行されるステートメントは現在の診断領域を変更し、一般的なルールに従ってその内容をクリアまたは設定する可能性があります。この場合、ハンドラー内で実行されるステートメント(RESIGNAL を除く)によって変更されないスタック上の診断領域を使用する方が、ハンドラーのアクティベーション条件に関する情報を取得するための信頼性の高い方法です。現在の診断領域がいつ設定およびクリアされるかについては、診断領域を参照してください。
以下の例では、現在の診断領域がハンドラーステートメントによって変更された後、ハンドラー内で GET STACKED DIAGNOSTICS を使用して処理された例外に関する情報を取得できます。
ストアドプロシージャ proc() では、TEXT NOT NULL 列を含むテーブルに2つの値を挿入しようとします。最初の値は非 NULL 文字列、2番目は NULL です。この列は NULL 値を許可しないため、最初の挿入は成功しますが、2回目は例外を引き起こします。このプロシージャには例外ハンドラーが含まれており、NULL を空文字列に挿入しようと試みます。
DROP TABLE IF EXISTS tbl1;
CREATE TABLE tbl1 (col1 TEXT NOT NULL);
DROP PROCEDURE IF EXISTS proc;
delimiter //
CREATE PROCEDURE proc ()
BEGIN
-- 診断領域情報を格納するための変数を宣言
DECLARE err_count INT;
DECLARE err_no INT;
DECLARE err_msg TEXT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
-- ここでは現在のDAは非空です。ハンドラー内で実行された先行するステートメントがそれをクリアしていないため
GET CURRENT DIAGNOSTICS CONDITION 1
err_no = MYSQL_ERRNO, err_msg = MESSAGE_TEXT;
SELECT 'current DA before mapped insert' AS op, err_no, err_msg;
GET STACKED DIAGNOSTICS CONDITION 1
err_no = MYSQL_ERRNO, err_msg = MESSAGE_TEXT;
SELECT 'stacked DA before mapped insert' AS op, err_no, err_msg;
-- NULLを空文字列に挿入しようと試みる
INSERT INTO tbl1 (col1) VALUES('');
-- ここでは、現在のDAは挿入が成功した場合は空になるはずです。
-- そのため、条件情報を取得しようとする前に、条件が存在するかどうかを確認します。
GET CURRENT DIAGNOSTICS err_count = NUMBER;
IF err_count = 0
THEN
SELECT 'mapped insert succeeded, current DA is empty' AS op;
ELSE
GET CURRENT DIAGNOSTICS CONDITION 1
err_no = MYSQL_ERRNO, err_msg = MESSAGE_TEXT;
SELECT 'current DA after mapped insert' AS op, err_no, err_msg;
END IF ;
GET STACKED DIAGNOSTICS CONDITION 1
err_no = MYSQL_ERRNO, err_msg = MESSAGE_TEXT;
SELECT 'stacked DA after mapped insert' AS op, err_no, err_msg;
END;
INSERT INTO tbl1 (col1) VALUES('string 1');
INSERT INTO tbl1 (col1) VALUES(NULL);
END;
//
delimiter ;
CALL proc();
ハンドラーがアクティブになると、現在の診断領域のコピーが診断領域スタックにプッシュされます。ハンドラーはまず、現在とスタック上の診断領域の内容を表示します。これらは最初は同じです。
+---------------------------------+--------+------------------------------+
| op | err_no | err_msg |
+---------------------------------+--------+------------------------------+
| current DA before mapped insert | 1048 | Column 'col1' cannot be null |
+---------------------------------+--------+------------------------------+
1 row in set
+---------------------------------+--------+------------------------------+
| op | err_no | err_msg |
+---------------------------------+--------+------------------------------+
| stacked DA before mapped insert | 1048 | Column 'col1' cannot be null |
+---------------------------------+--------+------------------------------+
1 row in set
GET DIAGNOSTICS ステートメントの後に実行されるステートメントは、現在の診断領域をリセットする可能性があります。例えば、ハンドラーは NULL を空文字列にマッピングして挿入し、結果を表示します。新しい挿入は成功し、現在の診断領域はクリアされますが、スタック上の診断領域は変わらず、アクティブなハンドラーの条件に関する情報を含み続けます。
+----------------------------------------------+
| op |
+----------------------------------------------+
| mapped insert succeeded, current DA is empty |
+----------------------------------------------+
1 row in set
+--------------------------------+--------+------------------------------+
| op | err_no | err_msg |
+--------------------------------+--------+------------------------------+
| stacked DA after mapped insert | 1048 | Column 'col1' cannot be null |
+--------------------------------+--------+------------------------------+
1 row in set
条件ハンドラーが終了すると、現在存在する診断領域がスタックからポップアウトされ、スタック上の診断領域がストアドプロシージャ内の現在の診断領域となります。プロシージャが戻った後、テーブルには2行が含まれます。空行は、空文字列にマッピングされた NULL の挿入を試みたことによるものです。
+----------+
| col1 |
+----------+
| string 1 |
| |
+----------+
前述の例では、現在とスタック上の診断領域から情報を取得する条件ハンドラー内の最初の2つの GET DIAGNOSTICS ステートメントは同じ値を返します。ハンドラー内で現在の診断領域をリセットするステートメントが早く実行された場合は、そうではありません。proc() を書き換えて DECLARE ステートメントをハンドラー定義の後ろに配置すると、異なる結果が得られます。
CREATE PROCEDURE proc()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
-- 診断領域情報を格納するための変数を宣言
DECLARE err_count INT;
DECLARE err_no INT;
DECLARE err_msg TEXT;
GET CURRENT DIAGNOSTICS CONDITION 1
err_no = MYSQL_ERRNO, err_msg = MESSAGE_TEXT;
SELECT 'current DA before mapped insert' AS op, err_no, err_msg;
GET STACKED DIAGNOSTICS CONDITION 1
err_no = MYSQL_ERRNO, err_msg = MESSAGE_TEXT;
SELECT 'stacked DA before mapped insert' AS op, err_no, err_msg;
END;
INSERT INTO tbl1 (col1) VALUES('string 1');
INSERT INTO tbl1 (col1) VALUES(NULL);
END;
//
...
+---------------------------------+--------+---------+
| op | err_no | err_msg |
+---------------------------------+--------+---------+
| current DA before mapped insert | NULL | NULL |
+---------------------------------+--------+---------+
1 row in set
+---------------------------------+--------+------------------------------+
| op | err_no | err_msg |
+---------------------------------+--------+------------------------------+
| stacked DA before mapped insert | 1048 | Column 'col1' cannot be null |
+---------------------------------+--------+------------------------------+
1 row in set