文件首頁
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 參考手冊  /  ...  /  RESIGNAL 陳述式

15.6.7.4 RESIGNAL 陳述式

RESIGNAL [condition_value]
    [SET signal_information_item
    [, signal_information_item] ...]

condition_value: {
    SQLSTATE [VALUE] sqlstate_value
  | condition_name
}

signal_information_item:
    condition_information_item_name = simple_value_specification

condition_information_item_name: {
    CLASS_ORIGIN
  | SUBCLASS_ORIGIN
  | MESSAGE_TEXT
  | MYSQL_ERRNO
  | CONSTRAINT_CATALOG
  | CONSTRAINT_SCHEMA
  | CONSTRAINT_NAME
  | CATALOG_NAME
  | SCHEMA_NAME
  | TABLE_NAME
  | COLUMN_NAME
  | CURSOR_NAME
}

condition_name, simple_value_specification:
    (see following discussion)

RESIGNAL 傳遞在儲存程序或函式、觸發程序或事件內的複合陳述式中,條件處理常式執行期間可用的錯誤條件資訊。RESIGNAL 可以在傳遞之前變更部分或所有資訊。RESIGNALSIGNAL 相關,但 RESIGNAL 不是像 SIGNAL 那樣產生條件,而是轉發現有的條件資訊,可能會在修改後進行。

RESIGNAL 可以處理錯誤並返回錯誤資訊。否則,在處理常式中執行 SQL 陳述式,會破壞導致處理常式啟動的資訊。RESIGNAL 如果給定的處理常式可以處理一部分情況,然後將條件 向上傳遞到另一個處理常式,也可以縮短一些程序。

執行 RESIGNAL 陳述式不需要任何權限。

所有形式的 RESIGNAL 都要求目前上下文必須是條件處理常式。否則,RESIGNAL 會是非法的,並會發生 RESIGNAL when handler not active 錯誤。

若要從診斷區域擷取資訊,請使用 GET DIAGNOSTICS 陳述式(請參閱第 15.6.7.3 節,「GET DIAGNOSTICS 陳述式」)。如需診斷區域的相關資訊,請參閱第 15.6.7.7 節,「MySQL 診斷區域」

RESIGNAL 概觀

對於 condition_valuesignal_information_itemRESIGNAL 的定義和規則與 SIGNAL 相同。例如,condition_value 可以是 SQLSTATE 值,而且該值可以指示錯誤、警告或找不到。如需其他資訊,請參閱第 15.6.7.5 節,「SIGNAL 陳述式」

RESIGNAL 陳述式接受 condition_valueSET 子句,兩者皆為選用。這導致幾種可能的用法

  • 單獨的 RESIGNAL

    RESIGNAL;
  • 帶有新訊號資訊的 RESIGNAL

    RESIGNAL SET signal_information_item [, signal_information_item] ...;
  • 帶有條件值以及可能新的訊號資訊的 RESIGNAL

    RESIGNAL condition_value
        [SET signal_information_item [, signal_information_item] ...];

這些使用案例都會對診斷和條件區域造成變更

  • 診斷區域包含一個或多個條件區域。

  • 條件區域包含條件資訊項目,例如 SQLSTATE 值、MYSQL_ERRNOMESSAGE_TEXT

有一個診斷區域的堆疊。當處理常式取得控制權時,它會將診斷區域推送到堆疊頂端,因此在處理常式執行期間會有兩個診斷區域

  • 第一個(目前)診斷區域,它會以最後一個診斷區域的複本開始,但會被處理常式中第一個變更目前診斷區域的陳述式覆寫。

  • 最後一個(堆疊)診斷區域,其中包含在處理常式取得控制權之前設定的條件區域。

診斷區域中條件區域的最大數量由 max_error_count 系統變數的值決定。請參閱診斷區域相關系統變數

單獨的 RESIGNAL

單獨的簡單 RESIGNAL 表示傳遞錯誤,且不做任何變更。它會還原最後一個診斷區域,並將其設為目前診斷區域。也就是說,它會彈出診斷區域堆疊。

在捕獲條件的條件處理常式中,單獨的 RESIGNAL 的一種用法是執行一些其他動作,然後在不變更原始條件資訊(進入處理常式之前存在的資訊)的情況下傳遞。

範例

DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SET @error_count = @error_count + 1;
    IF @a = 0 THEN RESIGNAL; END IF;
  END;
  DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
CALL p();

假設 DROP TABLE xx 陳述式失敗。診斷區域堆疊看起來會像這樣

DA 1. ERROR 1051 (42S02): Unknown table 'xx'

然後執行會進入 EXIT 處理常式。它會先將診斷區域推送到堆疊頂端,現在看起來像這樣

DA 1. ERROR 1051 (42S02): Unknown table 'xx'
DA 2. ERROR 1051 (42S02): Unknown table 'xx'

此時,第一個(目前)和第二個(堆疊)診斷區域的內容相同。第一個診斷區域可能會在處理常式中後續執行的陳述式修改。

