暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL的SQL语句 -条件处理语句(4) - RESIGNAL 语句

林员外聊编程 2021-01-03
299
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 可能会在传递信息之前更改部分或全部信息。RESIGNAL SIGNAL 相关,但 RESIGNAL 不是像 SIGNAL 那样发起条件,而是传递现有的条件信息,当然可能是在修改了现有的条件信息之后传递。
 
RESIGNAL 使处理错误和返回错误信息成为可能。否则,通过在句柄中执行 SQL 语句,导致句柄激活的信息将被销毁。如果给定的句柄可以处理部分情况,那么 RESIGNAL 还可以缩短一些过程,然后将条件沿着“上行链路”传递给另一个句柄。
 
执行 RESIGNAL 语句不需要任何权限。
 
所有形式的 RESIGNAL 都要求当前上下文是条件句柄。否则,RESIGNAL 是非法的,并且当句柄未激活时会出现 RESIGNAL 错误。
 
要从诊断区域检索信息,请使用 GET DIAGNOSTICS 语句。
 
RESIGNAL 概述
 
对于 condition_value  signal_information_itemRESIGNAL SIGNAL 的定义和规则相同。例如,condition_value 可以是 SQLSTATE 值,并且该值可以指示错误、警告或“not found.”。
 
RESIGNAL 语句接受 condition_value  SET 子句,这两个子句都是可选的。这导致了几种可能的用途:
 
●  RESIGNAL :
 
RESIGNAL;
复制
 
● RESIGNAL 带有新信号信息:
 
RESIGNAL SET signal_information_item [, signal_information_item] ...;
复制
 
● RESIGNAL 带一个条件值和可能的新信号信息:
 
RESIGNAL condition_value
[SET signal_information_item [, signal_information_item] ...];
复制
 
这些用例都会导致诊断和条件区域发生变化:
 
● 诊断区域包含一个或多个条件区域。
 
● 条件区域包含条件信息项,例如 SQLSTATE 值、MYSQL_ERRNO MESSAGE_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 不是例外,它清除、执行操作并生成 “success” 结果。诊断区域堆栈现在如下所示:
 
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 提供了新的信号信息,因此该语句的意思是“将错误和更改一起传递”:
 
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 错误。例如:
 
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 将导致“句柄未激活”错误。
 
 
 
 
官方网址:
https://dev.mysql.com/doc/refman/8.0/en/resignal.html

文章转载自林员外聊编程,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论