处理程序的有效范围
存储程序可以包括当程序内发生某些条件时要调用的处理程序。每个处理程序的适用性取决于它在程序定义中的位置以及 它所处理的一个或多个条件。
处理程序的有效范围和相关规则
seekdb 处理程序的有效范围的相关规则如下:
-
在
BEGIN ... END块中声明的处理程序仅适用于块中处理程序声明之后的 SQL 语句。如果处理程序本身引发一个条件,则它不能用于处理该条件,也不能在块中声明其他处理程序。在以下示例中,处理程序h1和h2在语句st1和st2引发的条件的有效范围内,但是不在h1或h2主体中所引发的条件的有效范围内。BEGIN -- 外部块
DECLARE EXIT HANDLER FOR ...; -- 处理程序 h1
DECLARE EXIT HANDLER FOR ...; -- 处理程序 h2
st1;
st2;
END; -
处理程序仅在声明它的块的范围内有效,并且不能被发生在该块之外的条件所激活。在如下示例中,处理程序
h1在内部块中的st1范围内是有效的,但对于外部块中的st2是无效的:BEGIN -- 外部块
BEGIN -- 内部块
DECLARE EXIT HANDLER FOR ...; -- 处理程序 h1
st1;
END;
st2;
END; -
处理程序可以是特定的或通用的。特定的处理程序用于错误代码、
SQLSTATE值或条件名称。通用处理程序被SQLWARNING、SQLEXCEPTION或NOT FOUND类别中的条件所使用。条件特异性与条件优先级有关。可以在不同的范围内声明多个具有不同特性的处理程序。例如,外部块中可能有一个特定的错误代码处理程序,而内部块中可能有一个通用
SQLWARNING处理程序。或者在同一块中可能有特定错误代码和通用SQLWARNING类别的处理程序。
处理程序是否被激 活不仅取决于它自己的范围和条件值,还受到其他处理程序的影响。当存储程序中出现条件时,服务器会在当前范围(当前 BEGIN ... END 块)中搜索适用的处理程序。如果没有适用的处理程序,则继续向外搜索下一个范围(块)中的处理程序。当服务器在指定范围内找到一个或多个适用的处理程序时,它会根据条件优先级进行选择。条件优先级如下:
-
错误代码处理程序优先于
SQLSTATE值处理程序。 -
SQLSTATE值处理程序优先于通用的SQLWARNING、SQLEXCEPTION或NOT FOUND处理程序。 -
SQLEXCEPTION处理程序优先于SQLWARNING处理程序。 -
可以有多个具有相同优先级的适用处理程序。例如,一条语句可以生成多个带有不同错误代码的警告,每个警告都存在一个特定于错误的处理程序。在这种情况下,服务器激活哪个处理程序的选择是不确定的,并且可能会根据情况发生的情况而改变。
如果多个适用的处理程序出现在不同的范围内,则局部范围的处理程序优先于外部范围内的处理程序,甚至优先级高于指定条件的处理程序。
如果条件发生时没有合适的处理程序,则根据条件的类别采取如下操作:
-
对于
SQLEXCEPTION条件,存储程序在引发条件的语句处终止,类似于使用了一个EXIT处理程序。如果该程序被另一个存储程序调用,则调用程序会使用自己的选择规则来处理该条件。 -
对于
SQLWARNING条件,程序会继续执行,类似于使用了一个CONTINUE处理程序。 -
对于
NOT FOUND条件, 如果条件被正常引发,则操作为CONTINUE。如果该条件是由SIGNAL或RESIGNAL引发的,则动作为EXIT。
示例
示例 1 、示例 2 、示例 3 和示例 4 展示了如何应用处理程序的选择规则。
如下示例 1 中的过程包含两个处理程序,一个用于尝试删除不存在的表时发生指定 SQLSTATE 值 ('42S02'),另一个属于通用 SQLEXCEPTION 类别。
-- 示例 1
CREATE PROCEDURE proc1()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
SELECT 'SQLSTATE handler was activated' AS msg;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SELECT 'SQLEXCEPTION handler was activated' AS msg;
DROP TABLE test.tbl1;
END;
在示例 1 的情况下,两个处理程序都在同一个块中声明并具有相同的范围。但是,SQLSTATE 处理程序优先于 SQLEXCEPTION 处理程序,因此如果表 tbl1 不存在,则 DROP TABLE 语句会引发条件从而激活 SQLSTATE 处理程序。如下所示:
CALL proc1();
+--------------------------------+
| msg |
+--------------------------------+
| SQLSTATE handler was activated |
+--------------------------------+
1 row in set
如下示例 2 中,过程包含与示例 1 相同的两个处理程序。但是相对于 SQLSTATE 处理程序,DROP TABLE 语句和 SQLEXCEPTION 处理程序位于的内部块中。
-- 示例 2
CREATE PROCEDURE proc2()
BEGIN -- 外部块
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
SELECT 'SQLSTATE handler was activated' AS msg;
BEGIN -- 内部块
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SELECT 'SQLEXCEPTION handler was activated' AS msg;
DROP TABLE test.tbl1; -- 发生在内部块内
END;
END;
在示例 2 的情况下,如果处理程序位于更接近 条件发生位置就会优先被激活,所以 SQLEXCEPTION 处理程序被激活,即使它比 SQLSTATE 处理程序更通用。如下所示:
CALL proc2();
+------------------------------------+
| msg |
+------------------------------------+
| SQLEXCEPTION handler was activated |
+------------------------------------+
1 row in set
在如下示例 3 中,过程的一个处理程序在 DROP TABLE 语句范围内的块中声明:
-- 示例 3
CREATE PROCEDURE proc3()
BEGIN -- 外部块
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SELECT 'SQLEXCEPTION handler was activated' AS msg;
BEGIN -- 内部块
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
SELECT 'SQLSTATE handler was activated' AS msg;
END;
DROP TABLE test.tbl1; -- 发生在外部块内
END;
在示例 3 的情况下,SQLEXCEPTION 处理程序会被激活,因为 SQLSTATE 不在 DROP TABLE 所引发的条件范围内。如下所示:
CALL proc3();
+------------------------------------+
| msg |
+------------------------------------+
| SQLEXCEPTION handler was activated |
+------------------------------------+
1 row in set
在如下示例 4 中,两个处理程序都在 DROP TABLE 语句范围内的块中声明:
-- 示例 4
CREATE PROCEDURE proc4()
BEGIN -- 外部块
BEGIN -- 内部块
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SELECT 'SQLEXCEPTION handler was activated' AS msg;
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
SELECT 'SQLSTATE handler was activated' AS msg;
END;
DROP TABLE test.tbl1; -- 发生在外部块内
END;
在示例 4 的情况下,这两个处理程序都不适用,因为它们不在 DROP TABLE 的范围内。该语句引发的条件未处理并以错误终止该过程。如下所示:
CALL proc4();
ERROR 1051 (42S02): Unknown table 'test.tbl1'