13.6.7.7 MySQL 诊断区域

SQL 语句产生的诊断信息将填充诊断区域。标准 SQL 具有诊断区域堆栈,其中包含每个嵌套执行上下文的诊断区域。标准 SQL 还支持获取堆叠诊断语法,用于在条件处理程序执行期间引用第二个诊断区域。从 MySQL 5.7 开始,MySQL 支持STACKED关键字。在此之前,MySQL 不支持STACKED;有一个诊断区域,其中包含来自写入该区域的最新语句的信息。

以下讨论描述了 MySQL 中诊断区域的结构,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 ...
诊断区域信息项

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

诊断区域的语句信息部分包含以下各项:

  • NUMBER:整数,指示具有信息的条件区域的数量。

  • ROW_COUNT:整数,指示受语句影响的行数。 ROW_COUNTROW_COUNT()函数具有相同的值(请参见第 12.15 节“信息功能”)。

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

每个条件区域包含以下列 table 中的项目。除MYSQL_ERRNO外,所有项均为标准 SQL,这是 MySQL 扩展。该定义适用于不是通过 signal(即通过SIGNALRESIGNAL语句)生成的条件。对于非 signal 条件,MySQL 仅填充未描述为始终为空的条件项。signal 对条件区域的影响将在后面描述。

  • CLASS_ORIGIN:包含RETURNED_SQLSTATE值的类的字符串。如果RETURNED_SQLSTATE值以 SQL 标准文档 ISO 9075-2(SQLSTATE 24.1 节)中定义的类值开头,则CLASS_ORIGIN'ISO 9075'。否则,CLASS_ORIGIN'MySQL'

  • SUBCLASS_ORIGIN:包含RETURNED_SQLSTATE值的子类的字符串。如果CLASS_ORIGIN'ISO 9075'RETURNED_SQLSTATE'000'结尾,则SUBCLASS_ORIGIN'ISO 9075'。否则,SUBCLASS_ORIGIN'MySQL'

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

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

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

  • CONSTRAINT_CATALOGCONSTRAINT_SCHEMACONSTRAINT_NAME:指示违反约束的目录,架构和名称的字符串。他们总是空的。

  • CATALOG_NAMESCHEMA_NAMETABLE_NAMECOLUMN_NAME:用于指示与条件相关的目录,架构,table 和列的字符串。他们总是空的。

  • CURSOR_NAME:指示光标名称的字符串。这总是空的。

有关特定错误的RETURNED_SQLSTATEMESSAGE_TEXTMYSQL_ERRNO值,请参见第 B.3.1 节“服务器错误消息参考”

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

SIGNAL还设置语句信息项。它将NUMBER设置为 1.将ROW_COUNT设置为-1table 示错误,否则设置为 0.

如何清除和填充诊断区域

非诊断 SQL 语句自动填充诊断区域,并且可以使用SIGNALRESIGNAL语句显式设置其内容。可以使用GET DIAGNOSTICS检查诊断区域以提取特定项目,或者使用SHOW WARNINGSSHOW ERRORS检查诊断区域以查看情况或错误。

SQL 语句清除并设置诊断区域,如下所示:

  • 服务器在解析语句后开始执行语句时,会清除非诊断语句的诊断区域。诊断语句不会清除诊断区域。这些语句是诊断性的:

  • GET DIAGNOSTICS

  • 如果一条语句提出了条件,则清除诊断区域中属于较早语句的条件。唯一的 exception 是,由GET DIAGNOSTICSRESIGNAL引发的条件被添加到了诊断区域而不清除它。

因此,即使该语句开始执行时,通常不会清除诊断区域的语句也会清除该语句。

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

DROP TABLE语句清除诊断区域,并在条件发生时填充该区域:

mysql> DROP TABLE IF EXISTS test.no_such_table;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> SHOW WARNINGS;
+-------+------+------------------------------------+
| Level | Code | Message                            |
+-------+------+------------------------------------+
| Note  | 1051 | Unknown table 'test.no_such_table' |
+-------+------+------------------------------------+
1 row in set (0.00 sec)

