GET DIAGNOSTICS Syntax

http://dev.mysql.com/doc/refman/5.7/en/get-diagnostics.html

 

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:
    (see following discussion)

SQL statements produce diagnostic information that populates the diagnostics area. The GET DIAGNOSTICS statement enables applications to inspect this information. (You can also use SHOW WARNINGS or SHOW ERRORS to see conditions or errors.)

No special privileges are required to execute GET DIAGNOSTICS.

The keyword CURRENT means to retrieve information from the current diagnostics area. The keyword STACKED means to retrieve information from the second diagnostics area, which is available only if the current context is a condition handler. If neither keyword is given, the default is to use the current diagnostics area.

The GET DIAGNOSTICS statement is typically used in a handler within a stored program. It is a MySQL extension that GET [CURRENT] DIAGNOSTICS is permitted outside handler context to check the execution of any SQL statement. For example, if you invoke the mysql client program, you can enter these statements at the prompt:

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' |
+-------+------------------------------------+

This extension applies only to the current diagnostics area. It does not apply to the second diagnostics area because GET STACKED DIAGNOSTICS is permitted only if the current context is a condition handler. If that is not the case, a GET STACKED DIAGNOSTICS when handler not active error occurs.

For a description of the diagnostics area, see Section 14.6.7.7, “The MySQL Diagnostics Area”. Briefly, it contains two kinds of information:

  • Statement information, such as the number of conditions that occurred or the affected-rows count.

  • Condition information, such as the error code and message. If a statement raises multiple conditions, this part of the diagnostics area has a condition area for each one. If a statement raises no conditions, this part of the diagnostics area is empty.

For a statement that produces three conditions, the diagnostics area contains statement and condition information like this:

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 can obtain either statement or condition information, but not both in the same statement:

  • To obtain statement information, retrieve the desired statement items into target variables. This instance of GET DIAGNOSTICS assigns the number of available conditions and the rows-affected count to the user variables @p1 and @p2:

    GET DIAGNOSTICS @p1 = NUMBER, @p2 = ROW_COUNT;
    
  • To obtain condition information, specify the condition number and retrieve the desired condition items into target variables. This instance of GET DIAGNOSTICS assigns the SQLSTATE value and error message to the user variables @p3 and@p4:

    GET DIAGNOSTICS CONDITION 1
      @p3 = RETURNED_SQLSTATE, @p4 = MESSAGE_TEXT;
    

The retrieval list specifies one or more target = item_name assignments, separated by commas. Each assignment names a target variable and either a statement_information_item_name or condition_information_item_namedesignator, depending on whether the statement retrieves statement or condition information.

Valid target designators for storing item information can be stored procedure or function parameters, stored program local variables declared with DECLARE, or user-defined variables.

Valid condition_number designators can be stored procedure or function parameters, stored program local variables declared with DECLARE, user-defined variables, system variables, or literals. A character literal may include a _charsetintroducer. A warning occurs if the condition number is not in the range from 1 to the number of condition areas that have information. In this case, the warning is added to the diagnostics area without clearing it.

When a condition occurs, MySQL does not populate all condition items recognized by GET DIAGNOSTICS. For example:

mysql> GET DIAGNOSTICS CONDITION 1
    ->   @p5 = SCHEMA_NAME, @p6 = TABLE_NAME;
mysql> SELECT @p5, @p6;
+------+------+
| @p5  | @p6  |
+------+------+
|      |      |
+------+------+

In standard SQL, if there are multiple conditions, the first condition relates to the SQLSTATE value returned for the previous SQL statement. In MySQL, this is not guaranteed. To get the main error, you cannot do this:

GET DIAGNOSTICS CONDITION 1 @errno = MYSQL_ERRNO;

Instead, retrieve the condition count first, then use it to specify which condition number to inspect:

GET DIAGNOSTICS @cno = NUMBER;
GET DIAGNOSTICS CONDITION @cno @errno = MYSQL_ERRNO;

For information about permissible statement and condition information items, and which ones are populated when a condition occurs, see Section 14.6.7.7.2, “Diagnostics Area Information Items”.

Here is an example that uses GET DIAGNOSTICS and an exception handler in stored procedure context to assess the outcome of an insert operation. If the insert was successful, the procedure uses GET DIAGNOSTICS to get the rows-affected count. This shows that you can use GET DIAGNOSTICS multiple times to retrieve information about a statement as long as the current diagnostics area has not been cleared.

