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: (seefollowing discussion)
RESIGNAL传递错误条件信息,该条件信息在存储过程或函数,触发器或事件内的复合语句内的条件处理程序执行期间可用。RESIGNAL可能会在传递某些或全部信息之前对其进行更改。RESIGNAL与关联SIGNAL,但是可能会在修改之后中继现有的条件信息,而不是像SIGNAL这样发起条件RESIGNAL。
RESIGNAL使处理错误并返回错误信息成为可能。否则,通过在处理程序中执行SQL语句,会破坏导致处理程序激活的信息。RESIGNAL如果给定的处理程序可以处理部分情况,则还可以使某些过程更短,然后将条件“向上”传递给另一个处理程序。
执行该RESIGNAL语句不需要特权。
所有形式的RESIGNAL要求当前上下文都是条件处理程序。否则,RESIGNAL是非法的,并且RESIGNAL when handler not active会发生错误。
要从诊断区域检索信息,请使用该GET DIAGNOSTICS语句(请参见“ GET DIAGNOSTICS语句”)。有关诊断区域的信息,请参见“ MySQL诊断区域”。
- RESIGNAL概述
- 独自签名
- 使用新的信号信息重新发送信号
- 带条件值和可选新信号信息的RESIGNAL
- RESIGNAL需要条件处理程序上下文
RESIGNAL概述
对于condition_value和signal_information_item,定义和规则是相同的RESIGNAL作为SIGNAL。例如,condition_value可以是一个SQLSTATE值,并且该值可以指示错误,警告或“未找到”。”有关更多信息,请参见第13.6.7.5,‘SIGNAL语句’。
该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单独使用的一种方法是执行其他一些操作,然后继续进行而不更改原始条件信息(输入到处理程序中之前存在的信息)。
例:
DROP TABLE IF EXISTS xx;delimiter //CREATE PROCEDURE p ()BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN SET @error_count = @error_count + 1;IF @a = 0THEN 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 = 0THEN 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 = 0THEN 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 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 INTBEGIN 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在f()结果内会出现“处理程序未激活”错误。
