Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  GET DIAGNOSTICS Statement

15.6.7.3 获取诊断信息语句

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: {
    CLASS_ORIGIN
  | SUBCLASS_ORIGIN
  | RETURNED_SQLSTATE
  | MESSAGE_TEXT
  | MYSQL_ERRNO
  | CONSTRAINT_CATALOG
  | CONSTRAINT_SCHEMA
  | CONSTRAINT_NAME
  | CATALOG_NAME
  | SCHEMA_NAME
  | TABLE_NAME
  | COLUMN_NAME
  | CURSOR_NAME
}

condition_number, target:
    (see following discussion)

SQL 语句生成诊断信息,填充诊断区域。 获取诊断信息 语句使应用程序可以检查这些信息。(您也可以使用 显示警告显示错误 查看条件或错误。)

执行 获取诊断信息 不需要特殊权限。

关键字 CURRENT 表示从当前诊断区域检索信息。关键字 STACKED 表示从第二个诊断区域检索信息,该区域仅在当前上下文为条件处理器时可用。如果没有给出关键字,默认情况下使用当前诊断区域。

获取诊断信息 语句通常在存储程序的处理器中使用。这是一个 MySQL 扩展, 获取 [CURRENT] 诊断信息 在处理器上下文外部也被允许,以检查任何 SQL 语句的执行。例如,如果您调用 mysql 客户端程序,您可以在提示符下输入这些语句:

mysql> DROP TABLE test.no_such_table;
ERROR 1051 (42S02): Unknown table 'test.no_such_table'
mysql> GET DIAGNOSTICS CONDITION 1
         @p1 = RETURNED_SQLSTATE, @p2 = MESSAGE_TEXT;
mysql> SELECT @p1, @p2;
+-------+------------------------------------+
| @p1   | @p2                                |
+-------+------------------------------------+
| 42S02 | Unknown table 'test.no_such_table' |
+-------+------------------------------------+

该扩展仅适用于当前诊断区域,不适用于第二个诊断区域,因为 获取 STACKED 诊断信息 仅在当前上下文为条件处理器时才被允许。如果不是这种情况,将发生 获取 STACKED 诊断信息 when handler not active 错误。

有关诊断区域的描述,请参阅 第 15.6.7.7 节,“MySQL 诊断区域”。简言之,它包含两种类型的信息:

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

  • 条件信息,如错误代码和消息。如果语句引发多个条件,这部分诊断区域将为每个条件包含一个条件区域。如果语句不引发条件,这部分诊断区域为空。

对于生成三个条件的语句,诊断区域将包含语句和条件信息,如下所示:

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 ...

获取诊断信息 可以获取语句或条件信息,但不能在同一语句中获取两者:

  • 要获取语句信息,请将所需的语句项分配给目标变量。这个 获取诊断信息 实例将可用条件的数量和受影响的行数分配给用户变量 @p1@p2

    GET DIAGNOSTICS @p1 = NUMBER, @p2 = ROW_COUNT;
  • 要获取条件信息,请指定条件号并将所需的条件项分配给目标变量。这个 获取诊断信息 实例将 SQLSTATE 值和错误消息分配给用户变量 @p3@p4

    GET DIAGNOSTICS CONDITION 1
      @p3 = RETURNED_SQLSTATE, @p4 = MESSAGE_TEXT;

检索列表指定一个或多个 target = item_name 分配,逗号分隔。每个分配命名目标变量和语句信息项名称或条件信息项名称,具体取决于语句是否检索语句或条件信息。

有效的 target 设计符用于存储项目信息可以是存储过程或函数参数、存储程序局部变量使用 DECLARE 声明的,或者用户定义变量。

有效的 condition_number 设计器可以是存储过程或函数参数、存储程序局部变量声明为 DECLARE、用户定义变量、系统变量或文字。字符文字可能包括一个 _charset 介绍者。如果条件编号不在从 1 到条件区域信息数量的范围内,将出现警告。在这种情况下,警告将添加到诊断区域中,而不清除它。

