13.6.7.2 DECLARE ... HANDLER 语句
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
}
声明...处理程序语句指定处理一个或多个条件的处理程序。如果出现这些情况之一,则执行指定的* statement
*。 * statement
*可以是简单的语句,例如SET var_name = value
,也可以是使用BEGIN
和END
编写的复合语句(请参见第 13.6.1 节“ BEGIN ... END 复合语句”)。
处理程序声明必须出现在变量或条件声明之后。
handler_action
*值指示在执行处理程序语句后处理程序将执行什么操作:
-
CONTINUE
:continue 执行当前程序。 -
EXIT
:对于声明处理程序的开始...结束复合语句,执行终止。即使条件发生在内部块中,也是如此。 -
UNDO
:不支持。
声明...处理程序的* condition_value
*table 示激活处理程序的特定条件或条件类别。它可以采用以下形式:
-
mysql_error_code
*:指示 MySQL 错误代码的整数 Literals,例如 1051,用于指定“未知 table”:
DECLARE CONTINUE HANDLER FOR 1051
BEGIN
-- body of handler
END;
不要使用 MySQL 错误代码 0,因为这 table 示成功而不是错误情况。有关 MySQL 错误代码的列 table,请参见第 B.3.1 节“服务器错误消息参考”。
- SQLSTATE [VALUE] *
sqlstate_value
*:5 个字符的字符串 Literals,指示 SQLSTATE 值,例如'42S01'
,用于指定“未知 table”:
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
BEGIN
-- body of handler
END;
不要使用以'00'
开头的 SQLSTATE 值,因为这些值 table 示成功而不是错误情况。有关 SQLSTATE 值的列 table,请参见第 B.3.1 节“服务器错误消息参考”。
-
condition_name
*:先前用声明...条件指定的条件名称。条件名称可以与 MySQL 错误代码或 SQLSTATE 值关联。参见第 13.6.7.1 节“ DECLARE ... CONDITION 语句”。
-
SQLWARNING
:以'01'
开头的 SQLSTATE 值类的简写。
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
-- body of handler
END;
NOT FOUND
:以'02'
开头的 SQLSTATE 值类的简写。这在游标的上下文中是相关的,用于控制游标到达数据集末尾时发生的情况。如果没有更多行可用,则使用 SQLSTATE 值'02000'
发生 No Data 条件。要检测此条件,可以为其设置处理程序或NOT FOUND
条件。
DECLARE CONTINUE HANDLER FOR NOT FOUND
BEGIN
-- body of handler
END;
有关另一个示例,请参见第 13.6.6 节“游标”。对于不检索任何行的SELECT ... INTO var_list
语句,也会发生NOT FOUND
条件。
SQLEXCEPTION
:不是以'00'
,'01'
或'02'
开头的 SQLSTATE 值类别的简写。
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
-- body of handler
END;
有关在条件发生时服务器如何选择处理程序的信息,请参见第 13.6.7.6 节“处理程序的范围规则”。
如果发生未声明任何处理程序的条件,则采取的操作取决于条件类:
-
对于
SQLEXCEPTION
条件,存储程序终止于引发该条件的语句,就像存在EXIT
处理程序一样。如果该程序被另一个存储程序调用,则调用程序使用应用于其自己的处理程序的处理程序选择规则来处理该条件。 -
对于
SQLWARNING
条件,程序将 continue 执行,就像有CONTINUE
处理程序一样。 -
对于
NOT FOUND
条件,如果条件正常升高,则动作为CONTINUE
。如果它是由SIGNAL或RESIGNAL引发的,则动作为EXIT
。
以下示例对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
,这 table 明在错误发生之后,执行将 continue 到过程结束。如果不存在声明...处理程序语句,则在第二个INSERT由于PRIMARY KEY
约束而失败后,MySQL 将采取默认操作(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
处理程序。如果不需要块清除,则开始...结束处理程序主体可以为空:
DECLARE EXIT HANDLER FOR SQLWARNING BEGIN END;
否则,将清除语句放入处理程序主体中:
DECLARE EXIT HANDLER FOR SQLWARNING
BEGIN
block cleanup statements
END;
- 要 continue 执行,请在
CONTINUE
处理程序中设置状态变量,可以在封闭的块中检查该状态变量以确定是否调用了该处理程序。下面的示例为此使用变量done
:
CREATE 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;