Oracle получить текст ошибки
При установлении исключительной ситуации управление программой сразу же передается
в секцию исключительных ситуаций блока.
Если такой секции в блоке нет, то исключение передается в объемлющий блок.
После передачи управления обработчику, вернуться в выполняющую секцию блока невозможно.
- стандартные
- определенные пользователем
Стандартные исключительные ситуации инициируются автоматически при возникновении
соответствующей ошибки Oracle.
Исключительные ситуации, определяемые пользователем,
устанавливаются явно при помощи оператора RAISE.
Обрабатываются исключения так:
EXCEPTION
WHEN имя_ex1 THEN
. ; -- обработать
WHEN имя_ex2 THEN
. ; -- обработать
WHEN OTHERS THEN
. ; -- обработать
END;
/
Имена исключений не должны повторяться т.е. каждое исключение может
обрабатываться максимум только одним обработчиком в секции EXCEPTION
Один обработчик может обслуживать несколько исключительных ситуаций
и их нужно перечислить в условии WHEN через OR
EXCEPTION
WHEN NO_DATA_FOUND OR TOO_MANY_ROWS THEN
INSERT INTO log_table(info) VALUES ('A select error occurred.');
END;
/
Два исключения одновременно один обработчик обработать не может:
WHEN имя_ex1 AND имя_ex2 - > ERR
Пользовательское исключение должно быть определено:
DECLARE
e_my_ex EXCEPTION;
.
BEGIN
IF (. ) THEN
RAISE e_my_ex;
END IF;
.
EXCEPTION
WHEN e_my_ex THEN
.
END;
/
После перехвата более специализированных исключений:
WHEN . THEN
.
WHEN . THEN
мы можем перехватить все остальные исключения с помощью:
WHEN OTHERS THEN
.
Обработчик OTHERS рекомендуется помещать на самом высоком уровне программы:
(В самом высшем блоке)
для обеспечения распознавания всех возможных ошибок.
Иначе ошибки будут распространяться в вызывающую среду и возможны
нежелательные последствия, такие как откат на сервере текущей транзакции.
Не используйте в промышленном коде такое:
WHEN OTHERS THEN NULL;
т.к. оно будет молчаливо перехватывать все неожиданные ошибки не сообщая,
что они произошли.
Обработчик OTHERS должен регистрировать ошибку и возможно предоставлять
дополнительную информацию для дальнейшего исследования.
WHEN OTHERS THEN
INSERT INTO log_table(info) VALUES ('Another error occurred.');
END;
/
Информацию об ошибках можно получить при помощи двух встроенных функций:
- SQLCODE
- SQLERRM
Для исключений определенных пользователем:
SQLCODE возвращает 1
а
SQLERRM "User-defined Exception"
WHEN OTHERS THEN
v_ErrorCode := SQLCODE;
v_ErrorText := SUBSTR(SQLERRM, 1, 200);
INSERT INTO log_tab(code, message, info) VALUES (v_ErrorCode, v_ErrorText, 'Oracle error.');
END;
/
SQLERRM(100) - > ORA-1403: no data found
Это исключение ANSI
Остальные коды ошибок Oracle все отрицательные.
Для получения информации об ошибке можно также использовать функцию
FORMAT_ERROR_STACK из пакета DBMS_UTILITY
Её можно непосредственно использовать в операторах SQL:
WHEN OTHERS THEN
INSERT INTO log_tab(code, message, info) VALUES (NULL,
SUBSTR(DBMS_UTILITY.FORMAT_ERROR_STACK, 1, 200),
'Oracle error occurred.');
END;
/
Ещё одна функция.
Любое именованное исключение можно связать с конкретной ошибкой ORACLE.
Например, в ORACLE есть стандартная ошибка ORA-1400, которая возникает при пропуске значения
или вставке значения NULL в столбец с ограничением NOT NULL.
ORA-1400: mandatory NOT NULL column missing or NULL during insert.
Мы хотим создать свое пользовательское именованное исключение и связать его с этой стандартной ошибкой ORA-1400
DECLARE
e_my_ex EXCEPTION;
PRAGMA EXCEPTION_INIT(e_my_ex, -1400);
BEGIN
WHEN e_my_ex THEN
INSERT INTO log_tab(info) VALUES ('ORA-1400 occurred.');
END;
/
Теперь мы перехватываем её по имени с помощъю WHEN или THEN
Все стандартные исключительные ситуации также ассоциируются с соответствующими им ошибками Oracle
при помощи прагмы EXCEPTION_INIT в пакете STANDARD
VALUE_ERROR - > ORA-6501
TO_MANY_ROWS - > ORA-1422
ZERO_DIVIDE - > ORA-1476
.
и т.д.
Так что если вам не хватает некоего имени конкретной ошибки ORA-NNNN,
то придумайте свое имя и свяжите его с ошибкой с помощью прагмы : EXCEPTION_INIT
RAISE_APPLICATION_ERROR(номер, текст, [флаг]);
TRUE - пополнить список ранее произошедших ошибок
FALSE - новая ошибка заместит текущий список ошибок (по умолчанию)
set serveroutput on
variable a NUMBER;
variable b NUMBER;
exec :a := 0;
exec :b := 10;
DECLARE
l_a NUMBER := :a;
l_b NUMBER := :b;
l_c NUMBER;
BEGIN
IF l_a = 0 THEN
raise_application_error(-20005, 'Divizor is 0');
END IF;
l_c := l_b / l_a;
dbms_output.put_line('The result: '||l_c);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
END;
/
Поскольку у исключения нет имени, то его может обработать только обработчик OTHERS
Но такое исключение можно и поименовать
и с помощью прагмы связать с нашим кодом.
my_ex EXCEPTION;
.
.
PRAGMA EXCEPTION_INIT(my_ex, -20005);
BEGIN
IF (. ) THEN
raise_application_error(-20005, 'Divizor is 0');
.
.
EXCEPTION
WHEN my_ex THEN
dbms_output.put_line(SQLERRM);
END;
/
Теперь это исключение можно обработать по имени с помощью:
WHEN my_ex THEN
Compile-Time Warnings
While compiling stored PL/SQL units, the PL/SQL compiler generates warnings for conditions that are not serious enough to cause errors and prevent compilation—for example, using a deprecated PL/SQL feature.
To see warnings (and errors) generated during compilation, either query the static data dictionary view *_ERRORS (described in Oracle Database Reference ) or, in the SQL*Plus environment, use the command SHOW ERRORS .
The message code of a PL/SQL warning has the form PLW- nnnnn . For the message codes of all PL/SQL warnings, see Oracle Database Error Messages .
Table 11-1 summarizes the categories of warnings.
Table 11-1 Compile-Time Warning Categories
Condition might cause unexpected action or wrong results.
Aliasing problems with parameters
Condition might cause performance problems.
Passing a VARCHAR2 value to a NUMBER column in an INSERT statement
Condition does not affect performance or correctness, but you might want to change it to make the code more maintainable.
Code that can never run
By setting the compilation parameter PLSQL_WARNINGS , you can:
Enable and disable all warnings, one or more categories of warnings, or specific warnings
Treat specific warnings as errors (so that those conditions must be corrected before you can compile the PL/SQL unit)
You can set the value of PLSQL_WARNINGS for:
Your Oracle database instance
Use the ALTER SYSTEM statement, described in Oracle Database SQL Language Reference .
Use the ALTER SESSION statement, described in Oracle Database SQL Language Reference .
A stored PL/SQL unit
Use an ALTER statement from "ALTER Statements" with its compiler_parameters_clause . For more information about PL/SQL units and compiler parameters, see "PL/SQL Units and Compilation Parameters".
In any of the preceding ALTER statements, you set the value of PLSQL_WARNINGS with this syntax:
For the syntax of value_clause , see Oracle Database Reference .
Example 11-1 shows several ALTER statements that set the value of PLSQL_WARNINGS .
Example 11-1 Setting Value of PLSQL_WARNINGS Compilation Parameter
For the session, enable all warnings—highly recommended during development:
For the session, enable PERFORMANCE warnings:
For the procedure loc_var , enable PERFORMANCE warnings, and reuse settings:
For the session, enable SEVERE warnings, disable PERFORMANCE warnings, and treat PLW-06002 warnings as errors:
For the session, disable all warnings:
To display the current value of PLSQL_WARNINGS , query the static data dictionary view ALL_PLSQL_OBJECT_SETTINGS , described in Oracle Database Reference .
DBMS_WARNING Package
If you are writing PL/SQL units in a development environment that compiles them (such as SQL*Plus), you can display and set the value of PLSQL_WARNINGS by invoking subprograms in the DBMS_WARNING package.
Example 11-2 uses an ALTER SESSION statement to disable all warning messages for the session and then compiles a procedure that has unreachable code. The procedure compiles without warnings. Next, the example enables all warnings for the session by invoking DBMS_WARNING.set_warning_setting_string and displays the value of PLSQL_WARNINGS by invoking DBMS_WARNING.get_warning_setting_string . Finally, the example recompiles the procedure, and the compiler generates a warning about the unreachable code.
Unreachable code could represent a mistake or be intentionally hidden by a debug flag.
Example 11-2 Displaying and Setting PLSQL_WARNINGS with DBMS_WARNING Subprograms
Disable all warning messages for this session:
With warnings disabled, this procedure compiles with no warnings:
Enable all warning messages for this session:
Check warning setting:
DBMS_WARNING subprograms are useful when you are compiling a complex application composed of several nested SQL*Plus scripts, where different subprograms need different PLSQL_WARNINGS settings. With DBMS_WARNING subprograms, you can save the current PLSQL_WARNINGS setting, change the setting to compile a particular set of subprograms, and then restore the setting to its original value.
Oracle Database PL/SQL Packages and Types Reference for more information about the DBMS_WARNING package
Overview of Exception Handling
Exceptions (PL/SQL runtime errors) can arise from design faults, coding mistakes, hardware failures, and many other sources. You cannot anticipate all possible exceptions, but you can write exception handlers that let your program to continue to operate in their presence.
Any PL/SQL block can have an exception-handling part, which can have one or more exception handlers. For example, an exception-handling part could have this syntax:
In the preceding syntax example, ex_name_ n is the name of an exception and statements_ n is one or more statements. (For complete syntax and semantics, see "Exception Handler".)
When an exception is raised in the executable part of the block, the executable part stops and control transfers to the exception-handling part. If ex_name_1 was raised, then statements_1 run. If either ex_name_2 or ex_name_3 was raised, then statements_2 run. If any other exception was raised, then statements_3 run.
After an exception handler runs, control transfers to the next statement of the enclosing block. If there is no enclosing block, then:
If the exception handler is in a subprogram, then control returns to the invoker, at the statement after the invocation.
If the exception handler is in an anonymous block, then control transfers to the host environment (for example, SQL*Plus)
If an exception is raised in a block that has no exception handler for it, then the exception propagates. That is, the exception reproduces itself in successive enclosing blocks until a block has a handler for it or there is no enclosing block (for more information, see "Exception Propagation"). If there is no handler for the exception, then PL/SQL returns an unhandled exception error to the invoker or host environment, which determines the outcome (for more information, see "Unhandled Exceptions").
Guidelines for Avoiding and Handling Exceptions
To make your programs as reliable and safe as possible:
Use both error-checking code and exception handlers.
Use error-checking code wherever bad input data can cause an error. Examples of bad input data are incorrect or null actual parameters and queries that return no rows or more rows than you expect. Test your code with different combinations of bad input data to see what potential errors arise.
Sometimes you can use error-checking code to avoid raising an exception, as in Example 11-7.
Add exception handlers wherever errors can occur.
Errors are especially likely during arithmetic calculations, string manipulation, and database operations. Errors can also arise from problems that are independent of your code—for example, disk storage or memory hardware failure—but your code still must take corrective action.
Design your programs to work when the database is not in the state you expect.
For example, a table you query might have columns added or deleted, or their types might have changed. You can avoid problems by declaring scalar variables with %TYPE qualifiers and record variables to hold query results with %ROWTYPE qualifiers.
Whenever possible, write exception handlers for named exceptions instead of using OTHERS exception handlers.
Learn the names and causes of the predefined exceptions. If you know that your database operations might raise specific internally defined exceptions that do not have names, then give them names so that you can write exception handlers specifically for them.
Have your exception handlers output debugging information.
If you store the debugging information in a separate table, do it with an autonomous routine, so that you can commit your debugging information even if you roll back the work that the main subprogram did. For information about autonomous routines, see "AUTONOMOUS_TRANSACTION Pragma".
For each exception handler, carefully decide whether to have it commit the transaction, roll it back, or let it continue.
Regardless of the severity of the error, you want to leave the database in a consistent state and avoid storing bad data.
Avoid unhandled exceptions by including an OTHERS exception handler at the top level of every PL/SQL program.
Make the last statement in the OTHERS exception handler either RAISE or an invocation of the RAISE_APPLICATION_ERROR procedure. (If you do not follow this practice, and PL/SQL warnings are enabled, then you get PLW-06009.) For information about RAISE or an invocation of the RAISE_APPLICATION_ERROR , see "Raising Exceptions Explicitly".
EXCEPTION PROPAGATION
enclosing block - обьемлющий блок
Если в текущем блоке имеется обработчик данной исключительной ситуации,
то он выполняется и блок успешно завершается.
Управление передаётся вышестоящему блоку.
Если обработчик отсутствует, исключительная ситуация передается в обьемлющий блок и инициируется там.
Если обьемлющего блока не существует, то исключение будет передано вызывающей среды (например SQL*Plus).
При вызове процедуры также может создаваться обьемлющий блок:
p(. ); -- вызов процедуры
EXCEPTION
WHEN OTHERS THEN
-- исключение инициированное p()
-- будет обработано здесь
END;
/
Исключения инициируемые в секции обьявлений (DECLARE) не обрабатываются секцией EXCEPTION
текущего блока, а передаются в EXCEPTION обьемлющего блока.
Тоже самое, если исключение инициируется в секции EXCEPTION,
то обработка данного исключения передается в обьемлющий блок.
Исключительную ситуацию можно обработать в текущем блоке и сразу снова установить
то же самое исключение, которое будет передано в обьемлющую область:
RAISE A;
EXCEPTION
WHEN A THEN
INSERT INTO log_tab(info) VALUES ('Exception A occurred.');
COMMIT;
RAISE;
END;
/
Тут commit гарантирует, что результаты insert будут зафиксированы
в базе данных в случае отката транзакции.
С помощью пакета UTL_FILE можно избежать необходимости commit
или используйте автономные транзакции.
Область действия исключительной ситуации
BEGIN
DECLARE
e_ex EXCEPTION; -- видно по имени только внутри блока
BEGIN
RAISE e_ex;
END;
EXCEPTION
-- тут исключение не видно по имени e_ex
-- и его можно обработать с помощью обработчика OTHERS
WHEN OTHERS THEN
-- инициируем это исключение повторно
RAISE; -- Теперь это исключение передается вызывающей среде
END;
/
Как описать исключение, которое будет видно вне блока?
Нужно создать пакет Globals и описать в нем пользовательское исключение.
Такая исключительная ситуация будет видима и во внешнем блоке.
CREATE OR REPLACE PACKAGE Globals AS
e_ex EXCEPTION;
END Globals;
BEGIN
BEGIN
RAISE Globals.e_ex;
END;
EXCEPTION
WHEN Globals.e_ex THEN
-- инициируем повторно
-- для передачи в вызывающую среду
RAISE;
END;
/
В пакете Globals можно также объявлять:
- таблицы
- переменные
- типы
Избегайте необработанных исключений
Нельзя допускать завершение программ, пока в них остаются необработанные исключения
Используйте обработчик OTHERS на самом верхнем уровне программы.
И пусть он регистрирует факт и время возникновения ошибки.
И ни одна ошибка не останется без внимания.
v_ErrorNumber NUMBER;
v_ErrorText VARCHAR2(200);
BEGIN
.
.
EXCEPTION
WHEN OTHERS THEN
.
v_ErrorNumber := SQLCODE;
v_ErrorText := SUBSTR(SQLERRM, 1, 200);
INSERT INTO log_tab(code, message, info)
VALUES (v_ErrorNumber, v_ErrorText,
'Oracle error . at ' || to_char(sysdate, 'DD-MON-YYHH24:MI:SS'));
END;
/
Можно использовать и утилиту DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
она регистрирует первоначальное местовозникновения исключения.
Как определить, где произошла ошибка?
SELECT .
SELECT .
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- какой select инициировал ошибку?
END;
/
Можно создать счетчик, указывающий на sql - оператор:
v_sel_count NUMBER := 1;
BEGIN
SELECT .
v_sel_count := 2;
SELECT .
v_sel_count := 3;
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_tab(info)
VALUES ('no data found in select '||v_sel_count);
END;
/
Можно разместить каждый select в собственном врутреннем блоке
BEGIN
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_tab(info)
VALUES ('no data found in select 1');
END;
BEGIN
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_tab(info)
VALUES ('no data found in select 2');
END;
BEGIN
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_tab(info)
VALUES ('no data found in select 3');
END;
Или использовать : DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
и потом анализировать файл трассировки.
Пусть в нашей программе Oracle выдает ошибку ORA-01844: not f valid month
перехватить его можно так:
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -1843 THEN
Да, код плохо читаем.
Сделаем его более лучшим:
PROCEDURE my_procedure
IS
invalid_month EXCEPTION;
PRAGMA EXCEPTION_INIT(invalid_month, -1843);
Язык PL/SQL предоставляет разработчикам мощный механизм оповещения о возникающих ошибках и их обработки. Следующая процедура получает имя и баланс счета по идентификатору, после чего проверяет баланс. При слишком низком значении процедура явно инициирует исключение, которое прекращает выполнение программы:
Рассмотрим подробнее ту часть кода, которая связана с обработкой ошибок.
Строки
Описание
Объявление пользовательского исключения с именем l _ balance _ below _ minimum . В Oracle имеется набор заранее определенных исключений, таких как DUP _ VAL _ ON _ INDEX , но для данного приложения я хочу создать нечто более конкретное, поэтому определяю собственный тип исключения
Запрос для получения имени счета. Если счет с указанным идентификатором не существует, Oracle инициирует стандартное исключение NO _ DATA _ FOUND , что ведет к завершению программы
Если баланс слишком низок, процедура явно инициирует пользовательское исключение, поскольку это свидетельствует о наличии серьезных проблем со счетом
Ключевое слово EXCEPTION отмечает конец исполняемого раздела и начало раздела исключений, в котором обрабатываются ошибки
Блок обработки ошибок для ситуации, когда счет не найден. Если было инициировано исключение NO _ DATA _ FOUND , здесь оно перехватывается, а ошибка регистрируется в журнале процедурой log _ error . Затем я заново инициирую то же самое исключение, чтобы внешний блок был в курсе того, что для идентификатора счета отсутствует совпадение
Блок обработки ошибок для ситуации, когда баланс счета оказался слишком низким (пользовательское исключение для данного приложения). Если было инициировано исключение l _ balance _ below _ minimum , оно перехватывается и ошибка регистрируется в журнале. Затем я инициирую системное исключение VALUE _ ERROR , чтобы оповестить внешний блок о проблеме
Механизмы обработки ошибок PL/SQL подробно рассмотрим в следующих статьях моего блога. Конечно, о PL/SQL еще можно сказать очень много — собственно, именно поэтому материал моего блога предполагают занять не одну сотню страниц! ;-) Но для начала пример выше дает некоторое представление о коде PL/SQL, его важнейших синтаксических элементах и о той простоте, с которой пишется (и читается) код PL/SQL.
This chapter explains how to handle PL/SQL compile-time warnings and PL/SQL runtime errors. The latter are called exceptions .
The language of warning and error messages depends on the NLS_LANGUAGE parameter. For information about this parameter, see Oracle Database Globalization Support Guide .
If you have problems creating or running PL/SQL code, check the Oracle Database trace files. The USER_DUMP_DEST initialization parameter specifies the current location of the trace files. You can find the value of this parameter by issuing SHOW PARAMETER USER_DUMP_DEST . For more information about trace files, see Oracle Database Performance Tuning Guide .
Internally Defined Exceptions
Internally defined exceptions (ORA- n errors) are described in Oracle Database Error Messages . The runtime system raises them implicitly (automatically).
An internally defined exception does not have a name unless either PL/SQL gives it one (see "Predefined Exceptions") or you give it one.
If you know that your database operations might raise specific internally defined exceptions that do not have names, then give them names so that you can write exception handlers specifically for them. Otherwise, you can handle them only with OTHERS exception handlers.
To give a name to an internally defined exception, do the following in the declarative part of the appropriate anonymous block, subprogram, or package. (To determine the appropriate block, see "Exception Propagation".)
Declare the name.
An exception name declaration has this syntax:
For semantic information, see "Exception Declaration".
Associate the name with the error code of the internally defined exception.
For semantic information, see "EXCEPTION_INIT Pragma".
An internally defined exception with a user-declared name is still an internally defined exception, not a user-defined exception.
Example 11-5 gives the name deadlock_detected to the internally defined exception ORA-00060 (deadlock detected while waiting for resource) and uses the name in an exception handler.
Example 11-5 Naming Internally Defined Exception
Predefined Exceptions
Predefined exceptions are internally defined exceptions that have predefined names, which PL/SQL declares globally in the package STANDARD . The runtime system raises predefined exceptions implicitly (automatically). Because predefined exceptions have names, you can write exception handlers specifically for them.
Run-time errors arise from design faults, coding mistakes, hardware failures, and many other sources. Although you cannot anticipate all possible errors, you can plan to handle certain kinds of errors meaningful to your PL/SQL program.
With many programming languages, unless you disable error checking, a run-time error such as stack overflow or division by zero stops normal processing and returns control to the operating system. With PL/SQL, a mechanism called exception handling lets you "bulletproof" your program so that it can continue operating in the presence of errors.
This chapter discusses the following topics:
Exception Categories
The runtime system raises internally defined exceptions implicitly (automatically). Examples of internally defined exceptions are ORA-00060 (deadlock detected while waiting for resource) and ORA-27102 (out of memory).
An internally defined exception always has an error code, but does not have a name unless PL/SQL gives it one or you give it one.
A predefined exception is an internally defined exception that PL/SQL has given a name. For example, ORA-06500 (PL/SQL: storage error) has the predefined name STORAGE_ERROR .
You can declare your own exceptions in the declarative part of any PL/SQL anonymous block, subprogram, or package. For example, you might declare an exception named insufficient_funds to flag overdrawn bank accounts.
You must raise user-defined exceptions explicitly.
Table 11-2 summarizes the exception categories.
Table 11-2 Exception Categories
Only if you assign one
Only if you assign one
For a named exception, you can write a specific exception handler, instead of handling it with an OTHERS exception handler. A specific exception handler is more efficient than an OTHERS exception handler, because the latter must invoke a function to determine which exception it is handling. For details, see "Error Code and Error Message Retrieval".
Predefined PL/SQL Exceptions
An internal exception is raised implicitly whenever your PL/SQL program violates an Oracle rule or exceeds a system-dependent limit. Every Oracle error has a number, but exceptions must be handled by name. So, PL/SQL predefines some common Oracle errors as exceptions. For example, PL/SQL raises the predefined exception NO_DATA_FOUND if a SELECT INTO statement returns no rows.
To handle other Oracle errors, you can use the OTHERS handler. The functions SQLCODE and SQLERRM are especially useful in the OTHERS handler because they return the Oracle error code and message text. Alternatively, you can use the pragma EXCEPTION_INIT to associate exception names with Oracle error codes.
PL/SQL declares predefined exceptions globally in package STANDARD , which defines the PL/SQL environment. So, you need not declare them yourself. You can write handlers for predefined exceptions using the names in the following list:
Маленькое руководство по отлавливанию ошибок в Oracle PLSQL.
Описание как использовать в Oracle (PLSQL) функции SQLERRM и SQLCODE для отлова ошибок EXCEPTION, с описанием синтаксиса и примером.
Функция SQLCODE возвращает код ошибки связанный с последним возникшим исключением (ошибкой)
Функция SQLERRM — не имеет параметров.
Обычно обработка исключений EXCEPTION выглядит следующим образом:
Варианты основных возможных ошибок:
DUP_VAL_ON_INDEX
ORA-00001
При попытке произвести вставку INSERT или изменение UPDATE данных которое создает дублирующую запись нарушающую уникальный индекс (unique index).
TIMEOUT_ON_RESOURCE
ORA-00051
Происходит когда ресурс над которым производится операция заблокирован и произошел сброс по таймауту.
TRANSACTION_BACKED_OUT
ORA-00061
Произошёл частичный откат транзакции.
INVALID_CURSOR
ORA-01001
Попытка использовать курсор которого не существует. Может происходить если вы пытаетесь использовать FETCH курсор или закрыть CLOSE курсор до того как вы этот курсор открыли OPEN.
NOT_LOGGED_ON
ORA-01012
Попытка произвести действия не залогинившись.
LOGIN_DENIED
ORA-01017
Неудачная попытка залогиниться, в доступе отказано, не верный пользователь или пароль.
NO_DATA_FOUND
ORA-01403
Что то из перечисленного: Попытка произвести вставку SELECT INTO несуществующего набора значений (select — ничего не возвращает). Попытка доступа к неинициализированной строке/записи в таблице. Попытка чтения записи после окончания файла при помощи пакета UTL_FILE.
TOO_MANY_ROWS
ORA-01422
Попытка вставить значение в переменную при помощи SELECT INTO и select вернул более чем одно значение.
ZERO_DIVIDE
ORA-01476
Попытка деления на ноль.
INVALID_NUMBER
ORA-01722
Попытка выполнить SQL запрос который производит конвертацию строки (STRING) в число (NUMBER) при этом такое преобразование невозможно.
STORAGE_ERROR
ORA-06500
Либо нехватка памяти, либо ошибка в памяти.
PROGRAM_ERROR
ORA-06501
Внутренняя программная ошибка рекомендуется с такой ошибкой обращаться в службу поддержки Oracle.
VALUE_ERROR
ORA-06502
Попытка выполнить операцию конвертации данных которая закончилась с ошибкой (например: округление, преобразование типов, и т.п.).
CURSOR_ALREADY_OPEN
ORA-06511
Вы пытаетесь открыть курсор который уже открыт.
Advantages of Exception Handlers
Using exception handlers for error-handling makes programs easier to write and understand, and reduces the likelihood of unhandled exceptions.
Without exception handlers, you must check for every possible error, everywhere that it might occur, and then handle it. It is easy to overlook a possible error or a place where it might occur, especially if the error is not immediately detectable (for example, bad data might be undetectable until you use it in a calculation). Error-handling code is scattered throughout the program.
With exception handlers, you need not know every possible error or everywhere that it might occur. You need only include an exception-handling part in each block where errors might occur. In the exception-handling part, you can include exception handlers for both specific and unknown errors. If an error occurs anywhere in the block (including inside a sub-block), then an exception handler handles it. Error-handling code is isolated in the exception-handling parts of the blocks.
In Example 11-3, a procedure uses a single exception handler to handle the predefined exception NO_DATA_FOUND , which can occur in either of two SELECT INTO statements.
Example 11-3 Single Exception Handler for Multiple Exceptions
Invoke procedure (there is a DEPARTMENTS table, but it does not have a LAST_NAME column):
Invoke procedure (there is no EMP table):
If multiple statements use the same exception handler, and you want to know which statement failed, you can use locator variables, as in Example 11-4.
Example 11-4 Locator Variables for Statements that Share Exception Handler
You determine the precision of your error-handling code. You can have a single exception handler for all division-by-zero errors, bad array indexes, and so on. You can also check for errors in a single statement by putting that statement inside a block with its own exception handler.
Overview of PL/SQL Error Handling
In PL/SQL, a warning or error condition is called an exception. Exceptions can be internally defined (by the run-time system) or user defined. Examples of internally defined exceptions include division by zero and out of memory. Some common internal exceptions have predefined names, such as ZERO_DIVIDE and STORAGE_ERROR . The other internal exceptions can be given names.
You can define exceptions of your own in the declarative part of any PL/SQL block, subprogram, or package. For example, you might define an exception named insufficient_funds to flag overdrawn bank accounts. Unlike internal exceptions, user-defined exceptions must be given names.
When an error occurs, an exception is raised. That is, normal execution stops and control transfers to the exception-handling part of your PL/SQL block or subprogram. Internal exceptions are raised implicitly (automatically) by the run-time system. User-defined exceptions must be raised explicitly by RAISE statements, which can also raise predefined exceptions.
To handle raised exceptions, you write separate routines called exception handlers. After an exception handler runs, the current block stops executing and the enclosing block resumes with the next statement. If there is no enclosing block, control returns to the host environment.
In the example below, you calculate and store a price-to-earnings ratio for a company with ticker symbol XYZ. If the company has zero earnings, the predefined exception ZERO_DIVIDE is raised. This stops normal execution of the block and transfers control to the exception handlers. The optional OTHERS handler catches all exceptions that the block does not name specifically.
The last example illustrates exception handling, not the effective use of INSERT statements. For example, a better way to do the insert follows:
In this example, a subquery supplies values to the INSERT statement. If earnings are zero, the function DECODE returns a null. Otherwise, DECODE returns the price-to-earnings ratio.
EXCEPTION PROPAGATION
enclosing block - обьемлющий блок
Если в текущем блоке имеется обработчик данной исключительной ситуации,
то он выполняется и блок успешно завершается.
Управление передаётся вышестоящему блоку.
Если обработчик отсутствует, исключительная ситуация передается в обьемлющий блок и инициируется там.
Если обьемлющего блока не существует, то исключение будет передано вызывающей среды (например SQL*Plus).
При вызове процедуры также может создаваться обьемлющий блок:
p(. ); -- вызов процедуры
EXCEPTION
WHEN OTHERS THEN
-- исключение инициированное p()
-- будет обработано здесь
END;
/
Исключения инициируемые в секции обьявлений (DECLARE) не обрабатываются секцией EXCEPTION
текущего блока, а передаются в EXCEPTION обьемлющего блока.
Тоже самое, если исключение инициируется в секции EXCEPTION,
то обработка данного исключения передается в обьемлющий блок.
Исключительную ситуацию можно обработать в текущем блоке и сразу снова установить
то же самое исключение, которое будет передано в обьемлющую область:
RAISE A;
EXCEPTION
WHEN A THEN
INSERT INTO log_tab(info) VALUES ('Exception A occurred.');
COMMIT;
RAISE;
END;
/
Тут commit гарантирует, что результаты insert будут зафиксированы
в базе данных в случае отката транзакции.
С помощью пакета UTL_FILE можно избежать необходимости commit
или используйте автономные транзакции.
Область действия исключительной ситуации
BEGIN
DECLARE
e_ex EXCEPTION; -- видно по имени только внутри блока
BEGIN
RAISE e_ex;
END;
EXCEPTION
-- тут исключение не видно по имени e_ex
-- и его можно обработать с помощью обработчика OTHERS
WHEN OTHERS THEN
-- инициируем это исключение повторно
RAISE; -- Теперь это исключение передается вызывающей среде
END;
/
Как описать исключение, которое будет видно вне блока?
Нужно создать пакет Globals и описать в нем пользовательское исключение.
Такая исключительная ситуация будет видима и во внешнем блоке.
CREATE OR REPLACE PACKAGE Globals AS
e_ex EXCEPTION;
END Globals;
BEGIN
BEGIN
RAISE Globals.e_ex;
END;
EXCEPTION
WHEN Globals.e_ex THEN
-- инициируем повторно
-- для передачи в вызывающую среду
RAISE;
END;
/
В пакете Globals можно также объявлять:
- таблицы
- переменные
- типы
Избегайте необработанных исключений
Нельзя допускать завершение программ, пока в них остаются необработанные исключения
Используйте обработчик OTHERS на самом верхнем уровне программы.
И пусть он регистрирует факт и время возникновения ошибки.
И ни одна ошибка не останется без внимания.
v_ErrorNumber NUMBER;
v_ErrorText VARCHAR2(200);
BEGIN
.
.
EXCEPTION
WHEN OTHERS THEN
.
v_ErrorNumber := SQLCODE;
v_ErrorText := SUBSTR(SQLERRM, 1, 200);
INSERT INTO log_tab(code, message, info)
VALUES (v_ErrorNumber, v_ErrorText,
'Oracle error . at ' || to_char(sysdate, 'DD-MON-YYHH24:MI:SS'));
END;
/
Можно использовать и утилиту DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
она регистрирует первоначальное местовозникновения исключения.
Как определить, где произошла ошибка?
SELECT .
SELECT .
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- какой select инициировал ошибку?
END;
/
Можно создать счетчик, указывающий на sql - оператор:
v_sel_count NUMBER := 1;
BEGIN
SELECT .
v_sel_count := 2;
SELECT .
v_sel_count := 3;
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_tab(info)
VALUES ('no data found in select '||v_sel_count);
END;
/
Можно разместить каждый select в собственном врутреннем блоке
BEGIN
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_tab(info)
VALUES ('no data found in select 1');
END;
BEGIN
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_tab(info)
VALUES ('no data found in select 2');
END;
BEGIN
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_tab(info)
VALUES ('no data found in select 3');
END;
Или использовать : DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
и потом анализировать файл трассировки.
Пусть в нашей программе Oracle выдает ошибку ORA-01844: not f valid month
перехватить его можно так:
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -1843 THEN
Да, код плохо читаем.
Сделаем его более лучшим:
PROCEDURE my_procedure
IS
invalid_month EXCEPTION;
PRAGMA EXCEPTION_INIT(invalid_month, -1843);
Язык PL/SQL предоставляет разработчикам мощный механизм оповещения о возникающих ошибках и их обработки. Следующая процедура получает имя и баланс счета по идентификатору, после чего проверяет баланс. При слишком низком значении процедура явно инициирует исключение, которое прекращает выполнение программы:
Рассмотрим подробнее ту часть кода, которая связана с обработкой ошибок.
Строки
Описание
Объявление пользовательского исключения с именем l _ balance _ below _ minimum . В Oracle имеется набор заранее определенных исключений, таких как DUP _ VAL _ ON _ INDEX , но для данного приложения я хочу создать нечто более конкретное, поэтому определяю собственный тип исключения
Запрос для получения имени счета. Если счет с указанным идентификатором не существует, Oracle инициирует стандартное исключение NO _ DATA _ FOUND , что ведет к завершению программы
Если баланс слишком низок, процедура явно инициирует пользовательское исключение, поскольку это свидетельствует о наличии серьезных проблем со счетом
Ключевое слово EXCEPTION отмечает конец исполняемого раздела и начало раздела исключений, в котором обрабатываются ошибки
Блок обработки ошибок для ситуации, когда счет не найден. Если было инициировано исключение NO _ DATA _ FOUND , здесь оно перехватывается, а ошибка регистрируется в журнале процедурой log _ error . Затем я заново инициирую то же самое исключение, чтобы внешний блок был в курсе того, что для идентификатора счета отсутствует совпадение
Блок обработки ошибок для ситуации, когда баланс счета оказался слишком низким (пользовательское исключение для данного приложения). Если было инициировано исключение l _ balance _ below _ minimum , оно перехватывается и ошибка регистрируется в журнале. Затем я инициирую системное исключение VALUE _ ERROR , чтобы оповестить внешний блок о проблеме
Механизмы обработки ошибок PL/SQL подробно рассмотрим в следующих статьях моего блога. Конечно, о PL/SQL еще можно сказать очень много — собственно, именно поэтому материал моего блога предполагают занять не одну сотню страниц! ;-) Но для начала пример выше дает некоторое представление о коде PL/SQL, его важнейших синтаксических элементах и о той простоте, с которой пишется (и читается) код PL/SQL.
This chapter explains how to handle PL/SQL compile-time warnings and PL/SQL runtime errors. The latter are called exceptions .
The language of warning and error messages depends on the NLS_LANGUAGE parameter. For information about this parameter, see Oracle Database Globalization Support Guide .
If you have problems creating or running PL/SQL code, check the Oracle Database trace files. The USER_DUMP_DEST initialization parameter specifies the current location of the trace files. You can find the value of this parameter by issuing SHOW PARAMETER USER_DUMP_DEST . For more information about trace files, see Oracle Database Performance Tuning Guide .
Advantages of PL/SQL Exceptions
Using exceptions for error handling has several advantages. Without exception handling, every time you issue a command, you must check for execution errors:
Error processing is not clearly separated from normal processing; nor is it robust. If you neglect to code a check, the error goes undetected and is likely to cause other, seemingly unrelated errors.
With exceptions, you can handle errors conveniently without the need to code multiple checks, as follows:
Exceptions improve readability by letting you isolate error-handling routines. The primary algorithm is not obscured by error recovery algorithms. Exceptions also improve reliability. You need not worry about checking for an error at every point it might occur. Just add an exception handler to your PL/SQL block. If the exception is ever raised in that block (or any sub-block), you can be sure it will be handled.
Читайте также: