Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


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 相关,但 RESIGNAL 将现有条件信息传递,而不是像 SIGNAL 一样生成新的条件信息。

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

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

所有形式的 RESIGNAL 都需要当前上下文是条件处理程序。否则, RESIGNAL 将导致“RESIGNAL when handler not active”错误。

要从诊断信息中检索信息,请使用 GET DIAGNOSTICS 语句(见Section 15.6.7.3, “GET DIAGNOSTICS Statement”)。关于诊断信息的信息,请见Section 15.6.7.7, “The MySQL Diagnostics Area”

对于 condition_valuesignal_information_item,定义和规则与RESIGNALSIGNAL相同。例如,condition_value 可以是一个 SQLSTATE 值,值可以表示错误、警告或not found.。更多信息,请见第15.6.7.5节,“SIGNAL 语句”

RESIGNAL 语句接受 condition_valueSET take 两个可选的子句,这导致了多种可能的使用:

  • RESIGNAL alone:

    RESIGNAL;
  • RESIGNAL with new signal information:

    RESIGNAL SET signal_information_item [, signal_information_item] ...;
  • RESIGNAL with a condition value and possibly new signal information:

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

这些用例都将导致诊断信息和条件信息的变化:

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

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

诊断信息区有一个栈。当处理器获取控制权时,它将诊断信息区推到栈的顶部,因此在处理器执行期间有两个诊断信息区:

  • 第一个(当前)诊断信息区,从最后一个诊断信息区复制,但在处理器中的第一个语句更改当前诊断信息区时被覆盖。

  • 最后(堆栈)诊断信息区,包含在处理器获取控制权前设置的条件信息区。

诊断信息区中的最大条件信息数量由max_error_count 系统变量确定。请见Diagnostics Area-Related System Variables

简单的RESIGNAL alone意味着pass on the error with no change.它恢复最后的诊断信息区并将其设置为当前诊断信息区。这就是它pops诊断信息栈。

在捕捉条件的处理器中,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 a SET clause provides new signal information, so the statement means pass on the error with changes:

RESIGNAL SET signal_information_item [, signal_information_item] ...;

RESIGNAL alone,RESIGNAL SET语句的目的是弹出诊断信息栈,使原始信息出去。与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 with a condition value means push a condition into the current diagnostics area. If the SET clause is present, it also changes the error information.

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 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()中的执行有自己的上下文,这不是处理器上下文。因此,RESIGNALf()中的结果是一个handler not active错误。