Обработка ошибок
Общие сведения Что такое исключение? –Переменная в PL/SQL, возбуждаемая во время выполнения Как возникает исключение? –Возбуждается сервером Oracle –Возбуждается явно Как вы его обрабатываете? –Перехватываете с помощью обработчика исключений –Распространяете в вызывающую среду
Обработка исключений (DECLARE) BEGIN EXCEPTION END; (DECLARE) BEGIN EXCEPTION END; Перехват исключения Возбуждение исключения Перехват исключения Возбуждение исключения Исключение не перехвачено Распространение исключения в вызывающую среду
Типы исключений Предопределенные, возбуждаемые сервером Oracle Непредопределенные, возбуждаемые сервером Oracle Пользовательские Возбуждаются явно Возбуждаются неявно
Перехват исключений: синтаксис EXCEPTION WHEN исключение 1 [OR исключение 2...] THEN оператор 1; оператор 2;... WHEN исключение 3 [OR исключение 4...] THEN оператор 1; оператор 2;... [WHEN OTHERS THEN оператор 1; оператор 2;...]
Перехват исключений: указания Предложение WHEN OTHERS является последним Ключевое слово EXCEPTION начинает секцию обработки исключений Допускается несколько обработчиков исключений Перед выходом из блока выполняется только один обработчик
Перехват предопределенных ошибок сервера Oracle В программе обработки исключения ссылайтесь на стандартное имя Примеры предопределенных исключений: - NO_DATA_FOUND - TOO_MANY_ROWS - INVALID_CURSOR - ZERO_DIVIDE - DUP_VAL_ON_INDEX
Предопределенное исключение: пример PROCEDURE elim_inventory (v_product_id IN s_product.id%TYPE) IS v_id s_product.id%TYPE; BEGIN SELECT id INTO v_id FROM s_product WHERE id = v_product_id; DELETE FROM s_inventory WHERE product_id = v_product_id; COMMIT;...
Предопределенное исключение: пример EXCEPTION WHEN NO_DATA_FOUND THEN ROLLBACK; TEXT_IO.PUT_LINE(TO_CHAR(v_product_id) || 'is invalid.); WHEN TOO_MANY_ROWS THEN ROLLBACK; TEXT_IO.PUT_LINE ('Data corruption in S_PRODUCT.'); WHEN OTHERS THEN ROLLBACK; TEXT_IO.PUT_LINE ('Other error occurred.'); END elim_inventory;
Перехват не предопределенных исключений сервера Oracle Объявление СвязываниеСсылка Секция обработки ошибок Декларативная секция Присвоение имени исключению Вложение предложения PRAGMA EXCEPTION_UNIT Обработка исключения
Непредопределенное исключение: пример Перехват ошибки "-2292" сервера Oracle (нарушение правила целостности) [DECLARE] e_products_remaining EXCEPTION; PRAGMA EXCEPTION_UNIT( e_products_remaining, -2292);... BEGIN... EXCEPTION WHEN e_products_remaining THEN TEXT_IO.PUT_LINE ('Referential integrity constraint violated.');... END; 1 Присвоение имени 2 Кодирование указания 3 Обработка исключению компилятору возбужденного EXCEPTION_UNIT исключения 1 2 3
Итак, предположим, что у нас есть две таблицы - города и люди. Они связаны внешним ключом без каскадного удаления. При попытке удалить город, к которому приписаны люди, будет сгенерирована ошибка ORA Именно для этого исключения мы придумали название HAVE_PEOPLES и объявили его в секции declare. Прагма exception_init позволяет связать номер исключения и его имя. Далее мы перехватываем именованное исключение HAVE_PEOPLES в секции exception.
DECLARE HAVE_PEOPLES exception; pragma exception_init(HAVE_PEOPLES, -2292); BEGIN delete from cities; EXCEPTION WHEN HAVE_PEOPLES THEN dbms_output.put_line('ошибка TOO_MANY_ROWS'); WHEN OTHERS THEN dbms_output.put_line('неизвестная ошибка'); END;
Перехват пользовательских исключений Объявление ВозбуждениеСсылка Секция обработки исключений Декларативная секция Присвоение имени исключению Явное возбуждение исключения с помощью предложения RAISE Обработка исключения Выполняемая секция
Пользовательское исключение: пример Если товар имеется на складе, прекратить обработку и выдать сообщение пользователю [DECLARE] e_amount_remaining EXCEPTION;... BEGIN... RAISE e_amount_remaining;... EXCEPTION WHEN e_amount_remaining THEN TEXT_IO.PUT_LINE ('There is still an amount in stock.');... END; 1 Присвоение 2 Явное возбуждение 3 Обработка имени исключения с помощью возбужденного исключению оператора RAISE исключения 1 2 3
DECLARE a_salary number; INCORRECT_SALARY exception; BEGIN select salary into a_salary from test_table where name='drLivsi'; if a_salary<2000 then raise INCORRECT_SALARY; end if; EXCEPTION WHEN TOO_MANY_ROWS THEN dbms_output.put_line('ошибка TOO_MANY_ROWS'); WHEN INCORRECT_SALARY THEN dbms_output.put_line('ошибка INCORRECT_SALARY'); WHEN OTHERS THEN dbms_output.put_line('неизвестная ошибка'); END;
Функции для перехвата исключений Обработчик исключений WHEN OTHERS –Перехватывает все необработанные исключения –Является последним обработчиком SQLCODE –Возвращает числовой код ошибки SQLERRM[(n)] –Возвращает сообщение, связанное с кодом ошибки –n – код ошибки
Функции для перехвата исключений: пример Сохранение кода ошибки и сообщения для любого непредвиденного исключения... v_error_codeNUMBER; v_error_message VARCHAR2(255); BEGIN... EXCEPTION... WHEN OTHERS THEN ROLLBACK; v_error_code := SQLCODE; v_error_message:= SQLERRM; TEXT_IO.PUT_LINE (TO_CHAR(v_error_Code)|| : || v_error_message); END;
Возможная вызывающая среда
Распространение исключений в вызывающую среду DECLARE... e_no_rows exception; е_integrity exception; PRAGMA EXCEPTION_INIT( e_integrity, -2292); BEGIN FOR c_record IN emp_cursor LOOP BEGIN SELECT... UPDATE … IF SQL%NOTFOUND THEN RAISE e_no_rows; EXCEPTION WHEN e_integrity THEN... WHEN e_no_rows THEN … END; END LOOP; EXCEPTION WHEN NO_DATA_FOUND THEN.. WHEN TOO_MANY_ROWS THEN… END: Подблоки могут обрабатывать исключение или распространять его во внешний блок
Обработка исключений с помощью оператора NULL PROCEDURE calc _avg_sales BEGIN sales.avg := sales.total /sales.month; EXCEPTION WHEN ZERO_DIVIDE THEN sales.avg := 0; RAISE FORM_TRIGGER_FAILURE; WHEN OTHERS THEN NULL; END;
Обработка исключительной ситуации: пропуск оператора открытия курсора DECLARE X1 T01_A1%TYPE; X2 T01_A2%TYPE; X3 T01_A3%TYPE; CURSOR CUR1 IS SELECT * FRON T01; BEGIN WHILE CUR1%FOUND LOOP FETCH CUR1 INTO X1,X2,X3; DBMS_OUTPUT.PUT_LINE (X1||' '||X2||' '||X3); END LOOP EXCEPTION WHEN INVALID_CURSOR THEN DBMS_OUTPUT.PUT_LINE ('ОШИБКА. НЕ ОТКРЫТ КУРСОР1'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('НЕИЗВЕСТНАЯ ОШИБКА.'); END;
Пример. процедура, увеличивающая зарплату сотрудника по значению его номера. PROCEDURE raise_salary (empid INTEGER, increase REAL) IS current_salary REAL; salary_missing EXCEPTION; BEGIN SELECT sal INTO current_salary FROM employee WHERE empno = emp_id; IF current_salary IS NULL THEN RAISE salary_missing; ELSE UPDATE employee SET sal = sal + increase WHERE empno = emp_id; END IF; EXCEPTION WHEN NO_DATA_FOUND THEN INSERT INTO emp_audit VALUES (emp_id, 'Нет сотрудника с таким номером'); WHEN salary_missing THEN INSERT INTO emp_audit VALUES (emp_id, Зарплата не назначена'); END raise_salary;
Заключение Обработка исключений, возникающих при выполнении блока PL/SQL Типы исключений: –предопределенные, возбуждаемые сервером Oracle –не предопределенные, возбуждаемые сервером Oracle –пользовательские Обработка исключений: –перехват –распространение