1.10 Exception Handling
PL/SQL allows developers to raise and handle
errors (exceptions) in a very flexible and powerful way. Each PL/SQL
block can have its own exception section in which exceptions can be
trapped and handled (resolved or passed on to the enclosing block).
When an exception occurs (is raised) in a PL/SQL block, its execution
section immediately terminates. Control is passed to the exception
section.
Every exception in PL/SQL has an error number and error message; some
exceptions also have names.
1.10.1 Declaring Exceptions
Some exceptions
(see the following table) have been pre-defined by Oracle in the
STANDARD package or other built-in packages, such as UTL_FILE. You
can also declare your own exceptions as follows:
DECLARE
exception_name EXCEPTION;
ORA-00001
|
DUP_VAL_ON_INDEX
|
ORA-00051
|
TIMEOUT_ON_RESOURCE
|
ORA-00061
|
TRANSACTION_BACKED_OUT
|
ORA-01001
|
INVALID_CURSOR
|
ORA-01012
|
NOT_LOGGED_ON
|
ORA-01017
|
LOGIN_DENIED
|
ORA-01403
|
NO_DATA_FOUND
|
ORA-01410
|
SYS_INVALID_ROWID
|
ORA-01422
|
TOO_MANY_ROWS
|
ORA-01476
|
ZERO_DIVIDE
|
ORA-01725
|
USERENV_COMMMITSCN_ERROR
|
ORA-01722
|
INVALID_NUMBER
|
ORA-06500
|
STORAGE_ERROR
|
ORA-06501
|
PROGRAM_ERROR
|
ORA-06502
|
VALUE_ERROR
|
ORA-06504
|
ROWTYPE_MISMATCH
|
ORA-06511
|
CURSOR_ALREADY_OPEN
|
ORA-06530
|
ACCESS_INTO_NULL
|
ORA-06531
|
COLLECTION_IS_NULL
|
ORA-06532
|
SUBSCRIPT_OUTSIDE_LIMIT
|
ORA-06533
|
SUBSCRIPT_BEYOND_COUNT
|
ORA-09592
|
CASE_NOT_FOUND
|
ORA-30625
|
SELF_IS_NULL
|
ORA-29280
|
INVALID_PATH
|
ORA-29281
|
INVALID_MODE
|
ORA-29282
|
INVALID_FILEHANDLE
|
ORA-29283
|
INVALID_OPERATION
|
ORA-29284
|
READ_ERROR
|
ORA-29285
|
WRITE_ERROR
|
ORA-29286
|
INTERNAL_ERROR
|
ORA-29287
|
INVALID_MAXLINESIZE
|
ORA-29288
|
INVALID_FILENAME
|
ORA-29289
|
ACCESS_DENIED
|
ORA-29290
|
INVALID_OFFSET
|
ORA-29291
|
DELETE_FAILED
|
ORA-29292
|
RENAME_FAILED
|
An exception can be declared only once in a block, but nested blocks
can declare an exception with the same name as an outer block. If
this multiple declaration occurs, scope takes precedence over name
when handling the exception. The inner block's
declaration takes precedence over a global declaration.
When you declare your own exception, you must RAISE it explicitly.
All declared exceptions have an error code of 1 and the error message
"User-defined exception," unless
you use the EXCEPTION_INIT pragma.
You can associate an error number with a declared exception with the
PRAGMA EXCEPTION_INIT statement using the following syntax:
DECLARE
exception_name EXCEPTION;
PRAGMA EXCEPTION_INIT (exception_name,
error_number);
where error_number is a literal value (variable
references are not allowed). This number can be an Oracle error, such
as -1855, or an error in the user-definable -20000 to -20999 range.
1.10.2 Raising Exceptions
An
exception can be raised in three ways:
By the PL/SQL runtime engine
By an explicit RAISE statement in your code
By a call to the built-in function RAISE_APPLICATION_ERROR
The syntax for the RAISE statement is:
RAISE exception_name;
where exception_name is the name of an exception
that you have declared, or an exception that is declared in the
STANDARD package. If you use the RAISE statement inside an exception
handler, you can omit the exception name to re-raise the current
exception:
RAISE;
This syntax is not valid outside the exception section.
The RAISE_APPLICATION_ERROR built-in function has the following
header:
RAISE_APPLICATION_ERROR (
num BINARY_INTEGER,
msg VARCHAR2,
keeperrorstack BOOLEAN DEFAULT FALSE);
where num is the error number (an integer
between -20999 and -20000), msg is the
associated error message, and keeperrorstack
controls the contents of the error stack.
1.10.3 Scope
The scope of an exception section is that
portion of the code that is
"covered" by the exception section.
An exception handler will only handle or attempt to handle exceptions
raised in the executable section of the PL/SQL block. Exceptions
raised in the declaration or exception sections are automatically
passed to the outer block. Any line or set of PL/SQL code can be
placed inside its own block and given its own exception section. This
allows you to limit the propagation of an exception.
1.10.4 Propagation
Exceptions raised in a PL/SQL block
propagate to an outer block if they are unhandled or re-raised in the
exception section. When an exception occurs, PL/SQL looks for an
exception handler that checks for the exception (or is the WHEN
OTHERS clause) in the current block. If a match is not found, then
PL/SQL propagates the exception to the enclosing block or calling
program. This propagation continues until the exception is handled or
propagated out of the outermost block, back to the calling program.
In this case, the exception is
"unhandled" and (1) stops the
calling program, and (2) causes an automatic rollback of any
outstanding transactions.
Once an exception is handled, it will not propagate upward. If you
want to trap an exception, display a meaningful error message, and
have the exception propagate upward as an error, you must re-raise
the exception. The RAISE statement can re-raise the current exception
or raise a new exception, as shown here:
PROCEDURE delete_dept(deptno_in IN NUMBER)
DECLARE
still_have_employees EXCEPTION
PRAGMA EXCEPTION_INIT(still_have_employees.
-2292)
BEGIN
DELETE FROM dept
WHERE deptno = deptno_in;
EXCEPTION
WHEN still_have_employees
THEN
DBMS_OUTPUT.PUT_LINE
('Please delete employees in dept first');
ROLLBACK;
RAISE; /* Re-raise the current exception. */
END;
1.10.4.1 WHEN OTHERS clause
Use the WHEN OTHERS clause in the exception
handler as a catch-all to trap any exceptions that are not handled by
specific WHEN clauses in the exception section. If present, this
clause must be the last exception handler in the exception section.
You specify this clause as follows:
EXCEPTION
WHEN OTHERS
THEN
...
1.10.4.2 SQLCODE and SQLERRM
SQLCODE and
SQLERRM are
built-in functions that provide the SQL error code and message for
the current exception. Use these functions inside the exception
section's WHEN OTHERS clause to handle specific
errors by number. The EXCEPTION_INIT pragma allows you to handle
errors by name. For example, the following code:
CREATE TABLE err_test
(widget_name VARCHAR2(100)
,widget_count NUMBER
,CONSTRAINT no_small_numbers CHECK
(widget_count > 1000));
BEGIN
INSERT INTO err_test (widget_name, widget_count)
VALUES ('Athena',2);
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -2290
AND SQLERRM LIKE '%NO_SMALL_NUMBERS%'
THEN
DBMS_OUTPUT.PUT_LINE('widget_count is too
small');
ELSE
DBMS_OUTPUT.PUT_LINE('Exception not handled,'
||'SQLcode='||SQLCODE);
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END IF;
END;
produces this output:
widget_count is too small
The built-in package DBMS_UTILITY's
FORMAT_ERROR_STACK and FORMAT_CALL_STACK procedures can be used to
capture the full error stack and call stack. See the book
Oracle Built-in Packages for more information on
DBMS_UTILITY.
1.10.4.3 Exceptions and DML
When an exception is raised in a PL/SQL block, it does
not roll back your current transaction, even if
the block itself issued an INSERT, UPDATE, or DELETE. You must issue
your own ROLLBACK statement if you want to clean up your transaction
as a result of the exception.
If your exception goes unhandled (propagates out of the outermost
block), however, most host environments will then force an automatic,
unqualified rollback of any outstanding changes in your session.
|