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
相关,但不像 SIGNAL
那样产生条件,RESIGNAL
传递现有的条件信息,可能在修改之后。
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
细节使其看起来很复杂,但最终结果非常有用:处理程序可以执行而不会破坏导致处理程序激活的条件的信息。
RESIGNAL
带有 SET
子句会提供新的信号信息,因此该语句表示 “带修改地传递错误。”
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
会导致 “处理程序未激活” 错误。