通常,程序陳述式會清除第一個診斷區域。BEGIN 是一個例外,它不會清除,它不做任何事。SET 不是例外,它會清除、執行操作,並產生成功的結果。診斷區域堆疊現在看起來像這樣

DA 1. ERROR 0000 (00000): Successful operation
DA 2. ERROR 1051 (42S02): Unknown table 'xx'

此時,如果 @a = 0RESIGNAL 會彈出診斷區域堆疊,現在看起來像這樣

DA 1. ERROR 1051 (42S02): Unknown table 'xx'

這就是呼叫者看到的內容。

如果 @a 不等於 0,則處理常式只會結束,這表示目前診斷區域不再有用(它已被處理),因此可以捨棄,導致堆疊的診斷區域再次成為目前診斷區域。診斷區域堆疊看起來會像這樣

DA 1. ERROR 0000 (00000): Successful operation

詳細資訊使其看起來很複雜,但最終結果非常有用:處理常式可以在不破壞導致啟動處理常式的條件資訊的情況下執行。

帶有新訊號資訊的 RESIGNAL

帶有 SET 子句的 RESIGNAL 提供新的訊號資訊,因此該陳述式表示傳遞錯誤,並進行變更

RESIGNAL SET signal_information_item [, signal_information_item] ...;

與單獨的 RESIGNAL 一樣,其想法是彈出診斷區域堆疊,以便原始資訊輸出。與單獨的 RESIGNAL 不同,SET 子句中指定的任何內容都會變更。

範例

DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SET @error_count = @error_count + 1;
    IF @a = 0 THEN RESIGNAL SET MYSQL_ERRNO = 5; END IF;
  END;
  DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
CALL p();

從先前的討論中回想一下,單獨的 RESIGNAL 會導致診斷區域堆疊像這樣

DA 1. ERROR 1051 (42S02): Unknown table 'xx'

RESIGNAL SET MYSQL_ERRNO = 5 陳述式會改為導致此堆疊,這就是呼叫者看到的

DA 1. ERROR 5 (42S02): Unknown table 'xx'

換句話說,它會變更錯誤編號,而不會變更任何其他內容。

RESIGNAL 陳述式可以變更任何或所有訊號資訊項目,使診斷區域的第一個條件區域看起來大不相同。

帶有條件值和可選的新訊號資訊的 RESIGNAL

帶有條件值的 RESIGNAL 表示將條件推送到目前的診斷區域。如果 SET 子句存在,它也會變更錯誤資訊。

RESIGNAL condition_value
    [SET signal_information_item [, signal_information_item] ...];

此形式的 RESIGNAL 會還原最後一個診斷區域,並將其設為目前的診斷區域。也就是說,它會彈出診斷區域堆疊,這與單獨的簡單 RESIGNAL 所做的相同。但是,它也會根據條件值或訊號資訊變更診斷區域。

範例

DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SET @error_count = @error_count + 1;
    IF @a = 0 THEN RESIGNAL SQLSTATE '45000' SET MYSQL_ERRNO=5; END IF;
  END;
  DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
SET @@max_error_count = 2;
CALL p();
SHOW ERRORS;

這與先前的範例類似,效果也相同,只是如果 RESIGNAL 發生,則結尾的目前條件區域看起來會不同。(條件新增至現有條件而不是取代它的原因是使用了條件值。)

RESIGNAL 陳述式包含一個條件值 (SQLSTATE '45000'),因此它會新增一個新的條件區域,導致診斷區域堆疊看起來像這樣

DA 1. (condition 2) ERROR 1051 (42S02): Unknown table 'xx'
      (condition 1) ERROR 5 (45000) Unknown table 'xx'

此範例的 CALL p()SHOW ERRORS 結果如下

mysql> CALL p();
ERROR 5 (45000): Unknown table 'xx'
mysql> SHOW ERRORS;
+-------+------+----------------------------------+
| Level | Code | Message                          |
+-------+------+----------------------------------+
| Error | 1051 | Unknown table 'xx'               |
| Error |    5 | Unknown table 'xx'               |
+-------+------+----------------------------------+
RESIGNAL 需要條件處理常式上下文

所有形式的 RESIGNAL 都要求目前上下文必須是條件處理常式。否則,RESIGNAL 會是非法的,並會發生 RESIGNAL when handler not active 錯誤。例如

mysql> CREATE PROCEDURE p () RESIGNAL;
Query OK, 0 rows affected (0.00 sec)

mysql> CALL p();
ERROR 1645 (0K000): RESIGNAL when handler not active

以下是一個更困難的範例

delimiter //
CREATE FUNCTION f () RETURNS INT
BEGIN
  RESIGNAL;
  RETURN 5;
END//
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @a=f();
  SIGNAL SQLSTATE '55555';
END//
delimiter ;
CALL p();

RESIGNAL 發生在儲存函數 f() 內。雖然 f() 本身是在 EXIT 處理常式的上下文中調用,但在 f() 內執行有其自己的上下文,而不是處理常式上下文。因此,f() 內的 RESIGNAL 會導致處理常式未啟動錯誤。