跳到主要内容

诊断区

SQL 语句可以生成诊断区域的诊断信息。标准 SQL 包含一个诊断区域的堆栈,并包括每个嵌套的执行上下文的诊断区域。标准 SQL 还支持 GET STACKED DIAGNOSTICS 语法,用于在条件处理程序执行期间引用第二个诊断区域。本文主要介绍诊断区的结构,识别的信息项,如何清除和设置诊断区,以及诊断区如何入栈和出栈。

诊断区的结构

诊断区域包含如下两种信息:

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

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

如下示例展示了,对于引发三个条件的语句,诊断区域所包含的语句和条件信息。

Statement information:  -- 语句信息
row count
... other statement information items ... -- 其他语句信息列表
Condition area list: -- 条件区域列表
Condition area 1: -- 条件区域 1
error code for condition 1 -- 条件 1 的错误码
error message for condition 1 -- 条件 1 的错误信息
... other condition information items ... -- 其他条件信息列表
Condition area 2: -- 条件区域 2
error code for condition 2: -- 条件 2 的错误码
error message for condition 2 -- 条件 2 的错误信息
... other condition information items ... -- 其他条件信息列表
Condition area 3: -- 条件区域 3
error code for condition 3 -- 条件 3 的错误码
error message for condition 3 -- 条件 3 的错误信息
... other condition information items ... -- 其他条件信息列表

诊断区域的信息项

诊断区域包含语句和条件信息项。其中,数字项是整数,字符项的字符集是 UTF-8。没有项目可以为 NULL。如果填充诊断区域的语句未设置语句或条件信息项,则其值为 0 或空字符串,具体取决于项目的数据类型。

诊断区域包含以下语句信息:

  • NUMBER:一个整数,表示有信息的条件区域的数量。

  • ROW_COUNT:一个整数,表示受语句影响的行数。ROW_COUNTROW_COUNT() 函数具有相同的值。

诊断区域的条件信息部分包含每个条件的条件区域。条件区域使用从 1 到语句条件 NUMBER 项的值进行编号。如果 NUMBER 为 0,则没有条件区域。

标准 SQL 的每个条件区域都包含以下列表中的项目(其中 MYSQL_ERRNO 是扩展项):

  • RETURNED_SQLSTATE:指示条件的 SQLSTATE 值的字符串。

  • MESSAGE_TEXT:指示条件错误消息的字符串。

  • MYSQL_ERRNO:一个整数,表示条件的错误代码。

以上定义适用于不是由信号(即由 SIGNALRESIGNAL 语句)生成的条件。

如果 SIGNAL(或 RESIGNAL)语句填充诊断区域,则其 SET 子句可以将数据类型合法的值分配给除 RETURNED_SQLSTATE 之外的任何条件信息项。SIGNAL 还设置 RETURNED_SQLSTATE 值,该值来自 SIGNAL 语句 SQLSTATE 参数,而不是直接在其 SET 子句中设置。

SIGNAL 还将语句信息项 NUMBER 设置为 1,并将 ROW_COUNT 设置为 -1 来表示错误,否则设置为 0。

清除和填充诊断区域

非诊断 SQL 语句自动填充诊断区域,并且可以使用 SIGNALRESIGNAL 语句显式地设置诊断区的内容。可以使用 GET DIAGNOSTICS 检查诊断区域以提取指定信息,或使用 SHOW WARNINGSSHOW ERRORS 查看条件或错误。

SQL 语句清除并设置诊断区域的方式如下:

  • 当服务器在解析后开始执行语句时,它会清除诊断区域中的非诊断语句。诊断语句不会清除诊断区域。如下语句属于诊断性语句:

    • GET DIAGNOSTICS

    • SHOW ERRORS

    • SHOW WARNINGS

  • 如果语句引发了条件,则诊断区域将清除属于比其较早语句的条件。例外情况是,由 GET DIAGNOSTICSRESIGNAL 引发的条件会被添加到诊断区域而不会被清除。

所以,诊断区域的语句即使在开始执行时不会清除,也会在语句引发条件时被清除。

