跳到主要内容

SIGNAL

SIGNAL 语句是一种"返回"错误的方式。SIGNAL 向处理程序、应用程序的外部或客户端提供错误信息。此外,它还提供对错误特性(错误码、SQLSTATE 值、消息)的控制。

语法和参数说明

如果没有 SIGNAL,就必须采取其他方法来返回错误,例如故意引用不存在的表以导致例程返回错误。

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

SIGNAL 语句的语法如下:

SIGNAL 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: {
MESSAGE_TEXT
| MYSQL_ERRNO

}

SIGNAL 语句中的 condition_value 表示要返回的错误值。它可以是一个 SQLSTATE 值(一个占 5 个字符的字符串字面量)或一个 condition_name,它引用先前使用 DECLARE ... CONDITION 定义的命名条件(请参见 DECLARE ... CONDITION

SQLSTATE 值可以指示错误、告警或"not found"。该值的前两个字符表示其错误类别。一些信号值导致语句终止;请参见 信号对处理程序、游标和语句的影响

SIGNAL 语句的 SQLSTATE 值不应以 '00' 开头,因为这样的值表示成功并且对于发出错误信号是无效的,无论是在 SIGNAL 语句中直接指定 SQLSTATE 值,还是在语句中引用的命名条件中指定 SQLSTATE 值,都是如此。如果该值无效,则会发生 Bad SQLSTATE 错误。

要发出通用 SQLSTATE 值的信号,请使用"45000",含义是"unhandled user-defined exception"。

SIGNAL 语句可以包含一个 SET 子句(可选项),该子句可以包含多个信号项,并位于 condition_information_item_name = simple_value_specification 列表中,用逗号分隔。

每个 condition_information_item_name 只能在 SET 子句中被指定一次。否则,会出现错误 Duplicate condition information item

可以使用存储过程或函数参数、使用 DECLARE 声明的存储程序局部变量、用户自定义变量、系统变量或字面量来指定有效的 simple_value_specification 指示符。

有关 condition_information_item_name 值的信息,请参见 信号条件信息项

如下示例中,存储过程 proc 根据 pval 的值(其输入参数)发出错误或告警信号。

CREATE PROCEDURE proc(pval INT)
BEGIN
DECLARE psign CONDITION FOR SQLSTATE '45000';
IF pval = 0 THEN
SIGNAL SQLSTATE '01000';
ELSEIF pval = 1 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'An error occurred';
ELSEIF pval = 2 THEN
SIGNAL psign
SET MESSAGE_TEXT = 'An error occurred';
ELSE
SIGNAL SQLSTATE '01000'
SET MESSAGE_TEXT = 'A warning occurred', MYSQL_ERRNO = 1001;
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'An error occurred', MYSQL_ERRNO = 1002;
END IF;
END;

如果 pval 为 0,则 proc() 发出告警信号,因为以 '01' 开头的 SQLSTATE 值是告警类别的信号。该告警不会终止过程,并且可以在过程返回后通过 SHOW WARNINGS 查看。

如果 pval 为 1,则 proc() 发出错误信号并设置 MESSAGE_TEXT 条件信息项。错误会终止过程,并返回带有错误信息的文本。

如果 pval 为 2,则会发出相同的错误信号,尽管在这种情况下 SQLSTATE 值是使用已命名的条件指定的。

如果 pval 是其他任何内容,proc() 首先发出警告信号并设置消息文本和错误编号条件信息项。此告警不会终止过程,因此会继续执行,然后 proc() 会发出错误信号。该错误会终止该过程。告警设置的消息文本和错误编号被错误设置的值替换,这些值与错误信息一起返回。

SIGNAL 通常在存储程序中使用,但作为扩展功能,允许在处理程序上下文之外使用它。例如,当调用 mysql 客户端程序时,您可以在提示符处输入以下语句:

SIGNAL SQLSTATE '66666';

CREATE TRIGGER trg BEFORE INSERT ON tbl
FOR EACH ROW SIGNAL SQLSTATE '66666';

SIGNAL 的执行规则

SIGNAL 的执行规则如下:

  • 如果 SIGNAL 语句指示特定的 SQLSTATE 值,则该值用于指示指定的条件。示例如下:

    CREATE PROCEDURE proc(divisor INT)
    BEGIN
    IF divisor = 0 THEN
    SIGNAL SQLSTATE '22012';
    END IF;
    END;
  • 如果 SIGNAL 语句使用已命名的条件,则必须在适用于 SIGNAL 语句的某个范围内声明条件,并且必须使用 SQLSTATE 值而不是错误码来定义条件。如果指定的条件不存在于 SIGNAL 语句的范围内,则会引发报错"Undefined CONDITION"。示例如下:

    CREATE PROCEDURE proc(divisor INT)
    BEGIN
    DECLARE div_by_zero CONDITION FOR SQLSTATE '22012';
    IF divisor = 0 THEN
    SIGNAL div_by_zero;
    END IF;
    END;
  • 如果 SIGNAL 引用的是使用错误码而不是 SQLSTATE 值定义的已命名条件,则会报错"SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE"。以下语句会导致该错误,因为命名条件与错误码相关联:

    DECLARE no_table_found CONDITION FOR 1051;
    SIGNAL no_table_found;
  • 如果具有指定名称的条件在不同范围内多次声明,则应用具有局部范围的声明。

    如下示例中,如果 divisor 为 0,则执行第一个 SIGNAL 语句。最里面的 one_error 条件声明适用,并引发 SQLSTATE '22012'。如果 divisor 不为 0,则执行第二个 SIGNAL 语句。最外层的 one_error 条件声明适用,并引发 SQLSTATE '45000'

    CREATE PROCEDURE proc(divisor INT)
    BEGIN
    DECLARE one_error CONDITION FOR SQLSTATE '45000';
    IF divisor = 0 THEN
    BEGIN
    DECLARE one_error CONDITION FOR SQLSTATE '22012';
    SIGNAL one_error;
    END;
    END IF;
    SIGNAL one_error;
    END;
  • 可以在异常处理程序中引发信号。如下示例中,CALL proc() 获取 DROP TABLE 语句。由于没有名为 no_table_found 的表,因此激活了错误处理程序。错误处理程序会破坏原始错误("no such table")并使用 SQLSTATE '99999'An error occurred 来显示报错。

    CREATE PROCEDURE proc()
    BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
    SIGNAL SQLSTATE VALUE '99999'
    SET MESSAGE_TEXT = 'An error occurred';
    END;
    DROP TABLE no_table_found;
    END;

信号条件信息项

对于标准 SQL,下表列出了可以在 SIGNAL(或 RESIGNAL)语句中设置的诊断区域条件信息项的名称,其中 MYSQL_ERRNO 是扩展项。

信息项名称数据类型
MESSAGE_TEXTVARCHAR(64)
MYSQL_ERRNOSMALLINT UNSIGNED

字符项的字符集是 UTF-8。条件信息项不能将 NULL 分配给 SIGNAL 语句。

SIGNAL 语句总是直接或间接通过引用由 SQLSTATE 值定义的条件来指定 SQLSTATE 值。SQLSTATE 值的前两个字符是它的类别,类别决定了条件信息项的默认值,如下表所示。

SQLSTATE 值的类别说明
Class = '00' (success)非法的。以 '00' 开头的 SQLSTATE 值表示成功并且对 SIGNAL 无效。
Class = '01' (warning)MESSAGE_TEXT='Unhandled user-defined warning condition'; MYSQL_ERRNO=ER_SIGNAL_WARN
Class = '02' (not found)MESSAGE_TEXT='Unhandled user-defined not found condition'; MYSQL_ERRNO=ER_SIGNAL_NOT_FOUND
Class > '02' (exception)MESSAGE_TEXT='Unhandled user-defined exception condition'; MYSQL_ERRNO=ER_SIGNAL_EXCEPTION

SIGNAL 执行后获得的错误值是由 SIGNAL 语句和 MESSAGE_TEXTMYSQL_ERRNO 项引发的 SQLSTATE 值。这些值可从如下 C API 获得:

  • mysql_sqlstate() 返回 SQLSTATE 值。

  • mysql_errno() 返回 MYSQL_ERRNO 值。

  • mysql_error() 返回 MESSAGE_TEXT 值。

在 SQL 级别,使用 SHOW WARNINGSSHOW ERRORS 输出的 CodeMessage 列指示 MYSQL_ERRNOMESSAGE_TEXT 的值。

要从诊断区域检索信息,请使用 GET DIAGNOSTICS 语句,详细信息请参见 GET DIAGNOSTICS

信号对处理程序、游标和语句的影响

信号的类别对语句执行有不同的影响,如下表所示。类别用于确定错误的严重程度。SIGNAL 的目的是显式地引发用户生成的错误,因此信号永远不会被忽略。sql_mode 系统变量的值会被忽略,特别是在严格模式下。

SQLSTATE 值的类别说明
Class = '00' (success)非法的。以 '00' 开头的 SQLSTATE 值表示成功并且对 SIGNAL 无效。
Class = '01' (warning)SHOW WARNINGS 显示信号。SQLWARNING 处理程序捕获信号。 因为导致函数返回的 RETURN 语句会清除诊断区域,所以无法从存储函数返回告警。该语句会清除可能存在的任何告警(并将 warning_count 重置为 0)。
Class = '02' (not found)NOT FOUND 处理程序捕获信号。对游标没有影响。如果信号在存储函数中未被处理(即没有使用 DECLARE ... HANDLER 定义已发出的 SQLSTATE 值的处理程序),则语句结束。
Class > '02' (exception)SQLEXCEPTION 处理程序捕获信号。如果信号在存储函数中未被处理(即没有使用 DECLARE ... HANDLER 定义已发出的 SQLSTATE 值的处理程序),则语句结束。
Class = '40'视为普通异常。