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


MySQL 9.0 參考手冊  /  ...  /  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 |
|          |
+----------+