DECLARE条件处理
在存储的程序执行过程中可能会出现需要特殊处理的条件,例如退出当前程序块或继续执行。可以为一般条件(例如警告或异常)或特定条件(例如特定的错误代码)定义处理程序。可以为特定条件分配名称,并在处理程序中以这种方式进行引用。
要命名条件,请使用DECLARE ... CONDITION
语句。要声明处理程序,请使用以下DECLARE ... HANDLER
语句。请参见“ DECLARE ... CONDITION语句”和“ DECLARE ... HANDLER语句”。有关在条件发生时服务器如何选择处理程序的信息,请参见“处理程序的作用域规则”。
要提出条件,请使用SIGNAL
语句。要在条件处理程序中修改条件信息,请使用RESIGNAL
。请参见“ DECLARE ... CONDITION语句”和“ DECLARE ... HANDLER语句”。
要从诊断区域检索信息,请使用该GET DIAGNOSTICS
语句(请参见“ GET DIAGNOSTICS语句”)。
DECLARE ... CONDITION声明
DECLARE condition_nameCONDITION FOR condition_value condition_value: { mysql_error_code |SQLSTATE [VALUE ] sqlstate_value }
该DECLARE ... CONDITION
语句声明一个命名错误条件,将名称与需要特定处理的条件相关联。可以在后续DECLARE ... HANDLER
语句中引用该名称(请参见“ DECLARE ... HANDLER语句”)。
条件声明必须出现在游标或处理程序声明之前。
该condition_value
用于DECLARE ... CONDITION
指示特定条件或类的条件与状况名合伙人。它可以采用以下形式:
mysql_error_code
:整数文字,指示MySQL错误代码。不要使用MySQL错误代码0,因为这表示成功而不是错误情况。有关MySQL错误代码的列表,请参见第B.3.1节“服务器错误消息参考”。
SQLSTATE[VALUE]
sqlstate_value
:5个字符的字符串文字,指示SQLSTATE值。不要使用以开头的SQLSTATE值,
'00'
因为它们表示成功而不是错误情况。有关SQLSTATE值的列表,请参见第B.3.1节“服务器错误消息参考”。
引用SIGNAL
或使用RESIGNAL
语句中的条件名称必须与SQLSTATE值关联,而不是与MySQL错误代码关联。
使用名称作为条件可以帮助使存储的程序代码更清晰。例如,此处理程序适用于尝试删除不存在的表的情况,但是只有当您知道1051是“未知表”的MySQL错误代码时,此处理程序才可见:
DECLARE CONTINUE HANDLER FOR 1051BEGIN -- body of handlerEND ;
通过为条件声明名称,可以更容易地看到处理程序的目的:
DECLARE no_such_tableCONDITION FOR 1051;DECLARE CONTINUE HANDLER FOR no_such_tableBEGIN -- body of handlerEND ;
这是相同条件的命名条件,但是基于相应的SQLSTATE值而不是MySQL错误代码:
DECLARE no_such_tableCONDITION FOR SQLSTATE '42S02';DECLARE CONTINUE HANDLER FOR no_such_tableBEGIN -- body of handlerEND ;
DECLARE ... HANDLER语句
DECLARE handler_actionHANDLER FOR condition_value [, condition_value] ... statement handler_action: {CONTINUE |EXIT |UNDO } condition_value: { mysql_error_code |SQLSTATE [VALUE ] sqlstate_value | condition_name |SQLWARNING | NOTFOUND |SQLEXCEPTION }
该DECLARE ... HANDLER
语句指定处理一个或多个条件的处理程序。如果出现这些情况之一,则statement
执行指定的命令。statement
可以是诸如的简单语句,也可以是使用和编写的复合语句(请参见“ BEGIN ... END复合语句”)。SET var_name=value
BEGIN
END
处理程序声明必须出现在变量或条件声明之后。
该handler_action
值指示在执行处理程序语句后处理程序将执行的操作:
CONTINUE
:继续执行当前程序。EXIT
:对于BEGIN ... END
在其中声明处理程序的复合语句,执行终止。即使条件发生在内部块中,也是如此。UNDO
:不支持。
condition_value
用于DECLARE ... HANDLER
表明激活处理程序中的特定条件或一类的条件。它可以采用以下形式:
mysql_error_code
:整数文字,指示MySQL错误代码,例如1051,用于指定“未知表”:DECLARE CONTINUE HANDLER FOR 1051BEGIN -- body of handlerEND ;不要使用MySQL错误代码0,因为这表示成功而不是错误情况。有关MySQL错误代码的列表,请参见第B.3.1节“服务器错误消息参考”。
SQLSTATE[VALUE]
sqlstate_value
:5个字符的字符串文字,指示SQLSTATE值,例如'42S01'
用于指定“ unknown table ”:DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'BEGIN -- body of handlerEND ;不要使用以开头的SQLSTATE值,
'00'
因为它们表示成功而不是错误情况。有关SQLSTATE值的列表,请参见第B.3.1节“服务器错误消息参考”。condition_name
:之前用指定的条件名称DECLARE ... CONDITION
。条件名称可以与MySQL错误代码或SQLSTATE值关联。请参见“ DECLARE ... CONDITION语句”。SQLWARNING
:以开头的SQLSTATE值的类的简写'01'
。DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN -- body of handlerEND ;NOT FOUND
:以开头的SQLSTATE值的类的简写'02'
。这在游标的上下文中是相关的,用于控制游标到达数据集末尾时发生的情况。如果没有更多行可用,则使用SQLSTATE value发生No Data条件'02000'
。要检测此条件,可以为其设置一个处理程序或为一个NOT FOUND
条件设置处理程序。DECLARE CONTINUE HANDLER FOR NOTFOUND BEGIN -- body of handlerEND ;有关另一个示例,请参见“游标语句”。
NOT FOUND
对于不检索行的语句,也会发生这种情况。SELECT ... INTO var_list
SQLEXCEPTION
:速记类SQLSTATE值不开头'00'
,'01'
或'02'
。DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN -- body of handlerEND ;
有关在条件发生时服务器如何选择处理程序的信息,请参见“处理程序的作用域规则”。
如果发生未声明任何处理程序的条件,则采取的操作取决于条件类:
- 对于
SQLEXCEPTION
条件,存储程序终止于引发条件的语句,就像有一个EXIT
处理程序一样。如果该程序是由另一个存储程序调用的,则调用程序将使用应用于其自身处理程序的处理程序选择规则来处理该条件。 - 对于
SQLWARNING
条件,程序将继续执行,就像有一个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.tVALUES (1);SET @x = 2;INSERT INTO test.tVALUES (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 | +------+ 1row in set (0.00 sec)
请注意,这@x
是3
在过程执行之后,这表明在错误发生之后,执行将继续到过程结束。如果该DECLARE ... HANDLER
语句不存在,则MySQL将由于约束而EXIT
在第二次INSERT
失败后采取默认操作()PRIMARY KEY
,并SELECT @x
已返回2
。
要忽略条件,请CONTINUE
为其声明一个处理程序,并将其与一个空块关联。例如:
DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END ;
块标签的范围不包括在块内声明的处理程序的代码。因此,与处理程序关联的语句不能使用ITERATE
或LEAVE
引用包含处理程序声明的块的标签。考虑以下示例,其中该REPEAT
块的标签为retry
:
CREATE PROCEDURE p ()BEGIN DECLARE i INTDEFAULT 3; retry:REPEAT BEGIN DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN ITERATE retry; # illegalEND ;IF i < 0THEN LEAVE retry; # legalEND IF ;SET i = i - 1;END ;UNTIL FALSEEND 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 statementsEND ;要继续执行,请在
CONTINUE
处理程序中设置一个状态变量,可以在封闭的块中对其进行检查,以确定是否调用了该处理程序。以下示例done
为此目的使用了变量:CREATE PROCEDURE p ()BEGIN DECLARE i INTDEFAULT 3;DECLARE done INTDEFAULT FALSE; retry:REPEAT BEGIN DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN SET done = TRUE;END ;IF done OR i < 0THEN LEAVE retry;END IF ;SET i = i - 1;END ;UNTIL FALSEEND REPEAT ;END ;