6.6. Обработка исключительных ситуаций
При выполнении программных объектов пользователь должен иметь возможность оперативно реагировать на возникающие отклонения от нормального процесса их выполнения. Для решения этой задачи разработчики SQL Anywhere применили механизм обработки исключительных ситуаций. Данный механизм представляет собой прием, обеспечивающий перехват и обработку ошибок и предупреждений. Исключительные ситуации в SQL Anywhere возникают при выполнении SQL-операторов. Исключительные ситуации представляются в виде кодов возврата, которые формируются после завершения выполнения операторов. Коды возврата, как и в большинстве баз данных SQL, одновременно записываются в системные переменные SQLSTATE и SQLCODE. В этих переменных возникновение исключительных ситуаций кодируются по разному. Так в переменной SQLCODE они представляются в виде десятичных чисел. При этом отрицательные значения соответствуют ошибкам, положительные - предупреждениям, а ноль - успешному завершению оператора. Кодирование исключительных ситуаций в переменной SQLSTATE соответствует стандарту SQL/92. При этом коды возврата представляются в виде строк из пяти символов. В переменной SQLSTATE первые два символа составляют код класса ошибок, следующие три символа - код внутри класса. Код "00000" соответствует успешному выполнению оператора. Перечень кодов для переменных SQLSTATE и SQLCODE вы можете найти в документации SQL Anywhere или ее справочной системе. В зависимости от значений кодов возврата может быть принято решение о повторении оператора, прерывания функционирования приложения и т.д.
ПРИМЕЧАНИЕ.
После считывания значения одной из переменных SQLSTATE или SQLCODE, обе они приводятся в состояние отсутствия ошибок.
Рассмотрим сначала, что происходит с работой программных объектов при возникновении исключительных ситуаций в виде ошибок, когда обработка этих ошибок не предусмотрена. Обработка ошибок и поведение программных объектов при возникновении предупреждений рассмотрена п.п. 6.6.2, 6.6.3.
6.6.1. Работа программных объектов при отсутствии реакции на ошибки
Если при функционировании программного объекта возникает исключительная ситуаций в виде ошибки и их обработка нем не определена, то происходит следующее. Программный объект сразу прекращает свое функционирование и происходит передача управления вызвавшему его программному объекту. Туда же через переменные SQLSTATE и SQLCODE передается код возврата ошибки. Если и там не определена обработка возникшей ошибки, то происходит передача управления и кода возврата ошибки еще выше по иерархии вызовов. Такая передача происходит до тех пор пока не встретится программный объект, в котором предусмотрена обработка возникшей ошибки, или пока будет достигнут самый верхний уровень иерархии вызовов. В последнем случае произойдет аварийное завершение функционирования приложения.
Допустим, что ни в одном из программных объектов A, B и C не предусмотрена обработка ошибок. Допустим также, что для них имеется следующая динамика вызовов: A -> B ->C. Тогда при возникновении ошибки в C произойдет последовательное аварийное завершение функционирования программных объектов C,B и A , т.е. всего приложения в целом. Ниже приводится пример, демонстрирующий поведение программных объектов при отсутствии обработки ошибок. В данном примере процедура Proc_First вызывает Proc_Second , в которой возникает ошибка.
CREATE PROCEDURE Proc_First()
BEGIN
MESSAGE '===Работает Proc_First .';
CALL Proc_Second();
MESSAGE '=== SQLSTATE= ',
SQLSTATE,' в Proc_First.'
END //___конец___процедуры
CREATE PROCEDURE Proc_Second()
BEGIN
/* Объявление исключительной ситуации
colum_not_found -ошибка "поле не найдено" */
DECLARE colum_not_found
EXCEPTION FOR SQLSTATE '52003';
MESSAGE '***Работает Proc_Second.';
/* Искусственно генерируем возникновение
исключительной ситуации colum_not_found */
SIGNAL colum_not_found;
MESSAGE '******* SQLSTATE= ',
SQLSTATE,' в Proc_Second .' ;
END //___конец___процедуры
Сделаем некоторые комментарии к процедурам Proc_Firsrt и Proc_Second. Оператор MESSAGE осуществляет выдачу в окно локального сервера (см. рис. 2) или окно Messages удаленного сервера (см. рис. 4) строку, формируемую из параметров оператора. Оператор DECLARE..EXCEPTION объявляет псевдоним для исключительной ситуации colum_not_found. Эта исключительная ситуация в процедуре Proc_Second вызывается искусственно. Для этой цели используется оператор SIGNAL. Для выполнения данного примера применим следующий оператор:
//Вызов процедуры
CALL Proc_First().
Тогда в окне сервера получим следующие сообщения:
===Работает Proc_First
***Работает Proc_Second
Кроме того, на клиентской ЭВМ пользователю выдается сообщение colum not found.
В процедуре Proc_Second после выполнения оператора SIGNAL эмулируется исключительная ситуация. В связи с этим второе сообщение о значении переменной SQLSTATE из данной процедуры формироваться не будет. Дело в том, в что в этой процедуре не определена обработка ошибки colum not found. Поэтому после ее возникновения процедура сразу прекращает свое функционирование. Следовательно все операторы, следующие за оператором SIGNAL , в том числе и второй оператор MESSAGE, выполняться не будут.
После аварийного завершения процедуры Proc_Second управление передается процедуре Proc_First c выдачей кода возврата о ошибке colum_not_found. В этой процедуре также не предусмотрена обработка данной ошибки. По этой причине процедура Proc_First тоже аварийно завершает свое функционирование. При этом на экран клиентской ЭВМ, с которой была запущена процедура Proc_First, будет выдано сообщение о возникшей ошибке colum not found.
ПРИМЕЧАНИЕ
Определить оператор, при выполнении которого возникла ошибка, позволяет вызов в утилите ISQL функции Traceback(*).
6.6.2. Обработка ошибок в программных объектах
Рассмотрим как происходит обработка ошибок в программных объектах. Их обработка производится механизмом обработки исключительных ситуаций. Использование этого механизма состоит:
- в определении псевдонимов для исключительных ситуаций соответствующие ожидаемым ошибкам, посредством оператора DECLARE..EXCEPTION;
- в определении реакции на описанные исключительные ситуации в программном блоке, начинающемся служебным словом EXCEPTION.
Покажем как применяются исключительные ситуации для обработки ошибок на примере процедур Proc_First_Ex и Proc_Second|_Ex. Эти процедуры представляют собой незначительные модификации процедур Proc_Firsrt и Proc_Second.
CREATE PROCEDURE Proc_First_Ex()
BEGIN
MESSAGE '===Работает Proc_First_Ex';
CALL Proc_Second_Ex();
MESSAGE '=== SQLSTATE= ',
SQLSTATE, ' в Proc_First_Ex.'
END //___конец___процедуры
CREATE PROCEDURE Proc_Second_Ex()
BEGIN
/* Объявление исключительной ситуации
colum_not_found - ошибка "поле не найдено)" */
DECLARE colum_not_found
EXCEPTION FOR SQLSTATE '52003';
MESSAGE
'***Работает Proc_Second_Ex .';
//искусственно генерируем возникновение
// исключительной ситуации colum_not_found
SIGNAL colum_not_found;
MESSAGE
'Выполнен оператор SIGNAL';
EXCEPTION
WHEN colum_not_found
THEN
MESSAGE '***Сolum_not_found',
' SQLSTATE= ', SQLSTATE;
MESSAGE '***' SQLSTATE= ',
SQLSTATE, ' в Proc_Second_Ex';
WHEN OTHERS
THEN RESIGNAL;
END //___конец___процедуры
После выполнения данного примера посредством оператора
//Вызов процедуры
CALL Proc_First_Ex()
в окне сообщений сервера появится следующая информация:
===Работает Proc_First_Ex .
***Работает Proc_Second_Ex .
***Colum_not_found SQLSTATE= 52003
*** SQLSTATE= 00000 в Proc_Second_Ex
=== SQLSTATE= 00000 в Proc_First_Ex.
При использовании исключительных ситуации для обработки ошибок после возникновении последних происходит переход к блоку EXCEPTION. При этом операторы, следующие за ошибочным оператором не выполняются. В блоке EXCEPTION выполняется реакция на возникшую ошибку, если такая реакция определена. Если ошибка не определена, то в пределах этого блока осуществляется переход на метку OTHERS. В рассматриваемом примере в последнем случае должен выполняться оператор RESIGNAL. Он позволяет аварийно завершить процедуру, несмотря на наличие операторов обработки ошибок. Кроме того, данный оператор отменяет все действия совершенные в процедуре.
После выполнения соответствующих операторов в блоке EXCEPTION происходит завершение процедуры. При этот, если не используется оператор RESIGNAL, то в вызвавший программный объект передается код возврата об отсутствии ошибки (SQLSTATE='00000', SQLCODE=0).
Использование механизма исключительных ситуаций является удобным средством контроля за возникающими ошибками. При его применении от пользователя не требуется проверять коды возврата после каждого SQL-оператора. Эту функции берет на себя СУБД. Код программного объекта становится короче, нагляднее и, как правило, в нем уменьшается вероятность наличия ошибок.
6.6.3. Обработка предупреждений в программных объектах
Обработка предупреждений отличается от обработки ошибок. При формировании предупреждения в переменные SQLSTATE и SQLCODE также записывается код возврата. Но прерывания вычислительного процесса при этом не происходит и программный объект продолжает свое функционирование. Если возникает необходимость отреагировать на предупреждение, то достаточно проверить содержимое переменной SQLSTATE или SQLCODE.
Рассмотрим функционирование программных объектов в условиях формирования предупреждений на примере процедур Proc_Firsrt_W и Proc_Second_W. Они разработаны на базе процедур Proc_Firsrt и Proc_Second.
CREATE PROCEDURE Proc_First_W()
BEGIN
MESSAGE '===Работает Proc_First_w.';
CALL Proc_Second_W();
MESSAGE '=== SQLSTATE= ',
SQLSTATE,' в Proc_First_W.'
END //___конец___процедуры
CREATE PROCEDURE Proc_Second_W()
BEGIN
/* Объявление исключительной ситуации
row_not_found - предупреждение запись не найдена */
DECLARE row_not_found
EXCEPTION FOR SQLSTATE '02000';
MESSAGE '***Работает Proc_Second_W .';
/* искусственно генерируем исключи-
тельную ситуацию row_not_found */
SIGNAL row_not_found;
IF sqlstate='02000'
THEN
MESSAGE
'***Warning row_not_found',
' SQLSTATE= ', SQLSTATE;
END IF ;
MESSAGE '***SQLSTATE= ',
SQLSTATE,' в Proc_Second_W .' ;
END //___конец___процедуры
Запустив пример на исполнение оператором
//Вызов процедуры
CALL Proc_First_W()
в окне сообщений сервера появится следующая информация:
===Работает Proc_First_w .
***Работает Proc_Second_W .
***row_not_found SQLSTATE= 02000
***SQLSTATE= 00000 в Proc_Second_W .
=== SQLSTATE= 00000 в Proc_First_W.
Данный пример показывает, что управлять обработкой предупреждений казалось бы значительно проще, чем обработкой ошибок. Однако использование проверок после каждого SQL-оператора вызывает нагромождение вспомогательных конструкций в тексте программного объекта. Это никак не способствует снижению программных ошибок.
Назад |
Содержание |
Вперед