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
可以在傳遞之前變更部分或所有資訊。RESIGNAL
與 SIGNAL
相關,但 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 診斷區域」。
對於 condition_value
和 signal_information_item
,RESIGNAL
的定義和規則與 SIGNAL
相同。例如,condition_value
可以是 SQLSTATE
值,而且該值可以指示錯誤、警告或「找不到」。如需其他資訊,請參閱第 15.6.7.5 節,「SIGNAL 陳述式」。
RESIGNAL
陳述式接受 condition_value
和 SET
子句,兩者皆為選用。這導致幾種可能的用法
這些使用案例都會對診斷和條件區域造成變更
診斷區域包含一個或多個條件區域。
條件區域包含條件資訊項目,例如
SQLSTATE
值、MYSQL_ERRNO
或MESSAGE_TEXT
。
有一個診斷區域的堆疊。當處理常式取得控制權時,它會將診斷區域推送到堆疊頂端,因此在處理常式執行期間會有兩個診斷區域
第一個(目前)診斷區域,它會以最後一個診斷區域的複本開始,但會被處理常式中第一個變更目前診斷區域的陳述式覆寫。
最後一個(堆疊)診斷區域,其中包含在處理常式取得控制權之前設定的條件區域。
診斷區域中條件區域的最大數量由 max_error_count
系統變數的值決定。請參閱診斷區域相關系統變數。
單獨的簡單 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 = 0
,RESIGNAL
會彈出診斷區域堆疊,現在看起來像這樣
DA 1. ERROR 1051 (42S02): Unknown table 'xx'
這就是呼叫者看到的內容。
如果 @a
不等於 0,則處理常式只會結束,這表示目前診斷區域不再有用(它已被「處理」),因此可以捨棄,導致堆疊的診斷區域再次成為目前診斷區域。診斷區域堆疊看起來會像這樣
DA 1. ERROR 0000 (00000): Successful operation
詳細資訊使其看起來很複雜,但最終結果非常有用:處理常式可以在不破壞導致啟動處理常式的條件資訊的情況下執行。
帶有 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
表示「將條件推送到目前的診斷區域。」如果 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 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
會導致「處理常式未啟動」錯誤。