13.6.7.6 处理程序的范围规则

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

BEGIN -- outer block
  DECLARE EXIT HANDLER FOR ...;  -- handler H1
  DECLARE EXIT HANDLER FOR ...;  -- handler H2
  stmt1;
  stmt2;
END;
BEGIN -- outer block
  BEGIN -- inner block
    DECLARE EXIT HANDLER FOR ...;  -- handler H1
    stmt1;
  END;
  stmt2;
END;

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

处理程序是否被激活不仅取决于其自身的范围和条件值,还取决于存在其他哪些处理程序。当存储的程序中发生条件时,服务器将在当前范围(当前开始...结束块)中搜索适用的处理程序。如果没有适用的处理程序,则在每个连续的包含范围(块)中 continue 使用处理程序向外搜索。当服务器在给定范围内找到一个或多个适用的处理程序时,它将根据条件优先级在它们之间进行选择:

处理程序选择规则的一个含义是,如果多个适用的处理程序出现在不同的作用域中,则具有最局部作用域的处理程序将优先于外部作用域中的处理程序,甚至优先于更特定条件的处理程序。

如果条件发生时没有适当的处理程序,则采取的操作取决于条件的类:

以下示例演示 MySQL 如何应用处理程序选择规则。

此过程包含两个处理程序,一个用于处理试图删除不存在的 table 的特定SQLSTATE值('42S02'),另一个用于常规SQLEXCEPTION类:

CREATE PROCEDURE p1()
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.t;
END;

两个处理程序都在同一块中声明,并且具有相同的作用域。但是,SQLSTATE处理程序优先于SQLEXCEPTION处理程序,因此,如果 tablet不存在,则DROP TABLE语句将引发激活SQLSTATE处理程序的条件:

mysql> CALL p1();
+--------------------------------+
| msg                            |
+--------------------------------+
| SQLSTATE handler was activated |
+--------------------------------+

此过程包含相同的两个处理程序。但是这一次,DROP TABLE语句和SQLEXCEPTION处理程序相对于SQLSTATE处理程序位于内部块中:

CREATE PROCEDURE p2()
BEGIN -- outer block
    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
      SELECT 'SQLSTATE handler was activated' AS msg;
  BEGIN -- inner block
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
      SELECT 'SQLEXCEPTION handler was activated' AS msg;

    DROP TABLE test.t; -- occurs within inner block
  END;
END;

在这种情况下,优先于发生条件的地方的处理程序。 SQLEXCEPTION处理程序将激活,即使它比SQLSTATE处理程序更通用:

mysql> CALL p2();
+------------------------------------+
| msg                                |
+------------------------------------+
| SQLEXCEPTION handler was activated |
+------------------------------------+

在此过程中,其中一个处理程序在DROP TABLE语句范围内的一个块中声明:

CREATE PROCEDURE p3()
BEGIN -- outer block
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
    SELECT 'SQLEXCEPTION handler was activated' AS msg;
  BEGIN -- inner block
    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
      SELECT 'SQLSTATE handler was activated' AS msg;
  END;

  DROP TABLE test.t; -- occurs within outer block
END;

SQLEXCEPTION处理程序适用,因为另一个处理程序不在DROP TABLE引发的条件范围内:

mysql> CALL p3();
+------------------------------------+
| msg                                |
+------------------------------------+
| SQLEXCEPTION handler was activated |
+------------------------------------+

在此过程中,两个处理程序都在DROP TABLE语句范围内的块中声明:

CREATE PROCEDURE p4()
BEGIN -- outer block
  BEGIN -- inner block
    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.t; -- occurs within outer block
END;

这两个处理程序均不适用,因为它们不在DROP TABLE的范围内。语句引发的条件未处理,并以错误终止过程:

mysql> CALL p4();
ERROR 1051 (42S02): Unknown table 'test.t'
首页