GET DIAGNOSTICS 可檢查前一條 SQL 陳述式的診斷區資訊,包含陳述式層級(影響列數、條件數)與條件層級(錯誤碼、訊息、SQLSTATE)資訊。支援 CURRENT(目前診斷區)與 STACKED(條件處理器啟動時的堆疊診斷區)兩種模式,是預存程序精確錯誤處理的核心工具。
GET [CURRENT | STACKED] DIAGNOSTICS
{
@var = statement_item [, ...]
| CONDITION condition_number @var = condition_item [, ...]
}
statement_item: NUMBER | ROW_COUNT
condition_item: 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
Statement information: row count, ... Condition area list: Condition 1: error code, message, ... Condition 2: error code, message, ... ...
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 DIAGNOSTICS @p1 = NUMBER, @p2 = ROW_COUNT;
GET DIAGNOSTICS CONDITION 1 @p3 = RETURNED_SQLSTATE, @p4 = MESSAGE_TEXT;
CREATE PROCEDURE do_insert(value INT)
BEGIN
DECLARE code CHAR(5) DEFAULT '00000';
DECLARE msg TEXT;
DECLARE rows INT;
DECLARE result TEXT;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
code = RETURNED_SQLSTATE, msg = MESSAGE_TEXT;
END;
INSERT INTO t1 (int_col) VALUES (value);
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;
SELECT result;
END;
測試:
CALL do_insert(1); -- 成功:row count = 1 CALL do_insert(NULL); -- 失敗:error = 23000, Column 'int_col' cannot be null
CREATE PROCEDURE p()
BEGIN
DECLARE errcount INT;
DECLARE errno INT;
DECLARE msg TEXT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
-- 目前診斷區(未被修改前與 stacked 相同)
GET CURRENT DIAGNOSTICS CONDITION 1 errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
SELECT 'current DA before' AS op, errno, msg;
-- 堆疊診斷區(保留觸發錯誤的原始資訊)
GET STACKED DIAGNOSTICS CONDITION 1 errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
SELECT 'stacked DA before' AS op, errno, msg;
-- 映射 NULL 插入為空字串
INSERT INTO t1 (c1) VALUES('');
-- 檢查目前診斷區是否已清空
GET CURRENT DIAGNOSTICS errcount = NUMBER;
IF errcount = 0 THEN
SELECT 'mapped insert succeeded, current DA empty' AS op;
ELSE
GET CURRENT DIAGNOSTICS CONDITION 1 errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
SELECT 'current DA after' AS op, errno, msg;
END IF;
-- stacked 區塊始終保留原始錯誤
GET STACKED DIAGNOSTICS CONDITION 1 errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
SELECT 'stacked DA after' AS op, errno, msg;
END;
INSERT INTO t1 (c1) VALUES('string 1');
INSERT INTO t1 (c1) VALUES(NULL); -- 觸發 NOT NULL 違反
END;
關鍵差異: 處理器內的陳述式會重設 CURRENT 診斷區,唯有 STACKED 區塊保留觸發錯誤的原始資訊。
5.7.2 起 DECLARE 等非診斷陳述式也會清空 CURRENT 診斷區。處理器開頭若先宣告變數再 GET CURRENT DIAGNOSTICS 會得到空結果。
最佳實務: 條件處理器中永遠使用 GET STACKED DIAGNOSTICS 取得觸發錯誤的資訊,避免版本差異與陳述式副作用。
MySQL 5.7 Reference Manual: GET DIAGNOSTICS Syntax
善用 GET DIAGNOSTICS 並搭配 STACKED 模式,可建構可靠、可診斷的預存程序錯誤處理機制。