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=valueBEGINEND
处理程序声明必须出现在变量或条件声明之后。
该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_listSQLEXCEPTION:速记类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 ;