SET语句生成错误,因此清除并填充了诊断区域:

mysql> SET @x = @@x;
ERROR 1193 (HY000): Unknown system variable 'x'

mysql> SHOW WARNINGS;
+-------+------+-----------------------------+
| Level | Code | Message                     |
+-------+------+-----------------------------+
| Error | 1193 | Unknown system variable 'x' |
+-------+------+-----------------------------+
1 row in set (0.00 sec)

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

mysql> GET DIAGNOSTICS CONDITION 2 @p = MESSAGE_TEXT;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+-------+------+------------------------------+
| Level | Code | Message                      |
+-------+------+------------------------------+
| Error | 1193 | Unknown system variable 'xx' |
| Error | 1753 | Invalid condition number     |
+-------+------+------------------------------+
2 rows in set (0.00 sec)

现在,诊断区域中有两个条件,因此相同的GET DIAGNOSTICS语句成功:

mysql> GET DIAGNOSTICS CONDITION 2 @p = MESSAGE_TEXT;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @p;
+--------------------------+
| @p                       |
+--------------------------+
| Invalid condition number |
+--------------------------+
1 row in set (0.01 sec)
诊断区域堆栈的工作方式

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

  • 执行存储程序

推送在程序执行之前发生,然后弹出。如果在执行处理程序时存储的程序结束,则可能弹出多个诊断区域;否则,可能会弹出多个诊断区域。发生这种情况的原因是没有适当的处理程序的异常,或者由于处理程序中的RETURN

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

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

当由于条件处理程序激活而发生推送时,堆叠的诊断区域是推送之前存储程序中当前的区域。新的当前诊断区域是处理程序的当前诊断区域。可以在处理程序中使用获取[当前]诊断获取堆叠诊断来访问当前(处理程序)和堆叠(存储的程序)诊断区域的内容。最初,它们返回相同的结果,但是在处理程序中执行的语句会修改当前的诊断区域,并根据常规规则清除并设置其内容(请参见如何清除和填充诊断区域)。除了RESIGNAL之外,不能通过在处理程序中执行的语句来修改堆叠的诊断区域。

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

RESIGNAL语句传递错误条件信息,该信息在执行条件处理程序期间在存储程序内的复合语句内可用。 RESIGNAL可能会在传递某些或全部信息之前对其进行更改,如第 13.6.7.4 节“ RESIGNAL 语句”中所述修改诊断堆栈。

诊断区域相关的系统变量

某些系统变量控制或与诊断区域的某些方面有关:

  • max_error_count控制诊断区域中条件区域的数量。如果发生的情况更多,MySQL 将静默丢弃超出条件的信息。 (由RESIGNAL添加的条件总是会添加,较旧的条件会根据需要舍弃以腾出空间。)

  • warning_counttable 示发生的条件数。这包括错误,警告和 Comments。通常,NUMBERwarning_count是相同的。但是,随着生成的条件数超过max_error_countwarning_count的值 continue 上升,而NUMBER保持在max_error_count上限,因为在诊断区域中没有存储其他条件。

  • error_counttable 示发生的错误数。该值包括“未找到”和异常条件,但不包括警告和 Comments。像warning_count一样,其值可以超过max_error_count

  • 如果sql_notes系统变量设置为 0,则不会存储音符,也不会增加warning_count

示例:如果max_error_count为 10,则诊断区域最多可以包含 10 个条件区域。假设一条语句引发 20 个条件,其中 12 个是错误。在这种情况下,诊断区域包含前 10 个条件,NUMBER为 10,warning_count为 20,error_count为 12.

直到下次尝试修改诊断区域,对max_error_count的值的更改才会生效。如果诊断区域包含 10 个条件区域,并且max_error_count设置为 5,则对诊断区域的大小或内容没有立即影响。