GET DIAGNOSTICS语句
GET [CURRENT |STACKED ]DIAGNOSTICS { statement_information_item [, statement_information_item] ... |CONDITION condition_number condition_information_item [, condition_information_item] ... } statement_information_item: target = statement_information_item_name condition_information_item: target = condition_information_item_name statement_information_item_name:NUMBER |ROW_COUNT condition_information_item_name: {CLASS_ORIGIN |SUBCLASS_ORIGIN |RETURNED_SQLSTATE |MESSAGE_TEXT |MYSQL_ERRNO |CONSTRAINT_CATALOG |CONSTRAINT_SCHEMA |CONSTRAINT_NAME |CATALOG_NAME |SCHEMA_NAME |TABLE_NAME |COLUMN_NAME |CURSOR_NAME } condition_number, target: (seefollowing discussion)
SQL语句产生的诊断信息将填充诊断区域。该GET DIAGNOSTICS
语句使应用程序可以检查此信息。(您也可以使用SHOW WARNINGS
或SHOW ERRORS
参见条件或错误。)
无需特殊特权即可执行GET DIAGNOSTICS
。
关键字CURRENT
意味着从当前诊断区域检索信息。关键字STACKED
意味着从第二个诊断区域检索信息,仅当当前上下文是条件处理程序时才可用。如果没有给出任何关键字,则默认为使用当前诊断区域。
该GET DIAGNOSTICS
语句通常在存储程序的处理程序中使用。这是一个MySQL扩展,GET[CURRENT] DIAGNOSTICS
允许在处理程序上下文之外检查任何SQL语句的执行。例如,如果您调用mysql客户端程序,则可以在提示符下输入以下语句:
mysql>DROP TABLE test.no_such_table; ERROR 1051 (42S02): Unknown table 'test.no_such_table' mysql>GET DIAGNOSTICS CONDITION 1 @p1 =RETURNED_SQLSTATE , @p2 =MESSAGE_TEXT ; mysql>SELECT @p1, @p2; +------- +------------------------------------ + | @p1 | @p2 | +------- +------------------------------------ + | 42S02 | Unknown table 'test.no_such_table' | +------- +------------------------------------ +
该扩展名仅适用于当前的诊断区域。它不适用于第二个诊断区域,因为GET STACKED DIAGNOSTICS
仅当当前上下文是条件处理程序时才被允许。如果不是这种情况,GET STACKED DIAGNOSTICS when handler not active
则会发生错误。
有关诊断区域的说明,请参见“ 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 ...
GET DIAGNOSTICS
可以获取语句或条件信息,但不能在同一条语句中同时获得:
要获取语句信息,请将所需的语句项检索到目标变量中。此实例
GET DIAGNOSTICS
将可用条件的数量和受影响的行数分配给用户变量@p1
和@p2
:GET DIAGNOSTICS @p1 =NUMBER , @p2 =ROW_COUNT ;要获取条件信息,请指定条件编号并将所需的条件项检索到目标变量中。此实例
GET DIAGNOSTICS
将SQLSTATE值和错误消息分配给用户变量@p3
和@p4
:GET DIAGNOSTICS CONDITION 1 @p3 =RETURNED_SQLSTATE , @p4 =MESSAGE_TEXT ;
检索列表指定一个或多个分配,以逗号分隔。每个任务名称的目标变量以及一个或标志,这取决于是否语句检索语句或条件的信息。target=item_name
statement_information_item_name
condition_information_item_name
target
用于存储项目信息的有效指示符可以是存储过程或函数参数,用声明的存储程序局部变量DECLARE
或用户定义的变量。
有效的condition_number
指示符可以是存储过程或函数参数,用声明的存储程序局部变量DECLARE
,用户定义的变量,系统变量或文字。字符文字可能包括_charset
介绍人。如果条件编号不在1到具有信息的条件区域数的范围内,则会发生警告。在这种情况下,警告会添加到诊断区域而不会清除。
发生条件时,MySQL不会填充识别的所有条件项GET DIAGNOSTICS
。例如:
mysql>GET DIAGNOSTICS CONDITION 1 @p5 =SCHEMA_NAME , @p6 =TABLE_NAME ; mysql>SELECT @p5, @p6; +------ +------ + | @p5 | @p6 | +------ +------ + | | | +------ +------ +
在标准SQL中,如果存在多个条件,则第一个条件与SQLSTATE
为先前的SQL语句返回的值有关。在MySQL中,无法保证。要获取主要错误,您不能执行以下操作:
GET DIAGNOSTICS CONDITION 1 @errno =MYSQL_ERRNO ;
相反,请先检索条件计数,然后使用它指定要检查的条件编号:
GET DIAGNOSTICS @cno =NUMBER ;GET DIAGNOSTICS CONDITION @cno @errno =MYSQL_ERRNO ;
有关允许的语句和条件信息项的信息,以及在条件发生时填充的信息,请参阅“诊断区域信息项”。
这是一个GET DIAGNOSTICS
在存储过程上下文中使用和异常处理程序来评估插入操作的结果的示例。如果插入成功,则该过程用于GET DIAGNOSTICS
获取受影响的行数。这表明GET DIAGNOSTICS
只要没有清除当前诊断区域,就可以多次使用该语句来检索有关语句的信息。
CREATE PROCEDURE do_insert(value INT)BEGIN -- Declare variables to hold diagnostics area informationDECLARE code CHAR(5)DEFAULT '00000';DECLARE msg TEXT;DECLARE nrows INT;DECLARE result TEXT; -- Declare exception handler for failed insertDECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN GET DIAGNOSTICS CONDITION 1code =RETURNED_SQLSTATE , msg =MESSAGE_TEXT ;END ; -- Perform the insertINSERT INTO t1 (int_col)VALUES (value ); -- Check whether the insert was successfulIF code = '00000'THEN GET DIAGNOSTICS nrows =ROW_COUNT ;SET result = CONCAT('insert succeeded, row count = ',nrows);ELSE SET result = CONCAT('insert failed, error = ',code ,', message = ',msg);END IF ; -- Say what happenedSELECT result;END ;
假设这t1.int_col
是一个声明为的整数列NOT NULL
。分别插入非NULL
和NULL
值时,该过程将产生以下结果:
mysql>CALL do_insert(1); +--------------------------------- + | result | +--------------------------------- + | insert succeeded, row count = 1 | +--------------------------------- + mysql>CALL do_insert(NULL); +------------------------------------------------------------------------- + | result | +------------------------------------------------------------------------- + | insert failed, error = 23000, message = Column 'int_col' cannot be null | +------------------------------------------------------------------------- +
当条件处理程序激活时,将推送到诊断区域堆栈:
- 第一个(当前)诊断区域变为第二个(堆叠)诊断区域,并创建一个新的当前诊断区域作为其副本。
GET[CURRENT] DIAGNOSTICS
并且GET STACKED DIAGNOSTICS
可以在处理程序内使用,以访问当前和堆叠诊断区域的内容。- 最初,两个诊断区域都返回相同的结果,因此,只要您在处理程序内未执行任何更改其当前诊断区域的语句,就可以从当前诊断区域获取有关激活处理程序的条件的信息。
但是,在处理程序中执行的语句可以修改当前的诊断区域,并根据常规规则清除和设置其内容(请参阅如何清除和填充诊断区域)。
获取有关处理程序激活条件的信息的一种更可靠的方法是使用堆叠的诊断区域,该区域不能通过在处理程序中执行的语句(除外)进行修改
RESIGNAL
。有关何时设置和清除当前诊断区域的信息,请参见“ MySQL诊断区域”。
下一个示例显示GET STACKED DIAGNOSTICS
即使在处理程序语句修改了当前诊断区域之后,如何在处理程序中使用它来获取有关已处理异常的信息。
在存储过程中p()
,我们尝试将两个值插入到包含TEXT NOT NULL
列的表中。第一个值为非NULL
字符串,第二个为NULL
。该列禁止NULL
值,因此第一个插入成功,但是第二个插入导致异常。该过程包括一个异常处理程序,该异常处理程序将NULL
插入的尝试映射到空字符串的插入中:
DROP TABLE IF EXISTS t1;CREATE TABLE t1 (c1 TEXT NOT NULL);DROP PROCEDURE IF EXISTS p;delimiter //CREATE PROCEDURE p ()BEGIN -- Declare variables to hold diagnostics area informationDECLARE errcount INT;DECLARE errno INT;DECLARE msg TEXT;DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN -- Here the current DA is nonempty because no prior statements -- executing within the handler have cleared itGET CURRENT DIAGNOSTICS CONDITION 1 errno =MYSQL_ERRNO , msg =MESSAGE_TEXT ;SELECT 'current DA before mapped insert'AS op, errno, msg;GET STACKED DIAGNOSTICS CONDITION 1 errno =MYSQL_ERRNO , msg =MESSAGE_TEXT ;SELECT 'stacked DA before mapped insert'AS op, errno, msg; -- Map attempted NULL insert to empty string insertINSERT INTO t1 (c1)VALUES (''); -- Here the current DA should be empty (if the INSERT succeeded), -- so check whether there are conditions before attempting to -- obtain condition informationGET CURRENT DIAGNOSTICS errcount =NUMBER ;IF errcount = 0THEN SELECT 'mapped insert succeeded, current DA is empty'AS op;ELSE GET CURRENT DIAGNOSTICS CONDITION 1 errno =MYSQL_ERRNO , msg =MESSAGE_TEXT ;SELECT 'current DA after mapped insert'AS op, errno, msg;END IF ;GET STACKED DIAGNOSTICS CONDITION 1 errno =MYSQL_ERRNO , msg =MESSAGE_TEXT ;SELECT 'stacked DA after mapped insert'AS op, errno, msg;END ;INSERT INTO t1 (c1)VALUES ('string 1');INSERT INTO t1 (c1)VALUES (NULL);END ; //delimiter ;CALL p();SELECT *FROM t1;
处理程序激活后,当前诊断区域的副本将被推送到诊断区域堆栈。处理程序首先显示当前和堆叠的诊断区域的内容,最初两者都是相同的:
+---------------------------------+-------+----------------------------+ | op | errno | msg | +---------------------------------+-------+----------------------------+ | current DA before mapped insert | 1048 | Column 'c1' cannot be null | +---------------------------------+-------+----------------------------+ +---------------------------------+-------+----------------------------+ | op | errno | msg | +---------------------------------+-------+----------------------------+ | stacked DA before mapped insert | 1048 | Column 'c1' cannot be null | +---------------------------------+-------+----------------------------+
在语句之后执行的GET DIAGNOSTICS
语句可能会重置当前诊断区域。语句可能会重置当前诊断区域。例如,处理程序将NULL
插入内容映射到空字符串插入内容并显示结果。新的插入成功并清除了当前的诊断区域,但是堆叠的诊断区域保持不变,并且仍然包含有关激活处理程序的条件的信息:
+----------------------------------------------+ | op | +----------------------------------------------+ | mapped insert succeeded, current DA is empty | +----------------------------------------------+ +--------------------------------+-------+----------------------------+ | op | errno | msg | +--------------------------------+-------+----------------------------+ | stacked DA after mapped insert | 1048 | Column 'c1' cannot be null | +--------------------------------+-------+----------------------------+
当条件处理程序结束时,其当前诊断区域将从堆栈中弹出,而堆叠的诊断区域将成为存储过程中的当前诊断区域。
该过程返回后,该表包含两行。空行是由于尝试将插入NULL
映射到空字符串插入而产生的:
+----------+ | c1 | +----------+ | string 1 | | | +----------+
在前面的示例中,GET DIAGNOSTICS
条件处理程序中从当前和堆叠的诊断区域检索信息的前两个语句返回相同的值。如果重置当前诊断区域的语句在处理程序中更早执行,则情况并非如此。假设将p()
其重写以将DECLARE
语句放置在处理程序定义中而不是放置在处理程序定义之前:
CREATE PROCEDURE p ()BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN -- Declare variables to hold diagnostics area informationDECLARE errcount INT;DECLARE errno INT;DECLARE msg TEXT;GET CURRENT DIAGNOSTICS CONDITION 1 errno =MYSQL_ERRNO , msg =MESSAGE_TEXT ;SELECT 'current DA before mapped insert'AS op, errno, msg;GET STACKED DIAGNOSTICS CONDITION 1 errno =MYSQL_ERRNO , msg =MESSAGE_TEXT ;SELECT 'stacked DA before mapped insert'AS op, errno, msg; ...
在这种情况下,结果取决于版本:
在MySQL 5.7.2之前,
DECLARE
它不会更改当前的诊断区域,因此前两个GET DIAGNOSTICS
语句返回的结果相同,就像的原始版本一样p()
。在MySQL 5.7.2中,已按照SQL标准进行了确保所有非诊断语句填充诊断区域的工作。
DECLARE
是其中之一,因此在5.7.2及更高版本中,DECLARE
在处理程序开头执行的语句清除了当前的诊断区域,并且这些GET DIAGNOSTICS
语句产生了不同的结果:+---------------------------------+-------+------+ | op | errno | msg | +---------------------------------+-------+------+ | current DA before mapped insert | NULL | NULL | +---------------------------------+-------+------+ +---------------------------------+-------+----------------------------+ | op | errno | msg | +---------------------------------+-------+----------------------------+ | stacked DA before mapped insert | 1048 | Column 'c1' cannot be null | +---------------------------------+-------+----------------------------+
为避免在条件处理程序中寻求获取有关激活该处理程序的条件的信息时发生此问题,请确保访问堆积的诊断区域,而不是当前的诊断区域。