文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


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

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'