文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  GET DIAGNOSTICS 陳述式

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

SQL 陳述式會產生診斷資訊,並將其填入診斷區域。 GET DIAGNOSTICS 陳述式讓應用程式能夠檢查此資訊。(您也可以使用 SHOW WARNINGSSHOW 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 錯誤。

如需診斷區域的說明,請參閱 第 15.6.7.7 節「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_namecondition_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 中,如果有多個條件,則第一個條件與先前 SQL 陳述式傳回的 SQLSTATE 值相關。在 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 information
  DECLARE code CHAR(5) DEFAULT '00000';
  DECLARE msg TEXT;
  DECLARE nrows 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 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 happened
  SELECT result;
END;

假設 t1.int_col 是宣告為 NOT NULL 的整數資料行。當叫用該程序以分別插入非 NULLNULL 值時,會產生以下結果

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] DIAGNOSTICSGET STACKED DIAGNOSTICS 來存取目前和堆疊的診斷區域的內容。

  • 最初,兩個診斷區域都會傳回相同的結果,因此可以從目前的診斷區域取得有關啟動處理常式的條件的資訊,只要您在處理常式內未執行任何會變更其目前診斷區域的陳述式即可。

  • 但是,在處理常式內執行的陳述式可以修改目前的診斷區域,根據正常規則清除並設定其內容(請參閱如何清除和填入診斷區域)。

    取得有關啟動處理常式條件的資訊的更可靠方法是使用堆疊的診斷區域,該區域無法由處理常式內執行的陳述式修改,但 RESIGNAL 除外。如需有關何時設定和清除目前診斷區域的資訊,請參閱第 15.6.7.7 節「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 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;

當處理常式啟動時,目前的診斷區域的複本會推送至診斷區域堆疊。處理常式首先會顯示目前和堆疊診斷區域的內容,兩者最初都相同

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