Иван Задворьев - Язык PL/SQL
- Название:Язык PL/SQL
- Автор:
- Жанр:
- Издательство:Array SelfPub.ru
- Год:2018
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Иван Задворьев - Язык PL/SQL краткое содержание
Язык PL/SQL - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Процедура RAISE_APPLICATION_ERROR
Если пользовательское исключение все-таки вылетит «наружу» в вызывающую среду, то независимо от того, какое исключение вылетело, «снаружи» выглядеть это будет одинаково – как ошибка ORA-06510.
Исключение exception1
Исключение exception2
SQL> DECLARE
2 exception1 EXCEPTION;
3 BEGIN
4 RAISE exception1;
5 END;
6 /
DECLARE
*
ERROR at line 1:
ORA-06510: PL/SQL:
unhandled user-defined exception
ORA-06512: at line 4
SQL> DECLARE
2 exception2 EXCEPTION;
3 BEGIN
4 RAISE exception2;
5 END;
6 /
DECLARE
*
ERROR at line 1:
ORA-06510: PL/SQL:
unhandled user-defined exception
ORA-06512: at line 4
С системными исключениями дело обстоит иначе – разные системные исключения вылетают «наружу» с разными кодами и сообщениями, что позволяет их обрабатывать в вызывающей среде, так как по коду понятно, какая ошибка произошла.
Как отмечалось выше, системные исключения автоматически инициируются виртуальной машиной PL/SQL при возникновении программных ошибок этапа выполнения. В то же время есть возможность инициировать системные исключения и вручную. Для этого используется процедура RAISE_APPLICATION_ERROR, которая инициирует системные исключения с задаваемыми программистом сообщениями и номерами ошибок из диапазона [-20999,-20000].
SQL> DECLARE
2 l_error_number INTEGER := -20187;
3 l_error_message VARCHAR2(100) := 'Отрицательная сумма платежа';
4 l_amount INTEGER := -10;
5 BEGIN
6 IF l_amount < 0 THEN
7 RAISE_APPLICATION_ERROR(l_error_number,l_error_message);
8 END IF;
9 END;
10 /
DECLARE
*
ERROR at line 1:
ORA-20187: Отрицательная сумма платежа
ORA-06512: at line 7
Привязка пользовательских исключений к ошибкам
В рассмотренных примерах работы с исключениями часто использовались предопределенные исключения, например, исключение ZERO_DIVIDE, которое соответствует ошибке ORA-01476 Divisor is equal to zero. В PL/SQL есть возможность практически к любой ошибке сервера привязать пользовательское исключение и ловить ошибки по именам таких исключений, а не в OTHERS-обработчике.
Для привязки ошибки к пользовательскому исключению достаточно узнать номер ошибки и записать соответствующую директиву компилятору:
PRAGMA EXCEPTION_INIT (имя пользовательского исключения, номер ошибки)
Обработаем ошибку преобразования символьного значения в дату по заданной маске с использованием привязанного исключения:
– сначала специально получаем ошибку и узнаем ее номер,
– это вспомогательный шаг
SQL> DECLARE
2 v1 DATE;
3 BEGIN
4 v1:=TO_DATE('abc','dd.mm.yyyy'); – ожидается не abc, а дата по маске
5 END;
6 /
DECLARE
*
ERROR at line 1:
ORA-01858: a non-numeric character was found where a numeric was expected
ORA-06512: at line 4
– объявляем исключение и привязываем его к ORA-01858
SQL> DECLARE
2 v1 DATE;
3 to_date_convert_error EXCEPTION;
4 PRAGMA EXCEPTION_INIT (to_date_convert_error, -01858);
5 BEGIN
6 v1:=TO_DATE('abc','dd.mm.yyyy');
7 EXCEPTION
8 WHEN to_date_convert_error THEN
9 DBMS_OUTPUT.PUT_LINE('Ошибка преобразования строки в дату');
10 END;
11 /
Ошибка преобразования строки в дату
PL/SQL procedure successfully completed.
Если бы возможности привязки к ошибкам пользовательских исключений не было, то пришлось бы все ошибки обрабатывать в OTHERS-обработчике примерно так:
BEGIN
v1:=TO_DATE('abc','dd.mm.yyyy');
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -01858 THEN
DBMS_OUTPUT.PUT_LINE('Ошибка преобразования строки в дату');
END IF;
IF SQLCODE = -… THEN
…
END IF;
… и так для каждой ожидаемой ошибки
… (в конце ELSE-ветвь – для неожидаемых ошибок)
END;
В результате применения такого подхода OTHERS-обработчик превратился бы в громоздкий фрагмент кода значительного объема с большим числом команд IF и/или CASE. Привязка пользовательских исключений к ошибкам позволяет избежать этого, распределив обработку ошибок по отдельным обработчикам.
Хорошим стилем является объявление в одном месте кода всех пользовательских исключений с привязкой к ошибкам. Далее эти ошибки можно ловить по именам исключений и иметь отдельные обработчики с обозримым объемом кода для каждой ошибки. При необходимости можно разделить ошибки на критичные и некритичные. Некритичные ошибки следует ловить и обрабатывать с продолжением вычислений (например, в циклах обычно обрабатывается ошибка на сбойной итерации и происходит переход на следующую итерацию цикла). Критичные ошибки «катапультировать» через все вложенные блоки, вызывая во всех обработчиках исключений команду RAISE до тех пор, пока критичная ошибка не долетит до раздела обработки критичных ошибок.
Использование обработчика OTHERS
Как было сказано ранее, обработчик OTHERS указывается последним в разделе обработки исключений. Он ловит все исключения, которые не поймали обработчики, перечисленные раньше него. Чаще всего обработчик OTHERS используется для того, чтобы обрабатывать системные исключения, инициируемые из-за возникновения ошибок.
При неправильном использовании наличие обработчика OTHERS может стать причиной «потери» для клиентских приложений ошибок в программах PL/SQL. Все вызовы программы PL/SQL с обработчиком WHEN OTHERS в разделе обработки исключений самого внешнего блока будут завершаться успешно, никакие ошибки «наружу» вылетать не будут. При этом в программе на P/SQL могут происходить и фатальные ошибки, но о них никто сразу не узнает, они будут «подавлены» в разделе обработки исключений.
Особенно плохой практикой является использование обработчиков вида
BEGIN
…
EXCEPTION
WHEN OTHERS THEN NULL;
END;
В этом случае исключение даже никак не регистрируется и просто теряется. Один из авторов в унаследованной системе столкнулся с тем, что при загрузке с помощью SQL*Loader некоторые строки то загружались, то не загружались. После нескольких часов жизни, напрасно потерянных на проверку различных гипотез, случайно был обнаружен триггер, который срабатывал на вставку строк предложением INSERT. В этом триггере осуществлялось преобразование строки в дату, которое то было успешным, то завершалось ошибкой. Ошибки эти обрабатывались так, как показано выше, то есть в новых записях то проставлялись даты, то нет. В результате в логах SQL*Loader появлялись сообщения об ошибках нарушения ограничения целостности для столбца с датами, а причина этого была неясна.
В том памятном случае разработчик триггера сделал три ошибки сразу:
понадеялся на неявное преобразование строки в дату без указания маски (плохая практика) и в этом была причина ошибки, которая то была, то нет;
с помощью изменения псевдозаписей :NEW тихо подменял значения столбцов добавляемых в таблицу строк в BEFORE-триггере (очень плохая практика);
подавлял происходящие ошибки в обработчике OTHERS (очень-очень плохая практика).
SQL в программах PL/SQL
Выполнение SQL в программах PL/ SQL
Выполнение предложений SQL в программах PL/SQL происходит совершенно естественным образом. И языковые конструкции PL/SQL, и компилятор, и виртуальная машина изначально разрабатывались и непрерывно улучшались специально для этого.
Читать дальшеИнтервал:
Закладка: