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
不同,它不是像 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
细节使它看起来很复杂,但最终结果非常有用:处理程序可以执行而不会破坏导致处理程序激活的条件的信息。
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
会导致 “处理程序未激活” 错误。