當程式內發生特定狀況時,儲存程式可能會包含要調用的處理器。每個處理器的適用性取決於它在程式定義中的位置,以及它所處理的狀況或多個狀況。
在
BEGIN ... END
區塊中宣告的處理器,其作用域僅限於區塊中處理器宣告之後的 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
值或條件名稱。通用的處理器適用於SQLWARNING
、SQLEXCEPTION
或NOT FOUND
類別中的狀況。條件的特定性與條件優先順序有關,如後所述。
可以在不同的作用域中宣告具有不同特定性的多個處理器。例如,在外部區塊中可能會有一個特定的 MySQL 錯誤代碼處理器,而在內部區塊中可能會有一個通用的 SQLWARNING
處理器。或者,在同一個區塊中,可能會有針對特定 MySQL 錯誤代碼和通用 SQLWARNING
類別的處理器。
處理器是否被啟動不僅取決於其自身的作用域和條件值,還取決於存在哪些其他處理器。當儲存程式中發生狀況時,伺服器會在目前作用域(目前的 BEGIN ... END
區塊)中搜尋適用的處理器。如果沒有適用的處理器,則會繼續向外搜尋,查找每個連續包含的作用域(區塊)中的處理器。當伺服器在給定的作用域中找到一個或多個適用的處理器時,它會根據條件優先順序在它們之間進行選擇。
MySQL 錯誤代碼處理器的優先順序高於
SQLSTATE
值處理器。SQLSTATE
值處理器的優先順序高於通用的SQLWARNING
、SQLEXCEPTION
或NOT FOUND
處理器。SQLEXCEPTION
處理器的優先順序高於SQLWARNING
處理器。有可能有多個具有相同優先順序的適用處理器。例如,一個陳述式可能會產生具有不同錯誤代碼的多個警告,每個錯誤代碼都存在一個特定的錯誤處理器。在這種情況下,伺服器啟動哪個處理器的選擇是不確定的,並且可能會根據發生狀況的情況而變化。
處理器選擇規則的一個含義是,如果多個適用的處理器出現在不同的作用域中,則具有最局部作用域的處理器優先於外部作用域中的處理器,即使是針對更具體條件的處理器也是如此。
如果發生狀況時沒有適當的處理器,則採取的動作取決於狀況的類別。
以下範例示範 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'