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
添加的条件总是被添加, older 条件将被丢弃以腾出空间。) -
warning_count
表示发生的条件数量,包括错误、警告和注意。通常,NUMBER
和warning_count
是相同的。但是,当生成的条件数量超过max_error_count
时,warning_count
的值将继续增加,而NUMBER
将保持在max_error_count
because no additional conditions are stored in the diagnostics area. -
error_count
表示发生的错误数量。这包括 “not found” 和异常条件,但排除警告和注意。像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,那么这不会立即影响诊断区域的大小或内容。