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_TEXT | VARCHAR(64) |
| MYSQL_ERRNO | SMALLINT 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_TEXT 和 MYSQL_ERRNO 项引发的 SQLSTATE 值。这些值可从如下 C API 获得:
-
mysql_sqlstate()返回SQLSTATE值。 -
mysql_errno()返回MYSQL_ERRNO值。 -
mysql_error()返回MESSAGE_TEXT值。
在 SQL 级别,使用 SHOW WARNINGS 和 SHOW ERRORS 输出的 Code 和 Message 列指示 MYSQL_ERRNO 和 MESSAGE_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' | 视为普通异常。 |