13.6.7.4 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可能会在传递某些或全部信息之前对其进行更改。 RESIGNALSIGNAL有关,但是RESIGNAL可能会在修改之后,而不是像SIGNAL那样发起条件,而是中继现有条件信息。

RESIGNAL可以处理错误并返回错误信息。否则,通过在处理程序中执行 SQL 语句,会破坏导致处理程序激活的信息。如果给定的处理程序可以处理部分情况,则RESIGNAL还可以使某些过程更短,然后将条件“向上”传递给另一个处理程序。

执行RESIGNAL语句不需要特权。

RESIGNAL的所有形式均要求当前上下文为条件处理程序。否则,RESIGNAL是非法的并且发生RESIGNAL when handler not active错误。

要从诊断区域检索信息,请使用GET DIAGNOSTICS语句(请参阅第 13.6.7.3 节“获取诊断声明”)。有关诊断区域的信息,请参见第 13.6.7.7 节“ MySQL 诊断区域”

RESIGNAL Overview

对于* condition_value signal_information_item RESIGNAL的定义和规则与SIGNAL相同。例如, condition_value *可以是SQLSTATE值,并且该值可以指示错误,警告或“未找到”。有关更多信息,请参见第 13.6.7.5 节“ SIGNAL 语句”

RESIGNAL语句带有* condition_value *和SET子句,这两个子句都是可选的。这导致了几种可能的用途:

RESIGNAL;
RESIGNAL SET signal_information_item [, signal_information_item] ...;
  • RESIGNAL,带有条件值和可能的新 signal 信息:
RESIGNAL condition_value
    [SET signal_information_item [, signal_information_item] ...];

这些用例都会导致诊断和条件区域的更改:

  • 诊断区域包含一个或多个条件区域。

  • 条件区域包含条件信息项,例如SQLSTATE值,MYSQL_ERRNOMESSAGE_TEXT

有大量的诊断区域。当处理程序取得控制权时,它将诊断区域推到堆栈的顶部,因此在处理程序执行期间有两个诊断区域:

  • 第一个(当前)诊断区域,以最后一个诊断区域的副本开始,但是将被更改当前诊断区域的处理程序中的第一条语句覆盖。

  • 最后一个(堆叠)诊断区域,其中包含在处理程序控制之前设置的条件区域。

诊断区域中条件区域的最大数量由max_error_count系统变量的值确定。参见诊断区域相关的系统变量

RESIGNAL Alone

一个简单的RESIGNALtable 示“毫无错误地传递错误”。它会还原最后的诊断区域,并使其成为当前的诊断区域。也就是说,它“弹出”诊断区域堆栈。

在捕获条件的条件处理程序中,单独使用RESIGNAL的一种用途是执行一些其他操作,然后 continue 进行而不更改原始条件信息(Importing 到处理程序中之前存在的信息)。

Example:

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是一个 exception,它不清楚,它什么也不做。 SET也不 exception,它清除,执行操作并产生“成功”结果。现在,诊断区域堆栈如下所示:

DA 1. ERROR 0000 (00000): Successful operation
DA 2. ERROR 1051 (42S02): Unknown table 'xx'

此时,如果@a = 0RESIGNAL弹出诊断区域堆栈,现在看起来像这样:

DA 1. ERROR 1051 (42S02): Unknown table 'xx'

这就是呼叫者看到的。

如果@a不为 0,则处理程序简单地结束,这意味着当前诊断区域不再使用(已被“处理”),因此可以将其丢弃,从而使堆叠的诊断区域成为当前诊断区域。再次区域。诊断区域堆栈如下所示:

DA 1. ERROR 0000 (00000): Successful operation

详细信息使它看起来很复杂,但是最终结果却非常有用:处理程序可以在不破坏导致激活处理程序的条件的信息的情况下执行。

RESIGNAL 带有新 signal 信息

带有SET子句的RESIGNAL提供了新的 signal 信息,因此该语句的意思是“通过更改传递错误”:

RESIGNAL SET signal_information_item [, signal_information_item] ...;

与单独使用RESIGNAL一样,其想法是弹出诊断区域堆栈,以便原始信息消失。与RESIGNAL不同,SET子句中指定的所有内容都会更改。

Example:

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语句可以更改任何或所有 signal 信息项,从而使诊断区域的第一个条件区域看起来完全不同。

RESIGNAL,带有条件值和可选的新 signal 信息

具有条件值的RESIGNALtable 示“将条件推入当前诊断区域”。如果存在SET子句,它也会更改错误信息。

RESIGNAL condition_value
    [SET signal_information_item [, signal_information_item] ...];

RESIGNAL的这种形式将恢复上一个诊断区域,并将其设置为当前诊断区域。也就是说,它“弹出”诊断区域堆栈,这与单独的RESIGNAL会执行的操作相同。但是,它也会根据条件值或 signal 信息更改诊断区域。

Example:

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 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会导致“处理程序未激活”错误。