Documentation Home

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可能会在传递之前更改部分或全部信息。 RESIGNAL与 相关 ,但不是像 那样SIGNAL发起条件,而是中继现有条件信息,可能在修改它之后。 SIGNALRESIGNAL

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_valuesignal_information_item,定义和规则与 for RESIGNAL相同 SIGNAL。例如, condition_value可以是一个 SQLSTATE值,该值可以指示错误、警告或未找到”。有关其他信息,请参阅第 13.6.7.5 节,“SIGNAL 语句”

RESIGNAL语句采用 condition_valueSET子句,两者都是可选的。这导致了几种可能的用途:

  • RESIGNAL独自的:

    RESIGNAL;
  • RESIGNAL使用新的信号信息:

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

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

这些用例都会导致诊断和条件区域发生变化:

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

  • 条件区域包含条件信息项,例如SQLSTATEMYSQL_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 = 0RESIGNAL弹出诊断区域堆栈,现在看起来像这样:

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

这就是调用者看到的。

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

DA 1. ERROR 0000 (00000): Successful operation

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

RESIGNAL 新信号信息

RESIGNALwith 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

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 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()有它自己的上下文,而不是处理程序上下文。因此,RESIGNALwithin f()会导致处理程序未激活错误。