跳到主要内容

GET DIAGNOSTICS

GET DIAGNOSTICS 语句使应用程序能够检查诊断区域中 SQL 语句所生成的诊断信息。

语法与参数说明

执行 GET DIAGNOSTICS 不需要特殊权限。您也可以使用 SHOW WARNINGSSHOW 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 表示从第二个诊断区域检索信息,该区域仅在当前上下文是条件处理程序时可用。如果没有指定任何关键字,则默认为当前诊断区域。

检索列表指定一个或多个 target = item_name 赋值等式,并用逗号分隔。每个赋值等式命名一个目标变量和一个 statement_information_item_namecondition_information_item_name 指示符(取决于检索语句信息还是条件信息)。

用于存储项目信息的 target 指示符可以是存储过程或函数参数、使用 DECLARE 声明的存储程序局部变量或用户自定义的变量。

condition_number 指示符可以是存储过程或函数参数、使用 DECLARE 声明的存储程序局部变量、用户定义变量、系统变量或字面量。如果条件编号不在 1 到具有信息的条件区域数的范围内,则会出现告警,而且告警会被添加到诊断区域而不会被清除。

GET DIAGNOSTICS 语句通常用于存储程序内的处理程序中。作为扩展功能,seekdb 允许 GET [CURRENT] DIAGNOSTICS 在处理程序上下文之外检查 SQL 语句的执行情况。例如,您可以在提示符处输入以下语句:

DROP TABLE test.no_table_found;
ERROR 1051 (42S02): Unknown table 'test.no_table_found'

GET DIAGNOSTICS CONDITION 1
@c1 = RETURNED_SQLSTATE, @c2 = MESSAGE_TEXT;
Query OK, 0 rows affected

SELECT @c1, @c2;
+-------+------------------------------------+
| @c1 | @c2 |
+-------+------------------------------------+
| 42S02 | Unknown table 'test.no_table_found' |
+-------+------------------------------------+

此扩展功能仅适用于当前诊断区域,不适用于第二诊断区域,因为仅有当前上下文是条件处理程序时才会执行 GET STACKED DIAGNOSTICS。如果不满足这种情况,则会发生报错 GET STACKED DIAGNOSTICS when handler not active

获取诊断区信息

总体讲,诊断区包含如下两种信息:

  • 语句信息,例如发生的条件数量或受影响的行数。

  • 条件信息,例如错误代码和消息。如果一条语句引发多个条件,则诊断区域对每个条件都有一个对应的条件区域。如果语句未引发任何条件,则诊断区域的条件信息部分为空。

如下示例中,诊断区域对于产生三个条件的语句包含信息:

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 所识别的所有条件项。如下例所示:

GET DIAGNOSTICS CONDITION 1
@c5 = SCHEMA_NAME, @c6 = TABLE_NAME;

SELECT @c5, @c6;
+------+------+
| @c5 | @c6 |
+------+------+
| NULL | NULL |
+------+------+

使用 GET STACKED DIAGNOSTICS

当条件处理程序被激活时,会推送到诊断区域堆栈,第一个(当前)诊断区域成为第二个(堆栈)诊断区域,并创建一个新的当前诊断区域作为它的副本。

GET [CURRENT] DIAGNOSTICSGET STACKED DIAGNOSTICS 可以在处理程序中用于访问当前和堆栈的诊断区域的内容。最初,两个诊断区域返回相同的结果,因此只要您在处理程序中不执行任何更改其当前诊断区域的语句,就可以从当前诊断区域获取处理程序的激活条件的有关信息。

但是,在处理程序中执行的语句可以修改当前诊断区域,根据常用规则来清除和设置其内容。这种情况下,获取有关处理程序激活条件的信息的一种更可靠的方法是使用堆栈诊断区域,该区域不能被处理程序中执行的语句修改,除了 RESIGNAL。有关何时设置和清除当前诊断区域的信息,请参见 诊断区

如下示例中,在当前诊断区域已被处理程序语句修改之后,可以再处理程序中使用 GET STACKED DIAGNOSTICS 来获取有关已处理异常的信息。

在存储过程 proc() 中,我们尝试将两个值插入到包含 TEXT NOT NULL 列的表中。第一个值是非 NULL 字符串,第二个是 NULL。该列禁止 NULL 值,因此第一次插入成功,但第二次导致异常。该过程包括一个异常处理程序,它将尝试将 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

当条件处理程序结束时,它当前所在的诊断区域从堆栈中弹出,堆栈的诊断区域成为存储过程中的当前诊断区域。过程返回后,表中包含两行,空行是由于尝试插入映射到空字符串插入的 NULL 导致的,如下所示:

+----------+
| col1 |
+----------+
| string 1 |
| |
+----------+

在前面的示例中,从当前和堆栈的诊断区域检索信息的条件处理程序中的前两个 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