13.6.7.6 Правила области действия обработчиков
В программе сохранённого кода могут быть включены обработчики, которые вызываются при возникновении определённых условий внутри программы. Применимость каждого обработчика зависит от его расположения в определении программы и от условия или условий, которые он обрабатывает:
-
Обработчик, объявленный в блоке
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 H1stmt1; END;stmt2; END; Обработчик может быть специфичным или общим. Специфический обработчик предназначен для кода ошибки MySQL, значения
SQLSTATEили имени условия. Общий обработчик предназначен для условия в классеSQLWARNING,SQLEXCEPTIONилиNOT FOUND. Специфичность условия связана с приоритетом условия, как описано позже.
В разных областях действия и с разной специфичностью можно объявлять несколько обработчиков. Например, во внешнем блоке может быть обработчик для определённого кода ошибки MySQL, а во внутреннем блоке — общий обработчик SQLWARNING. Или в одном блоке могут быть обработчики для конкретного кода ошибки MySQL и общего класса SQLWARNING.
Активация обработчика зависит не только от его собственной области действия и значения условия, но и от других присутствующих обработчиков. Когда в программе сохранённого кода возникает условие, сервер ищет применимые обработчики в текущей области действия (текущем блоке BEGIN ...
END). Если применимых обработчиков нет, поиск продолжается наружу с обработчиками в каждом последующем содержащем блоке. Когда сервер находит одного или нескольких применимых обработчиков в данной области действия, он выбирает среди них на основе приоритета условия:
Обработчик кода ошибки MySQL имеет приоритет над обработчиком значения
SQLSTATE.Обработчик значения
SQLSTATEимеет приоритет над общими обработчикамиSQLWARNING,SQLEXCEPTIONилиNOT FOUND.Обработчик
SQLEXCEPTIONимеет приоритет над обработчикомSQLWARNING.Возможно наличие нескольких применимых обработчиков с одинаковым приоритетом. Например, оператор может сгенерировать несколько предупреждений с различными кодами ошибок, для каждого из которых существует специализированный обработчик ошибки. В этом случае выбор обработчика, который активирует сервер, не является детерминированным и может меняться в зависимости от обстоятельств возникновения условия.
Следствием правил выбора обработчика является то, что если несколько применимых обработчиков возникают в разных областях действия, обработчики с самой локальной областью действия имеют приоритет над обработчиками во внешних областях действия, даже над теми, которые предназначены для более специфических условий.
Если при возникновении условия подходящего обработчика нет, действия зависят от класса условия:
Для условий
SQLEXCEPTIONпрограмма сохранённого кода завершается в операторе, который вызвал условие, как будто там был обработчикEXIT. Если программа была вызвана другой программой сохранённого кода, вызывающая программа обрабатывает условие, используя правила выбора обработчиков, применимые к её собственным обработчикам.Для условий
SQLWARNINGвыполнение программы продолжается, как будто там был обработчикCONTINUE.Для условий
NOT FOUND, если условие было вызвано обычным способом, действие —CONTINUE. Если оно было вызвано операторомSIGNALилиRESIGNAL, действие —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'
© 2025 Oracle
Licensed under the GPLv2 License.