После прилета исключения в раздел обработки возможны два случая:

если никакой обработчик исключению не подошел, то исключение со статусом «не обработано» бросается в дальнейший полет уже в родительском блоке (блоке, предыдущим по вложенности) с того места кода, где заканчивается вложенный блок;

если в результате «примерки» нашелся подходящий исключению обработчик, то управление передается ему.

Работа обработчика свою очередь может завершиться тремя исходами:

команды обработчика успешно выполнились, исключение получает статус «обработано» и управление передается родительскому блоку в то место кода, где заканчивается вложенный блок;

в процессе работы обработчика принято решение, что обрабатывать исключение надо не в этом обработчике, тогда исключение здесь же в обработчике инициируется повторно вызовом команды RAISE без параметров;

в ходе выполнения команд обработчика инициировано новое исключение (такое бывает, например, если в обработчике ошибки регистрируются в специальной таблице, а для нее кончилось место), прилетевшее исходное исключение тогда получает статус «обработано».

Два последних исхода работы обработчика предполагают, что из блока даже с подходящим обработчиком исключение бросится дальше – либо то же самое (после вызова команды RAISE), либо уже другое. Могло прилететь пользовательское исключение, обработаться со своей ошибкой, поэтому из обработчика бросится и в родительском блоке полетит дальше уже системное исключение, как в примере с ошибкой добавления строки в специальную таблицу журнала ошибок.

Примеры обработки исключений

Рассмотрим примеры полетов исключений в программе из трех вложенных блоков:

BEGIN – начало блока1

команда1_блока1;

команда2_блока1;

команда3_блока1;

BEGIN – начало блока2

команда1_блока2;

команда2_блока2 l_int := 1/TO_NUMBER(l_var) (l_var='1' или '0' или 'a')

команда3_блока2;

EXCEPTION

WHEN ZERO_DIVIDE THEN

команда1_zero_блока2;

команда2_zero_блока2;

END; – конец блока2

команда4_блока1;

команда5_блока1;

EXCEPTION

WHEN ZERO_DIVIDE THEN

команда1_zero_блока1;

команда2_zero_блока1;

WHEN OTHERS THEN

команда1_others_блока1;

команда2_others_блока1;

END; – конец блока 1

Пусть команда2_блока2 имеет вид l_int:=1/TO_NUMBER(l_var); где l_int – целочисленная переменная, l_var – символьная.


l_var='1' (без исключений)

l_var='0' (zero divide)

l_var='a' (conversion error)


команда1_блока1;

команда2_блока1;

команда3_блока1;

команда1_блока2;

команда2_блока2;

команда3_блока2;

команда4_блока1;

команда5_блока1;

команда1_блока1;

команда2_блока1;

команда3_блока1;

команда1_блока2;

команда2_блока2(error);

– в блоке 2

– ловится ZERO_DIVIDE:

команда1_zero_блока2;

команда2_zero_блока2;

–продолжение блока 1:

команда4_блока1;

команда5_блока1;

команда1_блока1;

команда2_блока1;

команда3_блока1;

команда1_блока2;

команда2_блока2(error);

–в блоке 2 ошибка

–преобразования

–не ловится, т.к.

–там только ZERO_DIVIDE

– в блоке 1

– ZERO_DIVIDE

– второй раз не ловит,

– а ловит OTHERS

– (он же все ловит):

команда1_others_блока1;

команда2_others_блока1;


Рассмотрим три случая в зависимости от значения, которое принимает переменная l_var ('1', или '0', или 'a').

Когда l_var=1 (первый столбец таблицы) исключения не инициируются выполняются все команды из разделов выполнения в той последовательности, как они записаны в коде.

В случае ошибки деления на ноль (второй столбец таблицы, l_var='0') в команде2_блока2 выполнение блока 2 прекращается, все остальные команды в блоке 2 после нее не выполняются, управление передается в раздел EXCEPTION блока 2, где пытаются поймать исключение деления на ноль (ZERO_DIVIDE). Подходящий обработчик в разделе обработки исключений блока 2 есть, поэтому исключение ловится в блоке 2, в котором успешно выполняются команды обработчика. После успешной обработки продолжается выполнение команд блока 1, родительского для блока 2, в котором произошла обработка исключения.