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