跳到主要内容

处理程序的有效范围

存储程序可以包括当程序内发生某些条件时要调用的处理程序。每个处理程序的适用性取决于它在程序定义中的位置以及它所处理的一个或多个条件。

处理程序的有效范围和相关规则

seekdb 处理程序的有效范围的相关规则如下:

  • BEGIN ... END 块中声明的处理程序仅适用于块中处理程序声明之后的 SQL 语句。如果处理程序本身引发一个条件,则它不能用于处理该条件,也不能在块中声明其他处理程序。在以下示例中,处理程序 h1h2 在语句 st1st2 引发的条件的有效范围内,但是不在 h1h2 主体中所引发的条件的有效范围内。

    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 值或条件名称。通用处理程序被 SQLWARNINGSQLEXCEPTIONNOT FOUND 类别中的条件所使用。条件特异性与条件优先级有关。

    可以在不同的范围内声明多个具有不同特性的处理程序。例如,外部块中可能有一个特定的错误代码处理程序,而内部块中可能有一个通用 SQLWARNING 处理程序。或者在同一块中可能有特定错误代码和通用 SQLWARNING 类别的处理程序。

处理程序是否被激活不仅取决于它自己的范围和条件值,还受到其他处理程序的影响。当存储程序中出现条件时,服务器会在当前范围(当前 BEGIN ... END 块)中搜索适用的处理程序。如果没有适用的处理程序,则继续向外搜索下一个范围(块)中的处理程序。当服务器在指定范围内找到一个或多个适用的处理程序时,它会根据条件优先级进行选择。条件优先级如下:

  • 错误代码处理程序优先于 SQLSTATE 值处理程序。

  • SQLSTATE 值处理程序优先于通用的 SQLWARNINGSQLEXCEPTIONNOT FOUND 处理程序。

  • SQLEXCEPTION 处理程序优先于 SQLWARNING 处理程序。

  • 可以有多个具有相同优先级的适用处理程序。例如,一条语句可以生成多个带有不同错误代码的警告,每个警告都存在一个特定于错误的处理程序。在这种情况下,服务器激活哪个处理程序的选择是不确定的,并且可能会根据情况发生的情况而改变。

如果多个适用的处理程序出现在不同的范围内,则局部范围的处理程序优先于外部范围内的处理程序,甚至优先级高于指定条件的处理程序。

如果条件发生时没有合适的处理程序,则根据条件的类别采取如下操作:

  • 对于 SQLEXCEPTION 条件,存储程序在引发条件的语句处终止,类似于使用了一个 EXIT 处理程序。如果该程序被另一个存储程序调用,则调用程序会使用自己的选择规则来处理该条件。

  • 对于 SQLWARNING 条件,程序会继续执行,类似于使用了一个 CONTINUE 处理程序。

  • 对于 NOT FOUND 条件,如果条件被正常引发,则操作为 CONTINUE。如果该条件是由 SIGNALRESIGNAL 引发的,则动作为 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'