当条件发生时,MySQL 不会填充所有条件项目,例如 GET DIAGNOSTICS。例如:

mysql> GET DIAGNOSTICS CONDITION 1
         @p5 = SCHEMA_NAME, @p6 = TABLE_NAME;
mysql> SELECT @p5, @p6;
+------+------+
| @p5  | @p6  |
+------+------+
|      |      |
+------+------+

在标准 SQL 中,如果有多个条件,第一个条件与之前的 SQL 语句返回的 SQLSTATE 值相关。在 MySQL 中,这不是保证的。要获取主错误,不能这样做:

GET DIAGNOSTICS CONDITION 1 @errno = MYSQL_ERRNO;

相反,首先检索条件计数,然后使用它来指定要检查的条件编号:

GET DIAGNOSTICS @cno = NUMBER;
GET DIAGNOSTICS CONDITION @cno @errno = MYSQL_ERRNO;

有关允许的语句和条件信息项目,以及哪些项目在条件发生时填充的信息,请参阅 诊断区域信息项目

以下是一个使用 GET DIAGNOSTICS 和异常处理程序在存储过程上下文中评估插入操作的结果的示例。如果插入成功,过程使用 GET DIAGNOSTICS 获取受影响的行数。这表明您可以多次使用 GET DIAGNOSTICS 检索语句信息,只要当前诊断区域没有被清除。

CREATE PROCEDURE do_insert(value INT)
BEGIN
  -- Declare variables to hold diagnostics area information
  DECLARE code CHAR(5) DEFAULT '00000';
  DECLARE msg TEXT;
  DECLARE nrows INT;
  DECLARE result TEXT;
  -- Declare exception handler for failed insert
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
    BEGIN
      GET DIAGNOSTICS CONDITION 1
        code = RETURNED_SQLSTATE, msg = MESSAGE_TEXT;
    END;

  -- Perform the insert
  INSERT INTO t1 (int_col) VALUES(value);
  -- Check whether the insert was successful
  IF code = '00000' THEN
    GET DIAGNOSTICS nrows = ROW_COUNT;
    SET result = CONCAT('insert succeeded, row count = ',nrows);
  ELSE
    SET result = CONCAT('insert failed, error = ',code,', message = ',msg);
  END IF;
  -- Say what happened
  SELECT result;
END;

假设 t1.int_col 是一个整数列,声明为 NOT NULL。过程在插入非 NULLNULL 值时分别产生以下结果:

mysql> CALL do_insert(1);
+---------------------------------+
| result                          |
+---------------------------------+
| insert succeeded, row count = 1 |
+---------------------------------+

mysql> CALL do_insert(NULL);
+-------------------------------------------------------------------------+
| result                                                                  |
+-------------------------------------------------------------------------+
| insert failed, error = 23000, message = Column 'int_col' cannot be null |
+-------------------------------------------------------------------------+

当条件处理程序激活时,诊断区域栈将发生推送:

  • 第一个(当前)诊断区域变成了第二个(栈)诊断区域,而新的当前诊断区域被创建为其副本。

  • GET [CURRENT] DIAGNOSTICSGET STACKED DIAGNOSTICS 可以在处理程序中用于访问当前和栈诊断区域的内容。

  • 最初,两个诊断区域返回相同的结果,因此可以从当前诊断区域获取关于激活处理程序的条件信息,只要您在处理程序中不执行任何更改当前诊断区域的语句。

  • 然而,在处理程序中执行的语句可以修改当前诊断区域,根据正常规则清除和设置其内容(参阅 如何清除和填充诊断区域)。

    获取激活处理程序条件信息的更可靠方法是使用栈诊断区域,该区域不能被处理程序中的语句修改,除非是 RESIGNAL。有关当前诊断区域何时被设置和清除的信息,请参阅 第 15.6.7.7 节,“MySQL 诊断区域”

