15.6.7.5 信号语句
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: {
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)
SIGNAL
是返回错误的方式。 SIGNAL
提供了错误信息给处理程序、应用程序的外部部分或客户端。它还提供了错误的特征(错误号、SQLSTATE
值、消息)。没有 SIGNAL
,需要使用工作-around方法,如故意引用不存在的表来导致一个程序返回错误。
不需要任何权限来执行 SIGNAL
语句。
要从诊断区域中检索信息,请使用 GET DIAGNOSTICS
语句(见 第15.6.7.3节,“GET DIAGNOSTICS 语句”)。关于诊断区域的信息,请见 第15.6.7.7节,“MySQL 诊断区域”。
在 SIGNAL
语句中的 condition_value
表示要返回的错误值。它可以是一个 SQLSTATE
值(5个字符的字符串字面量)或一个 condition_name
,该名称引用之前使用 DECLARE ... CONDITION
声明的命名条件(见 第15.6.7.1节,“DECLARE ... CONDITION 语句”)。
一个 SQLSTATE
值可以表示错误、警告或““not found.””。该值的前两个字符表示错误类别,详见 信号条件信息项。一些信号值会导致语句终止;见 信号对处理程序、游标和语句的影响。
SQLSTATE 值对于SIGNAL
语句应该不以 '00'
开头,因为这样的值表示成功且无效用于错误 signaling。这是无论 SQLSTATE 值是在SIGNAL
语句中指定的还是在语句中引用的命名条件中指定的。如果值无效,将出现 Bad SQLSTATE
错误。
要 signal 一个通用的 SQLSTATE 值,可以使用 '45000'
,它表示““未处理的用户定义异常。””
SIGNAL 语句可选地包括一个 SET
子句,该子句包含多个信号项目的列表,使用逗号分隔的 condition_information_item_name
= simple_value_specification
分配语句。
每个 condition_information_item_name
可以在 SET
子句中指定最多一次。否则,将出现 Duplicate condition information item
错误。
有效的 simple_value_specification
设定符可以使用存储程序或函数参数、存储程序本地变量、用户定义变量、系统变量或字面值指定。字符字面值可能包含 _charset
引入符。
有关可接受的 condition_information_item_name
值的信息,请参阅Signal Condition Information Items。
以下过程根据 pval
的值 signal 错误或警告:
CREATE PROCEDURE p (pval INT)
BEGIN
DECLARE specialty 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 specialty
SET MESSAGE_TEXT = 'An error occurred';
ELSE
SIGNAL SQLSTATE '01000'
SET MESSAGE_TEXT = 'A warning occurred', MYSQL_ERRNO = 1000;
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'An error occurred', MYSQL_ERRNO = 1001;
END IF;
END;
如果 pval
是 0,p()
signal 一个警告,因为 SQLSTATE 值以 '01'
开头是警告类信号。这不终止过程,可以使用SHOW WARNINGS
在过程返回后查看警告。
如果 pval
是 1,p()
signal 错误并设置 MESSAGE_TEXT
条件信息项目。错误终止过程,并返回错误信息。
如果 pval
是 2,p()
signal 同一个错误,但是使用命名条件指定 SQLSTATE 值。
如果 pval
是任何其他值,p()
首先 signal 一个警告,并设置错误信息项目。这个警告不终止过程,所以执行继续,然后 p()
signal 错误。错误终止过程,并返回错误信息。
SIGNAL
通常在存储程序中使用,但它是 MySQL 扩展,可以在非处理器上下文中使用。例如,如果您使用 mysql 客户端程序,可以在提示符下输入以下语句:
SIGNAL SQLSTATE '77777';
CREATE TRIGGER t_bi BEFORE INSERT ON t
FOR EACH ROW SIGNAL SQLSTATE '77777';
CREATE EVENT e ON SCHEDULE EVERY 1 SECOND
DO SIGNAL SQLSTATE '77777';
SIGNAL
执行根据以下规则:
如果 SIGNAL
语句指示特定的 SQLSTATE
值,该值将用来.signal 指定的条件。示例:
CREATE PROCEDURE p (divisor INT)
BEGIN
IF divisor = 0 THEN
SIGNAL SQLSTATE '22012';
END IF;
END;
如果 SIGNAL
语句使用命名条件,该条件必须在 SIGNAL
语句的作用域中声明,并且必须使用 SQLSTATE
值,而不是 MySQL 错误号。示例:
CREATE PROCEDURE p (divisor INT)
BEGIN
DECLARE divide_by_zero CONDITION FOR SQLSTATE '22012';
IF divisor = 0 THEN
SIGNAL divide_by_zero;
END IF;
END;
如果命名条件在 SIGNAL
语句的作用域中不存在,会出现 Undefined CONDITION
错误。
如果 SIGNAL
指向命名条件,该条件定义了 MySQL 错误号,而不是 SQLSTATE
值,会出现 SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE
错误。以下语句会出现该错误,因为命名条件与 MySQL 错误号相关:
DECLARE no_such_table CONDITION FOR 1051;
SIGNAL no_such_table;
如果具有给定名称的条件在不同的作用域中多次声明,声明在最内层作用域中应用。考虑以下过程:
CREATE PROCEDURE p (divisor INT)
BEGIN
DECLARE my_error CONDITION FOR SQLSTATE '45000';
IF divisor = 0 THEN
BEGIN
DECLARE my_error CONDITION FOR SQLSTATE '22012';
SIGNAL my_error;
END;
END IF;
SIGNAL my_error;
END;
如果 divisor
是 0,第一个 SIGNAL
语句执行。最内层的 my_error
条件声明应用,引发 SQLSTATE
'22012'
。
如果 divisor
不是 0,第二个 SIGNAL
语句执行。最外层的 my_error
条件声明应用,引发 SQLSTATE
'45000'
。
关于服务器在条件出现时选择处理器的信息,请参阅 Section 15.6.7.6, “Scope Rules for Handlers”。
可以在异常处理器中引发信号:
CREATE PROCEDURE p ()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SIGNAL SQLSTATE VALUE '99999'
SET MESSAGE_TEXT = 'An error occurred';
END;
DROP TABLE no_such_table;
END;
CALL p()
到达 DROP TABLE
语句。没有名为 no_such_table
的表,所以错误处理器被激活。错误处理器销毁原始错误(““no such table””)并创建一个新的错误,具有 SQLSTATE
'99999'
和消息 An error occurred
。
以下表格列出了可以在SIGNAL
(或RESIGNAL
)语句中设置的诊断信息项名称。所有项都是标准SQL,except MYSQL_ERRNO
,这是MySQL的扩展。关于这些项的更多信息,请参见第15.6.7.7节,“MySQL 诊断信息”。
Item Name Definition
--------- ----------
CLASS_ORIGIN VARCHAR(64)
SUBCLASS_ORIGIN VARCHAR(64)
CONSTRAINT_CATALOG VARCHAR(64)
CONSTRAINT_SCHEMA VARCHAR(64)
CONSTRAINT_NAME VARCHAR(64)
CATALOG_NAME VARCHAR(64)
SCHEMA_NAME VARCHAR(64)
TABLE_NAME VARCHAR(64)
COLUMN_NAME VARCHAR(64)
CURSOR_NAME VARCHAR(64)
MESSAGE_TEXT VARCHAR(128)
MYSQL_ERRNO SMALLINT UNSIGNED
字符集为 UTF-8。
在SIGNAL
语句中不能将NULL
分配给诊断信息项。
一个SIGNAL
语句总是指定一个SQLSTATE
值,直接或间接地通过引用一个定义了SQLSTATE
值的命名条件。一个SQLSTATE
值的前两个字符是其类别,类别确定了诊断信息项的默认值:
-
类别=
'00'
(成功)类别
'00'
表示成功,但不是SIGNAL
语句的有效值。 -
类别=
'01'
(警告)MESSAGE_TEXT = 'Unhandled user-defined warning condition'; MYSQL_ERRNO = ER_SIGNAL_WARN
-
类别=
'02'
(未找到)MESSAGE_TEXT = 'Unhandled user-defined not found condition'; MYSQL_ERRNO = ER_SIGNAL_NOT_FOUND
-
类别>
'02'
(异常)MESSAGE_TEXT = 'Unhandled user-defined exception condition'; MYSQL_ERRNO = ER_SIGNAL_EXCEPTION
对于合法的类别,其他诊断信息项将被设置为以下方式:
CLASS_ORIGIN = SUBCLASS_ORIGIN = '';
CONSTRAINT_CATALOG = CONSTRAINT_SCHEMA = CONSTRAINT_NAME = '';
CATALOG_NAME = SCHEMA_NAME = TABLE_NAME = COLUMN_NAME = '';
CURSOR_NAME = '';
执行SIGNAL
语句后可访问的错误值是SIGNAL
语句引发的SQLSTATE
值和MESSAGE_TEXT
和MYSQL_ERRNO
项。这些值可以从C API中访问:
-
mysql_sqlstate()
返回SQLSTATE
值。 -
mysql_errno()
返回MYSQL_ERRNO
值。 -
mysql_error()
返回MESSAGE_TEXT
值。
在SQL级别,SHOW WARNINGS
和SHOW ERRORS
语句的输出指示MYSQL_ERRNO
和MESSAGE_TEXT
值在Code
和Message
列中。
要从诊断区域中获取信息,请使用GET DIAGNOSTICS
语句(见第15.6.7.3节,“GET DIAGNOSTICS 语句”)。关于诊断区域的信息,请见第15.6.7.7节,“MySQL 诊断区域”。
信号对处理程序、游标和语句的影响
信号对语句执行的影响取决于信号类别。该类别确定错误的严重性。MySQL忽略了sql_mode
系统变量的值;特别是,严格SQL模式不起作用。MySQL也忽略了IGNORE
:SIGNAL
的目的是明确地引发用户生成的错误,因此信号永不被忽略。
以下描述中,“unhandled”表示没有为信号的SQLSTATE
值定义了处理程序,以DECLARE ... HANDLER
语句。
-
Class =
'00'
(成功)非法。以
'00'
开头的SQLSTATE
值表示成功,并且不适用于SIGNAL
语句。 -
Class =
'01'
(警告)warning_count
系统变量的值增加。SHOW WARNINGS
显示信号。SQLWARNING
处理程序捕捉信号。警告不能从存储函数中返回,因为
RETURN
语句使函数返回,清除诊断区域。语句因此清除可能存在的警告(并将warning_count
重置为0)。 -
Class =
'02'
(未找到)NOT FOUND
处理程序捕捉信号。如果信号在存储函数中未处理,语句结束。 -
Class >
'02'
(异常)SQLEXCEPTION
处理程序捕捉信号。如果信号在存储函数中未处理,语句结束。 -
Class =
'40'
视为普通异常。