Spec-Zone.ru › MySQL 5.7

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 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.

  • Возможно наличие нескольких применимых обработчиков с одинаковым приоритетом. Например, оператор может сгенерировать несколько предупреждений с различными кодами ошибок, для каждого из которых существует специализированный обработчик ошибки. В этом случае выбор обработчика, который активирует сервер, не является детерминированным и может меняться в зависимости от обстоятельств возникновения условия.

Следствием правил выбора обработчика является то, что если несколько применимых обработчиков возникают в разных областях действия, обработчики с самой локальной областью действия имеют приоритет над обработчиками во внешних областях действия, даже над теми, которые предназначены для более специфических условий.

Если при возникновении условия подходящего обработчика нет, действия зависят от класса условия:

  • Для условий 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.
https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/handler-scope.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API