DECLARE handler_action HANDLER
FOR condition_value [, condition_value] ...
statement
handler_action: {
CONTINUE
| EXIT
| UNDO
}
condition_value: {
mysql_error_code
| SQLSTATE [VALUE] sqlstate_value
| condition_name
| SQLWARNING
| NOT FOUND
| SQLEXCEPTION
}该 DECLARE ... HANDLER 语句指定一个用于处理一个或多个条件的处理程序。如果这些条件之一发生,则执行指定的 statement。 statement 可以是一个简单语句,例如 SET ,或者一个使用 var_name = valueBEGIN 和 END 编写的复合语句(参见 第 15.6.1 节,“BEGIN ... END 复合语句”)。
处理程序声明必须出现在变量或条件声明之后。
该 handler_action 值指示处理程序在执行处理程序语句后采取的操作
CONTINUE:当前程序的执行继续。EXIT:声明处理程序的BEGIN ... END复合语句的执行终止。即使条件发生在内部块中,也是如此。UNDO:不支持。
该 condition_value 用于 DECLARE ... HANDLER 指示激活处理程序的特定条件或条件类别。它可以采用以下形式
mysql_error_code: 一个整数文字,表示 MySQL 错误代码,例如 1051 表示 “unknown table”DECLARE CONTINUE HANDLER FOR 1051 BEGIN -- body of handler END;不要使用 MySQL 错误代码 0,因为这表示成功而不是错误条件。有关 MySQL 错误代码的列表,请参阅 服务器错误消息参考。
SQLSTATE [VALUE]
sqlstate_value: 一个 5 个字符的字符串文字,表示 SQLSTATE 值,例如'42S01'表示 “unknown table”DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' BEGIN -- body of handler END;不要使用以
'00'开头的 SQLSTATE 值,因为这些值表示成功而不是错误条件。有关 SQLSTATE 值的列表,请参阅 服务器错误消息参考。condition_name: 使用DECLARE ... CONDITION之前指定的条件名称。条件名称可以与 MySQL 错误代码或 SQLSTATE 值相关联。参见 第 15.6.7.1 节,“DECLARE ... CONDITION 语句”。SQLWARNING: 以'01'开头的 SQLSTATE 值的简写。DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN -- body of handler END;NOT FOUND: 以'02'开头的 SQLSTATE 值的简写。这在游标的上下文中是相关的,用于控制游标到达数据集末尾时发生的情况。如果不再有行可用,则会发生无数据条件,其 SQLSTATE 值为'02000'。要检测此条件,可以为其或NOT FOUND条件设置一个处理程序。DECLARE CONTINUE HANDLER FOR NOT FOUND BEGIN -- body of handler END;另一个例子,请参阅 第 15.6.6 节,“游标”。对于检索不到行的
SELECT ... INTO语句,也会发生var_listNOT FOUND条件。SQLEXCEPTION: 不以'00'、'01'或'02'开头的 SQLSTATE 值的简写。DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN -- body of handler END;
有关服务器在发生条件时如何选择处理程序的信息,请参阅 第 15.6.7.6 节,“处理程序的范围规则”。
如果发生没有声明处理程序的条件,采取的操作取决于条件类别。
以下示例使用 SQLSTATE '23000' 的处理程序,该程序会发生重复键错误。
mysql> CREATE TABLE test.t (s1 INT, PRIMARY KEY (s1));
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter //
mysql> CREATE PROCEDURE handlerdemo ()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
SET @x = 1;
INSERT INTO test.t VALUES (1);
SET @x = 2;
INSERT INTO test.t VALUES (1);
SET @x = 3;
END;
//
Query OK, 0 rows affected (0.00 sec)
mysql> CALL handlerdemo()//
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @x//
+------+
| @x |
+------+
| 3 |
+------+
1 row in set (0.00 sec)请注意,在过程执行后,@x 为 3,这表明在错误发生后,执行继续到过程的末尾。如果 DECLARE ... HANDLER 语句不存在,MySQL 会在第二次 INSERT 由于 PRIMARY KEY 约束而失败后采取默认操作(EXIT),并且 SELECT @x 将返回 2。
要忽略条件,请为其声明一个 CONTINUE 处理程序,并将其与一个空块相关联。例如:
DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;块标签的范围不包括块内声明的处理程序的代码。因此,与处理程序关联的语句不能使用 ITERATE 或 LEAVE 来引用包含处理程序声明的块的标签。请考虑以下示例,其中 REPEAT 块的标签为 retry
CREATE PROCEDURE p ()
BEGIN
DECLARE i INT DEFAULT 3;
retry:
REPEAT
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
ITERATE retry; # illegal
END;
IF i < 0 THEN
LEAVE retry; # legal
END IF;
SET i = i - 1;
END;
UNTIL FALSE END REPEAT;
END;retry 标签在块内的 IF 语句的范围内。它不在 CONTINUE 处理程序的范围内,因此那里的引用无效,会导致错误。
ERROR 1308 (42000): LEAVE with no matching label: retry为了避免在处理程序中引用外部标签,请使用以下策略之一。
要退出块,请使用
EXIT处理程序。如果不需要块清理,则BEGIN ... END处理程序主体可以为空。DECLARE EXIT HANDLER FOR SQLWARNING BEGIN END;否则,将清理语句放在处理程序主体中。
DECLARE EXIT HANDLER FOR SQLWARNING BEGIN block cleanup statements END;要继续执行,请在
CONTINUE处理程序中设置一个状态变量,以便在封闭的块中检查该变量,以确定是否调用了该处理程序。以下示例为此目的使用变量doneCREATE PROCEDURE p () BEGIN DECLARE i INT DEFAULT 3; DECLARE done INT DEFAULT FALSE; retry: REPEAT BEGIN DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN SET done = TRUE; END; IF done OR i < 0 THEN LEAVE retry; END IF; SET i = i - 1; END; UNTIL FALSE END REPEAT; END;