SQL 语句会生成诊断信息,这些信息会填充诊断区域。标准 SQL 具有诊断区域堆栈,包含每个嵌套执行上下文的诊断区域。标准 SQL 还支持 GET STACKED DIAGNOSTICS
语法,用于在条件处理程序执行期间引用第二个诊断区域。
以下讨论描述了 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_COUNT
的值与ROW_COUNT()
函数的值相同(参见 第 14.15 节,“信息函数”)。
诊断区域的条件信息部分包含每个条件的条件区域。条件区域从 1 到 NUMBER
语句条件项的值编号。如果 NUMBER
为 0,则没有条件区域。
每个条件区域包含以下列表中的项。所有项都是标准 SQL,除了 MYSQL_ERRNO
,它是 MySQL 扩展。这些定义适用于由信号(即 SIGNAL
或 RESIGNAL
语句)以外的其他方式生成的条件。对于非信号条件,MySQL 只填充那些没有被描述为总是为空的条件项。信号对条件区域的影响将在后面描述。
CLASS_ORIGIN
:一个字符串,包含RETURNED_SQLSTATE
值的类别。如果RETURNED_SQLSTATE
值以 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_CATALOG
、CONSTRAINT_SCHEMA
、CONSTRAINT_NAME
:字符串,表示违反的约束的目录、模式和名称。它们始终为空。CATALOG_NAME
、SCHEMA_NAME
、TABLE_NAME
、COLUMN_NAME
:字符串,表示与条件相关的目录、模式、表和列。它们始终为空。CURSOR_NAME
:一个字符串,表示游标名称。这始终为空。
有关特定错误的 RETURNED_SQLSTATE
、MESSAGE_TEXT
和 MYSQL_ERRNO
值,请参见 服务器错误消息参考。
如果 SIGNAL
(或 RESIGNAL
)语句填充了诊断区域,它的 SET
子句可以将任何合法的值分配给任何条件信息项,除了 RETURNED_SQLSTATE
以外,任何合法的值都可以分配给该项数据类型。 SIGNAL
还设置 RETURNED_SQLSTATE
值,但不直接在它的 SET
子句中设置。该值来自 SIGNAL
语句的 SQLSTATE
参数。
SIGNAL
还设置语句信息项。它将 NUMBER
设置为 1。它将 ROW_COUNT
设置为错误为 -1,否则为 0。
非诊断 SQL 语句会自动填充诊断区域,其内容可以用 SIGNAL
和 RESIGNAL
语句显式设置。可以用 GET DIAGNOSTICS
检查诊断区域以提取特定项,或者用 SHOW WARNINGS
或 SHOW ERRORS
查看条件或错误。
SQL 语句以如下方式清除和设置诊断区域
当服务器在解析语句后开始执行它时,它会为非诊断语句清除诊断区域。诊断语句不会清除诊断区域。这些语句是诊断语句
如果语句引发条件,则诊断区域会清除属于先前语句的条件。例外情况是,由
GET DIAGNOSTICS
和RESIGNAL
引发的条件会添加到诊断区域,而不会清除它。
因此,即使是那些在开始执行时通常不清除诊断区域的语句,如果语句引发条件,也会清除它。
以下示例展示了各种语句对诊断区域的影响,使用 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
造成的。然后,弹出的诊断区域中的任何警告或错误条件都会添加到当前诊断区域,但对于触发器,只有错误会被添加。当存储程序结束时,调用者会在其当前诊断区域中看到这些条件。
在存储程序中执行条件处理程序
当由于条件处理程序激活而发生推送时,堆栈诊断区域是在推送之前存储程序中当前的区域。新的现在是当前的诊断区域是处理程序的当前诊断区域。
GET [CURRENT] DIAGNOSTICS
和GET STACKED DIAGNOSTICS
可在处理程序中使用,以访问当前(处理程序)和堆栈(存储程序)诊断区域的内容。最初,它们返回相同的结果,但处理程序中执行的语句会修改当前诊断区域,根据正常规则清除和设置其内容(参见 诊断区域如何被清除和填充)。堆栈诊断区域不能被处理程序中执行的语句修改,除了RESIGNAL
。如果处理程序成功执行,则当前(处理程序)诊断区域会被弹出,堆栈(存储程序)诊断区域再次成为当前诊断区域。在处理程序执行期间添加到处理程序诊断区域的条件将被添加到当前诊断区域。
执行
RESIGNAL
RESIGNAL
语句传递在存储程序内复合语句中执行条件处理程序期间可用的错误条件信息。RESIGNAL
可能会在传递之前更改部分或所有信息,修改诊断堆栈,如 第 15.6.7.4 节,“RESIGNAL 语句” 中所述。
某些系统变量控制或与诊断区域的某些方面相关
max_error_count
控制诊断区域中条件区域的数量。如果发生的条件数量超过此值,MySQL 会静默地丢弃多余条件的信息。(由RESIGNAL
添加的条件始终会被添加,如果需要,会丢弃较旧的条件以腾出空间。)warning_count
表示发生的条件数量。这包括错误、警告和注释。通常,NUMBER
和warning_count
是相同的。但是,当生成的条件数量超过max_error_count
时,warning_count
的值会继续上升,而NUMBER
仍然被限制在max_error_count
处,因为诊断区域中没有存储额外的条件。error_count
表示发生的错误数量。此值包括 “未找到” 和异常条件,但不包括警告和注释。与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,则不会立即影响诊断区域的大小或内容。