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は空であるはずです(INSERTが成功した場合)。
-- そのため、条件情報を取得しようとする前に、条件が存在するかどうかを確認します
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