CREATE PROCEDURE do_insert(value INT)
BEGIN
  -- Declare variables to hold diagnostics area information
  DECLARE code CHAR(5) DEFAULT '00000';
  DECLARE msg TEXT;
  DECLARE rows INT;
  DECLARE result TEXT;
  -- Declare exception handler for failed insert
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
    BEGIN
      GET DIAGNOSTICS CONDITION 1
        code = RETURNED_SQLSTATE, msg = MESSAGE_TEXT;
    END;

  -- Perform the insert
  INSERT INTO t1 (int_col) VALUES(value);
  -- Check whether the insert was successful
  IF code = '00000' THEN
    GET DIAGNOSTICS rows = ROW_COUNT;
    SET result = CONCAT('insert succeeded, row count = ',rows);
  ELSE
    SET result = CONCAT('insert failed, error = ',code,', message = ',msg);
  END IF;
  -- Say what happened
  SELECT result;
END;

Suppose that t1.int_col is an integer column that is declared as NOT NULL. The procedure produces these results when invoked to insert non-NULL and NULL values, respectively:

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 |
+-------------------------------------------------------------------------+

When a condition handler activates, a push to the diagnostics area stack occurs:

  • The first (current) diagnostics area becomes the second (stacked) diagnostics area and a new current diagnostics area is created as a copy of it.

  • GET [CURRENT] DIAGNOSTICS and GET STACKED DIAGNOSTICS can be used within the handler to access the contents of the current and stacked diagnostics areas.

  • Initially, both diagnostics areas return the same result, so it is possible to get information from the current diagnostics area about the condition that activated the handler, as long as you execute no statements within the handler that change its current diagnostics area.

  • However, statements executing within the handler can modify the current diagnostics area, clearing and setting its contents according to the normal rules (see Section 14.6.7.7.3, “How the Diagnostics Area is Populated”).

    A more reliable way to obtain information about the handler-activating condition is to use the stacked diagnostics area, which cannot be modified by statements executing within the handler except RESIGNAL. For information about when the current diagnostics area is set and cleared, see Section 14.6.7.7, “The MySQL Diagnostics Area”.

The next example shows how GET STACKED DIAGNOSTICS can be used within a handler to obtain information about the handled exception, even after the current diagnostics area has been modified by handler statements.

Within a stored procedure p(), we attempt to insert two values into a table that contains a TEXT NOT NULL column. The first value is a non-NULL string and the second is NULL. The column prohibits NULL values, so the first insert succeeds but the second causes an exception. The procedure includes an exception handler that maps attempts to insert NULL into inserts of the empty string:

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 information
  DECLARE 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 it
    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;

    -- Map attempted NULL insert to empty string insert
    INSERT 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 information
    GET CURRENT DIAGNOSTICS errcount = NUMBER;
    IF errcount = 0
    THEN
      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;

When the handler activates, a copy of the current diagnostics area is pushed to the diagnostics area stack. The handler first displays the contents of the current and stacked diagnostics areas, which are both the same initially:

+---------------------------------+-------+----------------------------+
| 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 |
+---------------------------------+-------+----------------------------+

Statements executing after the GET DIAGNOSTICS statements may reset the current diagnostics area. statements may reset the current diagnostics area. For example, the handler maps the NULL insert to an empty-string insert and displays the result. The new insert succeeds and clears the current diagnostics area, but the stacked diagnostics area remains unchanged and still contains information about the condition that activated the handler:

+----------------------------------------------+
| op                                           |
+----------------------------------------------+
| mapped insert succeeded, current DA is empty |
+----------------------------------------------+

+--------------------------------+-------+----------------------------+
| op                             | errno | msg                        |
+--------------------------------+-------+----------------------------+
| stacked DA after mapped insert |  1048 | Column 'c1' cannot be null |
+--------------------------------+-------+----------------------------+

When the condition handler ends, its current diagnostics area is popped from the stack and the stacked diagnostics area becomes the current diagnostics area in the stored procedure.

After the procedure returns, the table contains two rows. The empty row results from the attempt to insert NULL that was mapped to an empty-string insert:

+----------+
| c1       |
+----------+
| string 1 |
|          |
+----------+

In the preceding example, the first two GET DIAGNOSTICS statements within the condition handler that retrieve information from the current and stacked diagnostics areas return the same values. This will not be the case if statements that reset the current diagnostics area execute earlier within the handler. Suppose that p() is rewritten to place the DECLARE statements within the handler definition rather than preceding it:

CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    -- Declare variables to hold diagnostics area information
    DECLARE 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;
...

In this case, the result is version dependent:

  • Before MySQL 5.7.2, DECLARE does not change the current diagnostics area, so the first two GET DIAGNOSTICS statements return the same result, just as in the original version of p().

    In MySQL 5.7.2, work was done to ensure that all nondiagnostic statements populate the diagnostics area, per the SQL standard. DECLARE is one of them, so in 5.7.2 and higher, DECLARE statements executing at the beginning of the handler clear the current diagnostics area and the GET DIAGNOSTICS statements produce different results:

    +---------------------------------+-------+------+
    | op                              | errno | msg  |
    +---------------------------------+-------+------+
    | current DA before mapped insert |  NULL | NULL |
    +---------------------------------+-------+------+
    
    +---------------------------------+-------+----------------------------+
    | op                              | errno | msg                        |
    +---------------------------------+-------+----------------------------+
    | stacked DA before mapped insert |  1048 | Column 'c1' cannot be null |
    +---------------------------------+-------+----------------------------+
    

To avoid this issue within a condition handler when seeking to obtain information about the condition that activated the handler, be sure to access the stacked diagnostics area, not the current diagnostics area.

DELIMITER $$ -- 创建错误日志表(建议长期保留) CREATE TABLE IF NOT EXISTS sys_sync_error_log ( id INT PRIMARY KEY AUTO_INCREMENT, error_time DATETIME DEFAULT CURRENT_TIMESTAMP, source_table VARCHAR(50), record_id VARCHAR(255), error_message TEXT, error_stack TEXT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 主存储过程 CREATE PROCEDURE SyncFileReferences() BEGIN DECLARE v_id VARCHAR(255); DECLARE v_file_storage_id VARCHAR(255); DECLARE v_source_key VARCHAR(50); DECLARE v_done INT DEFAULT 0; DECLARE v_error_msg TEXT; -- 创建临时数据表 DROP TEMPORARY TABLE IF EXISTS tmp_combined_data; CREATE TEMPORARY TABLE tmp_combined_data ( id VARCHAR(255), file_storage_id VARCHAR(255), source_key VARCHAR(50) ) ENGINE=Memory; -- 插入starry_facility数据 INSERT INTO tmp_combined_data SELECT CAST(id AS CHAR) AS id, img_path AS file_storage_id, '_imgPath' AS source_key FROM starry_facility WHERE img_path IS NOT NULL AND img_path != ''; -- 插入os_tablet_design_mst数据 INSERT INTO tmp_combined_data SELECT CAST(id AS CHAR) AS id, logo_path AS file_storage_id, '_logoPath' AS source_key FROM os_tablet_design_mst WHERE logo_path IS NOT NULL AND logo_path != ''; -- 定义游标 DECLARE cur_data CURSOR FOR SELECT id, file_storage_id, source_key FROM tmp_combined_data; -- 错误处理声明 DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = 1; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN GET DIAGNOSTICS CONDITION 1 v_error_msg = MESSAGE_TEXT; INSERT INTO sys_sync_error_log (source_table, record_id, error_message, error_stack) VALUES ('sys_file_storage', v_file_storage_id, v_error_msg, CONCAT('ID:', v_id, ' Key:', v_source_key)); END; OPEN cur_data; -- 开始循环处理 REPEAT FETCH cur_data INTO v_id, v_file_storage_id, v_source_key; IF NOT v_done THEN START TRANSACTION; -- 更新操作 UPDATE sys_file_storage SET source_id = CONCAT(v_id, v_source_key) WHERE id = v_file_storage_id; -- 添加错误检测示例 IF ROW_COUNT() = 0 THEN INSERT INTO sys_sync_error_log (source_table, record_id, error_message) VALUES ('sys_file_storage', v_file_storage_id, '目标记录不存在'); END IF; COMMIT; END IF; UNTIL v_done END REPEAT; CLOSE cur_data; -- 清理临时表 DROP TEMPORARY TABLE IF EXISTS tmp_combined_data; END$$ DELIMITER ; 这段代码发生了错误: 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DECLARE cur_data CURSOR FOR SELECT id, file_storage_id, source_key ' at line 37 请帮我解决这个问题
最新发布
03-08
<think>嗯,用户提供的这个存储过程代码出现了错误,错误信息是1064语法错误,具体位置在声明游标的附近。我需要仔细看一下问题出在哪里。 首先,我回忆一下MySQL存储过程的语法结构。存储过程中的变量声明、游标声明和处理程序声明都需要放在BEGIN之后的最前面,也就是在所有的执行语句之前。用户代码中,在创建临时表和插入数据之后才声明游标和处理程序,这显然不符合MySQL的语法规则。 看代码的结构,用户先创建了临时表tmp_combined_data,然后插入了数据,接着才开始声明DECLARE cur_data CURSOR FOR...,这在MySQL中是不允许的。所有的DECLARE语句必须集中放在BEGIN之后的第一个部分,不能与其他执行语句混合。 所以,问题出在DECLARE的位置。用户可能在创建临时表之后才声明游标,导致语法错误。正确的做法是将所有DECLARE语句移到执行语句之前,也就是在BEGIN之后,创建临时表之前。 具体来说,用户代码中的DECLARE cur_data和DECLARE CONTINUE HANDLER应该放在创建临时表之前。例如,在BEGIN之后,先声明变量、游标和异常处理,然后再进行创建临时表、插入数据等操作。 另外,还需要检查是否有其他语法错误,比如变量名是否正确,语句是否缺少分号等。不过根据错误信息,问题主要出在游标声明的位置上。 修改后的代码结构应该是: BEGIN DECLARE变量; DECLARE游标; DECLARE异常处理; 创建临时表; 插入数据; 打开游标; 循环处理; 关闭游标; 清理临时表; END 所以,用户需要将DECLARE部分移到所有执行语句之前。调整顺序后应该可以解决这个错误。</think>这个错误是由于MySQL中声明顺序不当导致的。所有`DECLARE`语句必须出现在存储过程主体中的其他操作语句之前。以下是需要修正的部分: **修改后的正确代码结构**: ```sql DELIMITER $$ CREATE PROCEDURE SyncFileReferences() BEGIN -- 所有声明必须放在最前面 DECLARE v_id VARCHAR(255); DECLARE v_file_storage_id VARCHAR(255); DECLARE v_source_key VARCHAR(50); DECLARE v_done INT DEFAULT 0; DECLARE v_error_msg TEXT; -- 游标声明必须在前 DECLARE cur_data CURSOR FOR SELECT id, file_storage_id, source_key FROM tmp_combined_data; -- 错误处理声明必须在前 DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = 1; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN GET DIAGNOSTICS CONDITION 1 v_error_msg = MESSAGE_TEXT; INSERT INTO sys_sync_error_log (source_table, record_id, error_message, error_stack) VALUES ('sys_file_storage', v_file_storage_id, v_error_msg, CONCAT('ID:', v_id, ' Key:', v_source_key)); END; -- 以下是操作语句 DROP TEMPORARY TABLE IF EXISTS tmp_combined_data; CREATE TEMPORARY TABLE tmp_combined_data (...); -- 后续插入数据、游标操作等... END$$ DELIMITER ; ``` **修改要点说明**: 1. **声明顺序问题**:MySQL要求所有`DECLARE`语句(变量、游标、错误处理器)必须出现在存储过程主体的最前面,之后才能进行其他操作(如创建临时表、插入数据等) 2. **错误处理器补充**:建议在错误处理中添加事务回滚: ```sql DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; -- 增加回滚 GET DIAGNOSTICS CONDITION 1 v_error_msg = MESSAGE_TEXT; -- 后续错误日志记录... END; ``` 3. **验证建议**:可以通过以下步骤验证存储过程: ```sql -- 删除旧版本 DROP PROCEDURE IF EXISTS SyncFileReferences; -- 创建新版本(使用修正后的代码) DELIMITER $$ CREATE PROCEDURE SyncFileReferences() ... $$ -- 执行测试 CALL SyncFileReferences(); ``` **完整修改建议**: ```sql DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; -- 新增回滚语句 GET DIAGNOSTICS CONDITION 1 v_error_msg = MESSAGE_TEXT; INSERT INTO sys_sync_error_log (source_table, record_id, error_message, error_stack) VALUES ('sys_file_storage', v_file_storage_id, v_error_msg, CONCAT('ID:', v_id, ' Key:', v_source_key)); END; ``` 这个错误是典型的MySQL存储过程声明顺序问题,按照要求调整声明顺序后即可正常执行。建议在开发过程中使用`SHOW WARNINGS;`查看详细编译错误信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值