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
语句(请参阅
第 13.6.7.3 节,“GET DIAGNOSTICS 语句”)。有关诊断区域的信息,请参阅第 13.6.7.7 节,“MySQL 诊断区域”。
对于condition_value
和
signal_information_item
,定义和规则与 for
RESIGNAL
相同
SIGNAL
。例如,
condition_value
可以是一个
SQLSTATE
值,该值可以指示错误、警告或“未找到”。”有关其他信息,请参阅第 13.6.7.5 节,“SIGNAL 语句”。
该RESIGNAL
语句采用
condition_value
和
SET
子句,两者都是可选的。这导致了几种可能的用途:
这些用例都会导致诊断和条件区域发生变化:
诊断区域包含一个或多个条件区域。
条件区域包含条件信息项,例如
SQLSTATE
值MYSQL_ERRNO
、 或MESSAGE_TEXT
。
有一堆诊断区域。当处理程序获得控制权时,它会将诊断区域压入堆栈的顶部,因此在处理程序执行期间有两个诊断区域:
第一个(当前)诊断区域,它作为最后一个诊断区域的副本开始,但被处理程序中更改当前诊断区域的第一条语句覆盖。
最后一个(堆叠的)诊断区域,其中包含在处理程序控制之前设置的条件区域。
诊断区域中条件区域的最大数量由
max_error_count
系统变量的值决定。请参阅
与诊断区域相关的系统变量。
一个简单的RESIGNAL
单独意味着
“传递错误而不改变。”它恢复上一个诊断区域并使其成为当前诊断区域。也就是说,它“弹出”诊断区域堆栈。
在捕获条件的条件处理程序中,forRESIGNAL
单独的一个用途是执行一些其他操作,然后在不更改原始条件信息(进入处理程序之前存在的信息)的情况下传递。
例子:
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
with
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()
有它自己的上下文,而不是处理程序上下文。因此,RESIGNAL
within
f()
会导致“处理程序未激活”错误。