15.6.7.4 Оператор RESIGNAL
RESIGNAL [condition_value]
[SET signal_information_item
[, signal_information_item] ...]
condition_value: {
SQLSTATE [VALUE] sqlstate_value
| condition_name
}
signal_information_item:
condition_information_item_name = simple_value_specification
condition_information_item_name: {
CLASS_ORIGIN
| SUBCLASS_ORIGIN
| MESSAGE_TEXT
| MYSQL_ERRNO
| CONSTRAINT_CATALOG
| CONSTRAINT_SCHEMA
| CONSTRAINT_NAME
| CATALOG_NAME
| SCHEMA_NAME
| TABLE_NAME
| COLUMN_NAME
| CURSOR_NAME
}
condition_name, simple_value_specification:
(see following discussion)
RESIGNAL передает информацию об ошибке, доступную во время выполнения обработчика условия в составном операторе внутри хранимой процедуры или функции, триггера или события. RESIGNAL может изменить часть или всю информацию перед передачей. RESIGNAL связан с SIGNAL, но вместо создания условия, как делает SIGNAL, RESIGNAL передает существующую информацию об условии, возможно после её изменения.
RESIGNAL позволяет как обработать ошибку, так и вернуть информацию об ошибке. В противном случае, выполняя оператор SQL внутри обработчика, информация, вызвавшая активацию обработчика, будет уничтожена. RESIGNAL также может сократить некоторые процедуры, если данный обработчик может обработать часть ситуации, а затем передать условие «вверх по цепочке» другому обработчику.
Для выполнения оператора RESIGNAL привилегии не требуются.
Все формы оператора RESIGNAL требуют, чтобы текущий контекст был обработчиком условия. В противном случае, RESIGNAL является недопустимым и возникает ошибка RESIGNAL when handler not active.
Для извлечения информации из области диагностики используйте оператор GET DIAGNOSTICS (см. Раздел 15.6.7.3, «Оператор GET DIAGNOSTICS»). Информацию об области диагностики см. в Разделе 15.6.7.7, «Область диагностики MySQL».
Обзор RESIGNAL
Для condition_value и signal_information_item, определения и правила для оператора RESIGNAL такие же, как и для SIGNAL. Например, condition_value может быть значением SQLSTATE, и это значение может указывать на ошибки, предупреждения или “не найдено.” Дополнительную информацию см. в Разделе 15.6.7.5, «Оператор SIGNAL».
Оператор RESIGNAL принимает condition_value и SET предложения, оба из которых необязательны. Это приводит к нескольким возможным вариантам использования:
-
RESIGNALсам по себе:RESIGNAL;
-
RESIGNALс новой информацией о сигнале:RESIGNAL SET
signal_information_item[,signal_information_item] ...; -
RESIGNALсо значением условия и, возможно, новой информацией о сигнале:RESIGNAL
condition_value[SETsignal_information_item[,signal_information_item] ...];
Все эти варианты использования приводят к изменениям в областях диагностики и условий:
Область диагностики содержит одну или несколько областей условий.
Область условия содержит элементы информации об условии, такие как значение
SQLSTATE,MYSQL_ERRNOилиMESSAGE_TEXT.
Существует стек областей диагностики. Когда обработчик получает управление, он помещает область диагностики на вершину стека, поэтому во время выполнения обработчика есть две области диагностики:
Первая (текущая) область диагностики, которая начинается как копия последней области диагностики, но перезаписывается первым оператором в обработчике, изменяющим текущую область диагностики.
Последняя (находящаяся в стеке) область диагностики, которая содержит области условий, установленные до того, как обработчик получил управление.
Максимальное количество областей условий в области диагностики определяется значением системной переменной max_error_count. См. Системные переменные, связанные с областью диагностики.
RESIGNAL без параметров
Простой оператор RESIGNAL без параметров означает “передать ошибку без изменений”. Он восстанавливает последнюю область диагностики и делает её текущей областью диагностики. То есть, он «извлекает» область диагностики из стека.
Внутри обработчика условия, который ловит условие, одно из применений оператора RESIGNAL без параметров заключается в выполнении других действий, а затем передаче без изменений исходной информации об условии (информации, существовавшей до входа в обработчик).
Пример:
DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SET @error_count = @error_count + 1;
IF @a = 0 THEN RESIGNAL; END IF;
END;
DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
CALL p();
Предположим, что оператор DROP TABLE xx не выполняется успешно. Стек областей диагностики выглядит так:
DA 1. ERROR 1051 (42S02): Unknown table 'xx'
Затем выполнение входит в обработчик EXIT. Он начинает с помещения области диагностики на вершину стека, который теперь выглядит так:
DA 1. ERROR 1051 (42S02): Unknown table 'xx'
DA 2. ERROR 1051 (42S02): Unknown table 'xx'
В этот момент содержимое первой (текущей) и второй (находящейся в стеке) областей диагностики одинаковы. Первая область диагностики может быть изменена операторами, которые выполняются после этого в рамках обработчика.
Обычно оператор процедуры очищает первую область диагностики. Оператор BEGIN является исключением; он не очищает, а ничего не делает. Оператор SET не является исключением; он очищает, выполняет операцию и возвращает результат «успешно». Стек областей диагностики теперь выглядит так:
DA 1. ERROR 0000 (00000): Successful operation
DA 2. ERROR 1051 (42S02): Unknown table 'xx'
В этот момент, если @a = 0, оператор RESIGNAL извлекает область диагностики из стека, который теперь выглядит так:
DA 1. ERROR 1051 (42S02): Unknown table 'xx'
И именно это видит вызывающая сторона.
Если @a не равно 0, обработчик просто заканчивает работу, а это означает, что текущая область диагностики больше не нужна (она была «обработана»), поэтому её можно отбросить, что приводит к тому, что область диагностики в стеке становится текущей областью диагностики снова. Стек областей диагностики выглядит так:
DA 1. ERROR 0000 (00000): Successful operation
Детали выглядят сложно, но конечный результат весьма полезен: обработчики могут выполняться без уничтожения информации об условии, которое вызвало активацию обработчика.
RESIGNAL с новой информацией о сигнале
RESIGNAL с предложением SET предоставляет новую информацию о сигнале, поэтому оператор означает “передать ошибку с изменениями”:
RESIGNAL SET signal_information_item [, signal_information_item] ...;
Как и в случае с оператором RESIGNAL без параметров, идея состоит в том, чтобы извлечь область диагностики из стека, чтобы исходная информация была передана. В отличие от оператора RESIGNAL без параметров, всё, что указано в предложении SET, изменяется.
Пример:
DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SET @error_count = @error_count + 1;
IF @a = 0 THEN RESIGNAL SET MYSQL_ERRNO = 5; END IF;
END;
DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
CALL p();
Помните из предыдущего обсуждения, что оператор RESIGNAL без параметров приводит к стеку областей диагностики, такому как:
DA 1. ERROR 1051 (42S02): Unknown table 'xx'
Оператор RESIGNAL SET MYSQL_ERRNO = 5 приводит к этому стеку вместо этого, что видит вызывающая сторона:
DA 1. ERROR 5 (42S02): Unknown table 'xx'
Другими словами, он меняет номер ошибки, и ничего больше.
Оператор RESIGNAL может изменить любой или все элементы информации о сигнале, делая первую область условия в области диагностики совершенно другой.
Указание RESIGNAL с значением условия и дополнительной информацией о новом сигнале
RESIGNAL со значением условия означает “добавить условие в текущую область диагностики.” Если присутствует фраза SET, она также изменяет информацию об ошибке.
RESIGNAL condition_value
[SET signal_information_item [, signal_information_item] ...];
Этот вид RESIGNAL восстанавливает последнюю область диагностики и делает её текущей областью диагностики. То есть, он “извлекает” область диагностики из стека, что аналогично простому RESIGNAL. Однако он также изменяет область диагностики в зависимости от значения условия или информации о сигнале.
Пример:
DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SET @error_count = @error_count + 1;
IF @a = 0 THEN RESIGNAL SQLSTATE '45000' SET MYSQL_ERRNO=5; END IF;
END;
DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
SET @@max_error_count = 2;
CALL p();
SHOW ERRORS;
Это аналогично предыдущему примеру, и эффекты те же, за исключением того, что если RESIGNAL происходит, текущая область условия выглядит по-другому в конце. (Причина, по которой условие добавляется, а не заменяет существующее условие, заключается в использовании значения условия.)
В операторе RESIGNAL используется значение условия (SQLSTATE '45000'), поэтому он добавляет новую область условия, что приводит к стеку областей диагностики, который выглядит так:
DA 1. (condition 2) ERROR 1051 (42S02): Unknown table 'xx'
(condition 1) ERROR 5 (45000) Unknown table 'xx'
Результат выполнения CALL
p() и SHOW ERRORS для этого примера:
mysql> CALL p();
ERROR 5 (45000): Unknown table 'xx'
mysql> SHOW ERRORS;
+-------+------+----------------------------------+
| Level | Code | Message |
+-------+------+----------------------------------+
| Error | 1051 | Unknown table 'xx' |
| Error | 5 | Unknown table 'xx' |
+-------+------+----------------------------------+
RESIGNAL Требует контекста обработчика условий
Все формы RESIGNAL требуют, чтобы текущий контекст был контекстом обработчика условий. В противном случае RESIGNAL является недопустимым и возникает ошибка RESIGNAL when handler not active. Например:
mysql> CREATE PROCEDURE p () RESIGNAL;
Query OK, 0 rows affected (0.00 sec)
mysql> CALL p();
ERROR 1645 (0K000): RESIGNAL when handler not active
Вот более сложный пример:
delimiter //
CREATE FUNCTION f () RETURNS INT
BEGIN
RESIGNAL;
RETURN 5;
END//
CREATE PROCEDURE p ()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @a=f();
SIGNAL SQLSTATE '55555';
END//
delimiter ;
CALL p();
RESIGNAL происходит внутри сохранённой функции f(). Хотя сама f() вызывается в контексте обработчика EXIT, выполнение внутри f() имеет свой собственный контекст, который не является контекстом обработчика. Таким образом, RESIGNAL внутри f() приводит к ошибке “обработчик не активен”.
© 2025 Oracle
Licensed under the GPLv2 License.