文档首页
MySQL 9.0 参考手册
相关文档 下载本手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 参考手册  /  ...  /  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 不同,它不是像 SIGNAL 那样产生条件,而是传递已有的条件信息,可能是在修改之后。

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,定义和规则对于 RESIGNALSIGNAL 都是一样的。例如,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 会导致 处理程序未激活 错误。