#### 13.6.7.6 处理程序的范围规则

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

-   在 a 中声明的处理程序[`开始...结束`](begin-end.html)块仅适用于块中处理程序声明之后的 SQL 语句。如果处理程序本身引发一个条件，它不能处理该条件，也不能在块中声明的任何其他处理程序。在以下示例中，处理程序`H1`和`H2`在语句引发的条件范围内*`stmt1`*和*`stmt2`*.但两者都没有`H1`也不`H2`是在正文中提出的条件的范围内`H1`要么`H2`.

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

-   处理程序仅在声明它的块的范围内，并且不能针对发生在该块之外的条件激活。在以下示例中，处理程序`H1`在范围内*`stmt1`*在内部块中，但不适用于*`stmt2`*在外部块中：

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

-   处理程序可以是特定的或一般的。一个特定的处理程序用于 MySQL 错误代码，`SQLSTATE`值或条件名称。通用处理程序是针对`SQL警告`,`SQL异常`， 要么`未找到`班级。条件特异性与条件优先级有关，如下所述。

    可以在不同的范围内声明多个处理程序，并具有不同的特性。例如，外部块中可能有一个特定的 MySQL 错误代码处理程序，以及一个通用的`SQL警告`内部块中的处理程序。或者可能有特定 MySQL 错误代码的处理程序和一般的`SQL警告`在同一个街区上课。

    处理程序是否被激活不仅取决于它自己的范围和条件值，还取决于其他处理程序的存在。当存储程序中出现条件时，服务器会在当前范围内搜索适用的处理程序（当前[`开始...结束`](begin-end.html)堵塞）。如果没有适用的处理程序，则搜索继续向外搜索每个连续包含范围（块）中的处理程序。当服务器在给定范围内找到一个或多个适用的处理程序时，它会根据条件优先级在其中进行选择：

-   MySQL 错误代码处理程序优先于`SQLSTATE`值处理程序。

-   一个`SQLSTATE`值处理程序优先于一般`SQL警告`,`SQL异常`， 要么`未找到`处理程序。

-   一个`SQL异常`处理程序优先于`SQL警告`处理程序。

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

    处理程序选择规则的一个含义是，如果多个适用的处理程序出现在不同的范围内，则具有最本地范围的处理程序优先于外部范围内的处理程序，甚至高于那些用于更具体条件的处理程序。

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

-   为了`SQL异常`条件，存储的程序在引发条件的语句处终止，就好像有一个`出口`处理程序。如果该程序被另一个存储的程序调用，则调用程序使用应用于其自己的处理程序的处理程序选择规则来处理该条件。

-   为了`SQL警告`条件下，程序继续执行，就好像有一个`继续`处理程序。

-   为了`未找到`条件，如果条件被正常提出，动作是`继续`.如果它是由[`信号`](signal.html)要么[`重新信号`](resignal.html), 动作是`出口`.

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

    此过程包含两个处理程序，一个用于特定的`SQLSTATE`价值 （`'42S02'`) 尝试删除不存在的表时会发生这种情况，而一般情况下会发生这种情况`SQL异常`班级：


```
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`处理程序优先于`SQL异常`处理程序，所以如果表`吨`是不存在的，[`删除表`](drop-table.html)语句引发了一个激活`SQLSTATE`处理程序：

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

此过程包含相同的两个处理程序。但这一次，[`删除表`](drop-table.html)声明和`SQL异常`处理程序位于相对于`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;
```

在这种情况下，更接近条件发生位置的处理程序优先。这`SQL异常`处理程序激活，即使它比`SQLSTATE`处理程序：

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

在此过程中，其中一个处理程序在[`删除表`](drop-table.html)陈述：

```
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;
```

只有`SQL异常`处理程序适用，因为另一个不在范围内[`删除表`](drop-table.html)：

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

在这个过程中，两个处理程序都在一个块内部的范围内声明[`删除表`](drop-table.html)陈述：

```
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.html).该语句引发的条件未处理并以错误终止该过程：

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