如下示例显示了各种语句对诊断区域的影响,并使用 SHOW WARNINGS 显示有关存储的条件信息。

示例 1:DROP TABLE 语句清除诊断区域并在条件发生时填充诊断区。

DROP TABLE IF EXISTS test.no_table_found;
Query OK, 0 rows affected, 1 warning

SHOW WARNINGS;
+-------+------+-------------------------------------+
| Level | Code | Message |
+-------+------+-------------------------------------+
| Note | 1051 | Unknown table 'test.no_table_found' |
+-------+------+-------------------------------------+
1 row in set

示例 2:SET 语句会生成错误,因此它会清除并填充诊断区域。

SET @var1 = @@var;
ERROR 1193 (HY000): Unknown system variable 'var'

SHOW WARNINGS;
+-------+------+-------------------------------+
| Level | Code | Message |
+-------+------+-------------------------------+
| Error | 1193 | Unknown system variable 'var' |
+-------+------+-------------------------------+
1 row in set

示例 3:前面示例的 SET 语句产生了一个条件,因此 1 是此时 GET DIAGNOSTICS 的唯一有效的条件编号。以下语句会生成一个告警并使用条件编号 2,该告警会添加到诊断区域而不会被清除。

GET DIAGNOSTICS CONDITION 2 @var2 = MESSAGE_TEXT;
Query OK, 0 rows affected, 1 warning

SHOW WARNINGS;
+-------+------+------------------------------+
| Level | Code | Message |
+-------+------+------------------------------+
| Error | 1193 | Unknown system variable 'var'|
| Error | 1753 | Invalid condition number |
+-------+------+------------------------------+
2 rows in set

示例 4:基于以上示例,现在诊断区域有两个条件,所以同样的 GET DIAGNOSTICS 语句会执行成功。

GET DIAGNOSTICS CONDITION 2 @var2 = MESSAGE_TEXT;
Query OK, 0 rows affected

SELECT @var2;
+---------------------------+
| @var2 |
+---------------------------+
| Invalid condition number |
+---------------------------+
1 row in set

诊断区域堆栈的工作原理

当推送到诊断区域堆栈时,第一个(当前)诊断区域成为第二个(堆栈的)诊断区域,并创建一个新的当前诊断区域作为它的副本。以下情况中,诊断区域会被压入堆栈并从堆栈中弹出:

  • 存储程序的执行

    在程序执行之前被推送到诊断区,之后再弹出诊断区域。如果存储程序在处理程序执行时结束,则可以弹出多个诊断区域。这是由于没有适当的处理程序引发异常或者由于处理程序中的 RETURN 引发的。

    然后将弹出的诊断区域中的任何告警或错误条件添加到当前诊断区域。但对于触发器,仅添加错误条件。当存储程序结束时,调用者会在其当前的诊断区域中看到这些条件。

  • 在存储程序中执行条件处理程序

    当由于条件处理程序激活而发生推送时,堆栈的诊断区域是在推送之前的当前区域(在存储程序中)。新的当前诊断区域是处理程序的当前诊断区域。GET [CURRENT] DIAGNOSTICSGET STACKED DIAGNOSTICS 可以在处理程序中用于访问当前(处理程序)和堆栈(存储程序)诊断区域的内容。最初,它们返回相同的结果,但在处理程序中执行的语句会修改当前诊断区域,根据通用规则清除来设置其内容。除了 RESIGNAL 之外,在处理程序中执行的语句不能修改堆栈的诊断区域。

    如果处理程序执行成功,则弹出当前(处理程序)诊断区域,并且堆栈(存储程序)诊断区域再次成为当前诊断区域。在处理程序执行期间添加到处理程序诊断区域的条件将被添加到当前诊断区域。

  • 执行 RESIGNAL

    在存储程序内的复合语句中执行条件处理程序期间,RESIGNAL 语句用于传递可用的错误条件信息。RESIGNAL 可能会在传递信息之前更改部分或全部信息,并修改堆栈诊断区域,详细信息请参见 RESIGNAL