Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

15.6.7.4 重新信号语句

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 那样originating 条件,而是将现有的条件信息传递,可能在修改后。

RESIGNAL 使得可以同时处理错误并返回错误信息。否则,执行 SQL 语句时,激活处理器的信息将被销毁。RESIGNAL 也可以使某些过程变得更短,如果给定的处理器可以处理部分情况,然后将条件“上报”到另一个处理器。

执行 RESIGNAL 语句不需要特权。

所有形式的 RESIGNAL 都需要当前上下文是一个条件处理器。否则,RESIGNAL 是非法的,并出现“RESIGNAL when handler not active”错误。

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

重新信号概述

对于 condition_valuesignal_information_item,定义和规则与 RESIGNAL 相同,如 SIGNAL。例如,condition_value 可以是一个 SQLSTATE 值,该值可以指示错误、警告或“未找到”。有关更多信息,请参阅 第 15.6.7.5 节,“信号语句”

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 Alone

简单的 RESIGNAL alone 表示 将错误传递不变。 它恢复最后一个诊断区域并使其成为当前诊断区域。也就是说,它 弹出 诊断区域栈。

在捕获条件的处理程序中,RESIGNAL alone 的一个用途是在执行其他操作后,传递原始条件信息(在处理程序入口之前存在的信息)。

示例:

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 with New Signal Information

RESIGNAL 带有 SET 子句提供新的信号信息,因此该语句表示 将错误传递带变化。

RESIGNAL SET signal_information_item [, signal_information_item] ...;

RESIGNAL alone 相似,想法是弹出诊断区域栈,以便原始信息出去。与 RESIGNAL alone 不同的是,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 alone 结果是一个诊断区域栈,看起来像这样:

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结果是一个处理器不活动”错误。