文档首页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF(US Ltr) - 39.9Mb
PDF(A4) - 40.0Mb
手册页(TGZ) - 258.5Kb
手册页(Zip) - 365.5Kb
Info(Gzip) - 4.0Mb
Info(Zip) - 4.0Mb


MySQL 8.4 参考手册  /  ...  /  RESIGNAL 语句

15.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 相关,但不像 SIGNAL 那样产生条件,RESIGNAL 传递现有的条件信息,可能在修改之后。

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

执行 RESIGNAL 语句不需要任何权限。

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

要从诊断区域检索信息,请使用 GET DIAGNOSTICS 语句(参见 第 15.6.7.3 节,“GET DIAGNOSTICS 语句”)。有关诊断区域的信息,请参见 第 15.6.7.7 节,“MySQL 诊断区域”

RESIGNAL 概述

对于 condition_valuesignal_information_item,定义和规则与 RESIGNAL 相同,与 SIGNAL 相同。例如,condition_value 可以是 SQLSTATE 值,该值可以表示错误、警告或 未找到。 有关更多信息,请参见 第 15.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] ...];

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

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

  • 条件区域包含条件信息项,例如 SQLSTATE 值、MYSQL_ERRNOMESSAGE_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 不是一个例外,它会清除,执行操作,并产生 成功。 的结果。诊断区域堆栈现在如下所示

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

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