下一个示例展示了如何在处理程序中使用 GET STACKED DIAGNOSTICS 获取关于处理的异常信息,即使当前诊断区域已经被处理程序中的语句修改。

在存储过程 p() 中,我们尝试将两个值插入到包含 TEXT NOT NULL 列的表中。第一个值是一个非 NULL 字符串,第二个值是 NULL。该列禁止 NULL 值,因此第一个插入成功,但第二个插入引发异常。过程包括一个异常处理程序,该程序将尝试插入 NULL 转换为插入空字符串:

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 TEXT NOT NULL);
DROP PROCEDURE IF EXISTS p;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  -- Declare variables to hold diagnostics area information
  DECLARE errcount INT;
  DECLARE errno INT;
  DECLARE msg TEXT;
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    -- Here the current DA is nonempty because no prior statements
    -- executing within the handler have cleared it
    GET CURRENT DIAGNOSTICS CONDITION 1
      errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
    SELECT 'current DA before mapped insert' AS op, errno, msg;
    GET STACKED DIAGNOSTICS CONDITION 1
      errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
    SELECT 'stacked DA before mapped insert' AS op, errno, msg;

    -- Map attempted NULL insert to empty string insert
    INSERT INTO t1 (c1) VALUES('');

    -- Here the current DA should be empty (if the INSERT succeeded),
    -- so check whether there are conditions before attempting to
    -- obtain condition information
    GET CURRENT DIAGNOSTICS errcount = NUMBER;
    IF errcount = 0
    THEN
      SELECT 'mapped insert succeeded, current DA is empty' AS op;
    ELSE
      GET CURRENT DIAGNOSTICS CONDITION 1
        errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
      SELECT 'current DA after mapped insert' AS op, errno, msg;
    END IF ;
    GET STACKED DIAGNOSTICS CONDITION 1
      errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
    SELECT 'stacked DA after mapped insert' AS op, errno, msg;
  END;
  INSERT INTO t1 (c1) VALUES('string 1');
  INSERT INTO t1 (c1) VALUES(NULL);
END;
//
delimiter ;
CALL p();
SELECT * FROM t1;

当处理程序激活时,当前诊断区域的副本将被推送到诊断区域栈中。处理程序首先显示当前和栈诊断区域的内容,它们最初都是相同的:

+---------------------------------+-------+----------------------------+
| op                              | errno | msg                        |
+---------------------------------+-------+----------------------------+
| current DA before mapped insert |  1048 | Column 'c1' cannot be null |
+---------------------------------+-------+----------------------------+

+---------------------------------+-------+----------------------------+
| op                              | errno | msg                        |
+---------------------------------+-------+----------------------------+
| stacked DA before mapped insert |  1048 | Column 'c1' cannot be null |
+---------------------------------+-------+----------------------------+

执行GET DIAGNOSTICS语句后的语句可能会重置当前诊断区域。例如,处理程序将NULL插入映射到空字符串插入,并显示结果。新的插入成功并清除当前诊断区域,但堆栈诊断区域保持不变,仍然包含激活处理程序的条件信息:

+----------------------------------------------+
| op                                           |
+----------------------------------------------+
| mapped insert succeeded, current DA is empty |
+----------------------------------------------+

+--------------------------------+-------+----------------------------+
| op                             | errno | msg                        |
+--------------------------------+-------+----------------------------+
| stacked DA after mapped insert |  1048 | Column 'c1' cannot be null |
+--------------------------------+-------+----------------------------+

当条件处理程序结束时,其当前诊断区域从堆栈中弹出,堆栈诊断区域变为存储过程中的当前诊断区域。

在过程返回后,表中包含两行。空行来自尝试插入NULL,该插入被映射到空字符串插入:

+----------+
| c1       |
+----------+
| string 1 |
|          |
+----------+