Инициирование исключений в PL/SQL Oracle
Инициирование исключений
Исключение может быть инициировано приложением в трех случаях:
- Oracle инициирует исключение при обнаружении ошибки;
- приложение инициирует исключение командой RAISE;
- исключение инициируется встроенной процедурой RAISE_APPLICATION_ERROR.
Команда RAISE
Чтобы разработчик имел возможность самостоятельно инициировать именованные исключения, в Oracle поддерживается команда RAISE. С ее помощью можно инициировать как собственные, так и системные исключения. Команда имеет три формы:
RAISE имя_исключения; RAISE имя_пакета.имя_исключения; RAISE;
Первая форма (без имени пакета) может инициировать исключения, определенные в текущем блоке (или в содержащем его блоке), а также системные исключения, объявленные в пакете STANDARD. Далее приводятся два примера, в первом из которых инициируется исключение, определенное разработчиком:
DECLARE invalid_id EXCEPTION; -- Все идентификаторы должны начинаться с буквы 'X'. id_value VARCHAR2(30); BEGIN id_value := id_for ('SMITH'); IF SUBSTR (id_value, 1, 1) != 'X' THEN RAISE invalid_id; END IF; ... END;
При необходимости вы всегда можете инициировать системное исключение:
BEGIN IF total_sales = 0 THEN RAISE ZERO_DIVIDE; -- Определено в пакете STANDARD ELSE RETURN (sales_percentage_calculation (my_sales, total_sales)); END IF; END;
Если исключение объявлено в пакете (но не в STANDARD) и инициируется извне, имя исключения необходимо уточнить именем пакета:
IF days_overdue (isbn_in, borrower_in) > 365 THEN RAISE overdue_pkg.book_is_lost; END IF;
Третья форма RAISE не требует указывать имя исключения, но используется только в условии WHEN раздела исключений. Ее синтаксис предельно прост:
RAISE;
Используйте эту форму для повторного инициирования (передачи) перехваченного исключения:
EXCEPTION WHEN NO_DATA_FOUND THEN -- Используем общий пакет для сохранений всей контекстной -- информации: код ошибки, имя программы и т. д. errlog.putline (company_id_in); -- А теперь исключение NO_DATA_FOUND передается -- в родительский блок без обработки. RAISE;
Эта возможность особенно полезна в тех случаях, когда информацию об ошибке нужно записать в журнал, а сам процесс обработки возложить на родительский блок. Таким образом выполнение родительских блоков завершается без потери информации об ошибке.
Процедура RAISE_APPLICATION_ERROR
Для инициирования исключений, специфических для приложения, Oracle предоставляет процедуру RAISE_APPLICATION_ERROR (определенную в используемом по умолчанию пакете DBMS_STANDARD). Ее преимущество перед командой RAISE (которая тоже может инициировать специфические для приложения явно объявленные исключения) заключается в том, что она позволяет связать с исключением сообщение об ошибке.
При вызове этой процедуры выполнение текущего блока PL/SQL прекращается, а любые изменения аргументов OUT и IN OUT (если таковые имеются) отменяются. Изменения, внесенные в глобальные структуры данных (с помощью команды INSERT, UPDATE, MERGE или DELETE), такие как переменные пакетов и объекты баз данных, не отменяются. Для отката DML-команд необходимо явно указать в разделе обработки исключений команду ROLLBACK.
Заголовок этой процедуры (определяемый в пакете DBMS_STANDARD) выглядит так:
PROCEDURE RAISE_APPLICATION_ERROR ( num binary_integer, msg varchar2, keeperrorstack boolean default FALSE);
Здесь:
- num — номер ошибки из диапазона от –20 999 до -20 000 (только представьте: все остальные отрицательные числа Oracle резервирует для собственных исключений!);
- msg — сообщение об ошибке, длина которого не должна превышать 2048 символов (символы, выходящие за эту границу, игнорируются);
- аргумент keeperrorstack указывает, хотите ли вы добавить ошибку к уже имеющимся в стеке (TRUE), или заменить существующую ошибку (значение по умолчанию — FALSE).
Oracle выделяет диапазон номеров от –20 999 до –20 000 для пользовательских ошибок, но учтите, что в некоторых встроенных пакетах, в том числе в DBMS_OUTPUT и DBMS_DESCRIBE, номера от –20 005 до –20 000 все равно присваиваются системным ошибкам.
Рассмотрим пример полезного применения этой встроенной процедуры. Допустим, мы хотим, чтобы сообщения об ошибках выдавались пользователям на разных языках. Создадим для них таблицу error_table и определим в ней язык каждого сообщения значением столбца string_language. Затем создается процедура, которая генерирует заданную ошибку, загружая соответствующее сообщение из таблицы с учетом языка текущего сеанса:
PROCEDURE raise_by_language (code_in IN PLS_INTEGER) IS l_message error_table.error_string%TYPE; BEGIN SELECT error_string INTO l_message FROM error_table WHERE error_number = code_in AND string_language = USERENV ('LANG'); RAISE_APPLICATION_ERROR (code_in, l_message); END;
Метки: EXCEPTION, Oracle, Исключения.