#### 13.6.7.7 MySQL 诊断区

SQL 语句生成填充诊断区域的诊断信息。标准 SQL 有一个诊断区域堆栈，其中包含每个嵌套执行上下文的诊断区域。标准 SQL 还支持[`获得叠加诊断`](get-diagnostics.html)在条件处理程序执行期间引用第二个诊断区域的语法。

下面讨论 MySQL 中诊断区的结构，MySQL 识别的信息项，语句如何清除和设置诊断区，以及诊断区如何入栈和出栈。

-   [诊断区域结构](diagnostics-area.html#diagnostics-area-structure)

-   [诊断区域信息项](diagnostics-area.html#diagnostics-area-information-items)

-   [如何清除和填充诊断区域](diagnostics-area.html#diagnostics-area-populating)

-   [诊断区域堆栈的工作原理](diagnostics-area.html#diagnostics-area-stack)

-   [诊断区域相关的系统变量](diagnostics-area.html#diagnostics-area-system-variables)

##### 诊断区域结构

诊断区域包含两种信息：

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

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

    对于产生三个条件的语句，诊断区域包含如下语句和条件信息：


```
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。没有项目可以`空值`.如果填充诊断区域的语句未设置语句或条件项，则其值为 0 或空字符串，具体取决于项数据类型。

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

-   `数字`: 一个整数，表示有信息的条件区域的数量。

-   `ROW_COUNT 行`: 一个整数，表示受语句影响的行数。`ROW_COUNT 行`具有与[`ROW_COUNT()`](information-functions.html#function_row-count)功能（见[第 12.16 节，“信息功能”](information-functions.html)）。

    诊断区域的条件信息部分包含每个条件的条件区域。条件区域从 1 到`数字`语句条件项。如果`数字`为 0，没有条件区域。

    每个条件区域都包含以下列表中的项目。所有项目都是标准 SQL，除了`MYSQL_ERRNO`，这是一个 MySQL 扩展。这些定义适用于不是由信号产生的条件（即，由[`信号`](signal.html)要么[`重新信号`](resignal.html)陈述）。对于非信号条件，MySQL 仅填充那些未描述为始终为空的条件项。信号对条件区域的影响将在后面描述。

-   `CLASS_ORIGIN`: 一个包含类的字符串`RETURNED_SQLSTATE`价值。如果`RETURNED_SQLSTATE`value 以 SQL 标准文档 ISO 9075-2（第 24.1 节，SQLSTATE）中定义的类值开头，`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_SCHEMA`,`CONSTRAINT_NAME`：指示违反约束的目录、模式和名称的字符串。它们总是空的。

-   `CATALOG_NAME`,`SCHEMA_NAME`,`TABLE_NAME`,`COLUMN_NAME`：表示与条件相关的目录、模式、表和列的字符串。它们总是空的。

-   `CURSOR_NAME`: 表示游标名称的字符串。这总是空的。

    为了`RETURNED_SQLSTATE`,`MESSAGE_TEXT`， 和`MYSQL_ERRNO`特定错误的值，请参阅[服务器错误消息参考](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html).

    如果一个[`信号`](signal.html)（要么[`重新信号`](resignal.html)) 语句填充诊断区域，其`放`子句可以分配给任何条件信息项，除了`RETURNED_SQLSTATE`对项数据类型合法的任何值。[`信号`](signal.html)还设置了`RETURNED_SQLSTATE`值，但不直接在其`放`条款。该值来自[`信号`](signal.html)陈述`SQLSTATE`争论。

[`信号`](signal.html)还设置语句信息项。它设置`数字`为 1. 它设置ROW_COUNT 行`错误为-1，否则为0。`如何清除和填充诊断区域

##### 非诊断 SQL 语句自动填充诊断区域，其内容可以使用

信号[`和`](signal.html)重新信号[`陈述。`](resignal.html)诊断区域可以检查[`得到诊断`](get-diagnostics.html)提取特定项目，或与[`显示警告`](show-warnings.html)要么[`显示错误`](show-errors.html)查看条件或错误。

SQL语句清除并设置诊断区域如下：

-   当服务器在解析后开始执行语句时，它会清除诊断区域中的非诊断语句。诊断语句不会清除诊断区域。这些陈述是诊断性的：

    -   [`得到诊断`](get-diagnostics.html)

    -   [`显示错误`](show-errors.html)

    -   [`显示警告`](show-warnings.html)

-   如果语句引发条件，则诊断区域将清除属于较早语句的条件。例外情况是由[`得到诊断`](get-diagnostics.html)和[`重新信号`](resignal.html)被添加到诊断区域而不清除它。

    因此，即使在开始执行时通常不会清除诊断区域的语句也会在语句引发条件时将其清除。

    以下示例显示了各种语句对诊断区域的影响，使用[`显示警告`](show-warnings.html)显示有关存储在那里的条件的信息。

    这[`删除表`](drop-table.html)语句清除诊断区域并在条件发生时填充它：


```
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-variable.html)语句生成错误，因此它清除并填充诊断区域：

```
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-variable.html)语句产生一个条件，所以 1 是唯一有效的条件编号[`得到诊断`](get-diagnostics.html)在此刻。以下语句使用条件编号 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.html)声明成功：

```
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.html)在处理程序中。

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

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

    当由于条件处理程序激活而发生推送时，堆叠诊断区域是在推送之前存储程序中的当前区域。新的 now-current 诊断区域是处理程序的当前诊断区域。[`获取 [当前] 诊断信息`](get-diagnostics.html)和[`获得叠加诊断`](get-diagnostics.html)可以在处理程序中使用以访问当前（处理程序）和堆叠（存储程序）诊断区域的内容。最初，它们返回相同的结果，但在处理程序中执行的语句会修改当前诊断区域，根据正常规则清除和设置其内容（参见[如何清除和填充诊断区域](diagnostics-area.html#diagnostics-area-populating)）。无法通过在处理程序中执行的语句修改堆叠的诊断区域，除非[`重新信号`](resignal.html).

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

-   执行[`重新信号`](resignal.html)

    这[`重新信号`](resignal.html)语句传递在存储程序内的复合语句中执行条件处理程序期间可用的错误条件信息。[`重新信号`](resignal.html)可能会在传递信息之前更改部分或全部信息，如中所述修改诊断堆栈[第 13.6.7.4 节，“RESIGNAL 声明”](resignal.html).

##### 诊断区域相关的系统变量

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

-   [`最大错误计数`](server-system-variables.html#sysvar_max_error_count)控制诊断区域中条件区域的数量。如果出现比这更多的条件，MySQL 会默默地丢弃多余条件的信息。（条件由[`重新信号`](resignal.html)总是添加，旧的条件被丢弃以腾出空间。）

-   [`警告计数`](server-system-variables.html#sysvar_warning_count)表示发生的条件数。这包括错误、警告和注释。一般，`数字`和[`警告计数`](server-system-variables.html#sysvar_warning_count)是相同的。但是，由于生成的条件数量超过[`最大错误计数`](server-system-variables.html#sysvar_max_error_count)， 的价值[`警告计数`](server-system-variables.html#sysvar_warning_count)继续上升而`数字`仍然限制在[`最大错误计数`](server-system-variables.html#sysvar_max_error_count)因为诊断区域中没有存储其他条件。

-   [`错误计数`](server-system-variables.html#sysvar_error_count)指示发生的错误数。此值包括“未找到”和异常情况，但不包括警告和注释。喜欢[`警告计数`](server-system-variables.html#sysvar_warning_count), 它的值可以超过[`最大错误计数`](server-system-variables.html#sysvar_max_error_count).

-   如果[`sql_notes`](server-system-variables.html#sysvar_sql_notes)系统变量设置为 0，注释不存储也不递增[`警告计数`](server-system-variables.html#sysvar_warning_count).

    示例：如果[`最大错误计数`](server-system-variables.html#sysvar_max_error_count)为 10，诊断区域最多可包含 10 个条件区域。假设一条语句引发了 20 个条件，其中 12 个是错误的。在这种情况下，诊断区域包含前 10 个条件，`数字`是 10，[`警告计数`](server-system-variables.html#sysvar_warning_count)是 20，并且[`错误计数`](server-system-variables.html#sysvar_error_count)是 12。

    值的变化[`最大错误计数`](server-system-variables.html#sysvar_max_error_count)直到下次尝试修改诊断区域时才会生效。如果诊断区域包含 10 个条件区域并且[`最大错误计数`](server-system-variables.html#sysvar_max_error_count)设置为 5，这对诊断区域的大小或内容没有直接影响。
