文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
資訊 (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  處理器的作用域規則

15.6.7.6 處理器的作用域規則

儲存的程式可能包含在程式內特定條件發生時要調用的處理器。每個處理器的適用性取決於其在程式定義中的位置以及它處理的條件。

  • BEGIN ... END 區塊中宣告的處理器,其作用域僅限於該區塊中處理器宣告之後的 SQL 陳述式。如果處理器本身引發條件,它無法處理該條件,區塊中宣告的任何其他處理器也無法處理。在以下範例中,處理器 H1H2 的作用域適用於陳述式 stmt1stmt2 引發的條件。但 H1H2 都無法處理在 H1H2 主體中引發的條件。

    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 值或條件名稱。一般的處理器適用於 SQLWARNINGSQLEXCEPTIONNOT FOUND 類別中的條件。條件的特定性與稍後描述的條件優先順序相關。

可以在不同的作用域中宣告具有不同特定性的多個處理器。例如,在外部區塊中可能有一個特定的 MySQL 錯誤碼處理器,而在內部區塊中可能有一個一般的 SQLWARNING 處理器。或者,在同一個區塊中可能存在針對特定 MySQL 錯誤碼和一般 SQLWARNING 類別的處理器。

處理器是否被啟動不僅取決於其自身的作用域和條件值,還取決於存在哪些其他處理器。當儲存的程式中發生條件時,伺服器會在目前作用域(目前 BEGIN ... END 區塊)中搜尋適用的處理器。如果沒有適用的處理器,則搜尋會繼續向外,搜尋每個連續包含作用域(區塊)中的處理器。當伺服器在給定作用域找到一個或多個適用的處理器時,它會根據條件優先順序在它們之間進行選擇。

  • MySQL 錯誤碼處理器的優先順序高於 SQLSTATE 值處理器。

  • SQLSTATE 值處理器的優先順序高於一般的 SQLWARNINGSQLEXCEPTIONNOT FOUND 處理器。

  • SQLEXCEPTION 處理器的優先順序高於 SQLWARNING 處理器。

  • 有可能有多個具有相同優先順序的適用處理器。例如,一個陳述式可能會產生具有不同錯誤碼的多個警告,每個警告都存在一個特定於錯誤的處理器。在這種情況下,伺服器啟動哪個處理器的選擇是不確定的,並且可能會根據條件發生的情況而改變。

處理器選擇規則的一個含義是,如果在不同的作用域中發生多個適用的處理器,則具有最局部作用域的處理器的優先順序高於外部作用域中的處理器,即使對於更特定的條件也是如此。

如果發生條件時沒有適當的處理器,則採取的行動取決於條件的類別。

  • 對於 SQLEXCEPTION 條件,儲存的程式會在引發條件的陳述式處終止,就像存在 EXIT 處理器一樣。如果程式是由另一個儲存的程式呼叫,則呼叫程式會使用應用於其自身處理器的處理器選擇規則來處理條件。

  • 對於 SQLWARNING 條件,程式會繼續執行,就像存在 CONTINUE 處理器一樣。

  • 對於 NOT FOUND 條件,如果該條件是正常引發的,則動作是 CONTINUE。如果是透過 SIGNALRESIGNAL 引發的,則動作是 EXIT

以下範例示範 MySQL 如何應用處理器選擇規則。

此程序包含兩個處理器,一個用於特定 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 處理器,因此如果資料表 t 不存在,則 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'