Database Chapter 6
Database Chapter 6
Types of Exceptions
Raising and Handling Exceptions
129
© SQL Star International Ltd.
Objectives
At the end of this chapter, you will be able to:
130
© SQL Star International Ltd.
Introduction
There can be situations when a PL/SQL code might generate a runtime error. This
error in PL/SQL is known as an Exception which is an identifier that is raised when it
encounters an unacceptable situation during the execution thereby causing the block
to terminate. The exceptions are handled by a special code called exception
handlers.
The activities that are included when working with exceptions are:
Declaring an exception
Raising an Exception
Trapping and Handling the Exception
Propagating the Exception
Let us look into each of them in detail.
Declaring Exceptions
Exceptions are also known as Named Identifiers. These are declared in the
declarative section of the PL/SQL block.
Syntax for declaring Exceptions:
DECLARE
exception_name EXCEPTION;
Raising Exceptions
An exception is raised when unacceptable situations are encountered. It can be
raised implicitly or explicitly.
Syntax for raising an exception explicitly using the RAISE keyword:
BEGIN
.............
RAISE exception_name;
Trapping Exceptions
Exceptions are trapped when the control encounters a RAISE EXCEPTION in the
executable section of a PL/SQL code. Then the control is given to the corresponding
131
© SQL Star International Ltd.
exception handler in the exception section of the block. After an exception is handled
it terminates the PL/SQL code and leaves the block.
The syntax to trap an exception is:
EXCEPTION
statement1;
statement2;
statement1;
statement2;
. . .]
statement1;
statement2;
. . .]
Where,
exception1 …exceptionN are the names of the exceptions handler.
statement1 . . . are SQL or PL/SQL statements
OTHERS is a clause that traps unspecified exceptions. This is an optional clause.
Only the exceptions specified in the executable section of the block can be handled
by the exception handlers. The exceptions not specified in the executable block are
handled by the WHEN OTHERS clause. Hence, this clause is always placed last. All
untrapped exceptions are trapped with this clause.
132
© SQL Star International Ltd.
Propagating Exceptions
When the block that raised the exception handles it, the block terminates as per the
instructions in the handler. Then the END statement of the block is encountered and the
control is given back to the enclosing block for execution.
In case of Nested blocks, when an exception is raised and there is no corresponding
handler within the block, the control is shifted to successive enclosing blocks in order of
execution. When the control is passed to these blocks the executable transactions of that
block are skipped. The advantage of doing this is, you can code handlers for specific
exceptions within the block. The enclosing successive blocks can handle the general
exceptions. If the exception is not handled by any of these blocks then the control is
passed on to the calling or host environment. All the other blocks are terminated.
Given below is a list of calling environments and the messages they generate when they
have to handle an exception.
The SQL * PLUS environment displays the error number and its message on
screen.
The Procedure Builder also displays the error number and its message.
In Oracle Developer Forms, the error number and message is trapped by the
in-built functions ERROR_CODE and ERROR_TEXT in a trigger.
A pre-compiler application accesses the error number using the SQLCA data
structure.
Finally, an enclosing PL/SQL block traps the exception in a handler in its exception
handling section.
Types of Exceptions
The three types of exceptions are:
Predefined exceptions
User-defined exceptions
Non-predefined exceptions
Predefined Exceptions
While writing SELECT statements you would have encountered errors like too many
rows or no data found. This is an error generated by the Oracle server. Errors like
these are trapped and handled by the server itself. These errors are called
Predefined Exceptions, as these are already defined within the server. These errors
occur due to some common situations in a database. Instead of you invoking and
trapping these errors explicitly, they are done automatically. A list of some of the
133
© SQL Star International Ltd.
common pre-defined exceptions is given below in a table, along with their error
number and what the error implies.
134
© SQL Star International Ltd.
When predefined errors occur, if you want your code to execute in a different
manner then code must be included in the exception section. For instance, the desk
officer of the
New Jersey Central Library handles frequent enquiries pertaining to books written by
particular authors by querying the Book table. But to save him the task of querying
the table repeatedly, the library database developer decides to embed the requisite
query into a
PL/SQL block. The database developer writes a code that will retrieve books written
by the author whose name the desk officer is prompted to enter. But while writing
such a code, the database developer needs to handle commonly encountered
exceptions such as NO_DATA_FOUND or TOO_MANY_ROWS and word them in a way
that would make it easy for the desk officer to interpret. The following code
illustrates this:
DECLARE
vAuthorName Book.cAuthorName%TYPE:=’&author’;
vBkName Book.cBookName%TYPE;
BEGIN
SELECT cBookName
INTO vBkName
FROM Book
135
© SQL Star International Ltd.
WHERE cAuthorName=vAuthorName;
EXCEPTION
author’||‘- ’||vAuthorName);
’||vAuthorName);
END;
/
This code returns easily understandable error messages on being executed. Such as:
more than one book written by author-Shakespeare: If the author name
entered causes the embedded query to return more than one book written by
the same author
no book written by author-Jane Austen: If the author name entered
causes the query to return no books by the same author
An error has occurred: check the author name you have just entered: If
any other error such as misspelling an author’s name or entering a name that
does not exist in the database table.
However, instead of displaying your own error message in the WHEN OTHERS clause,
you could easily identify the error code and error message associated with errors (other
than NO_DATA_FOUND and TOO_MANY_ROWS) using the following two functions:
SQLCODE, which returns the numeric value of an error
SQLERRM, which returns the message associated with the error number
Some of the SQLCODE values are:
0 – if no exception is encountered
1 – for user defined exceptions
+100 – for NO_DATA_FOUND exception
negative number – for any other Oracle server error
136
© SQL Star International Ltd.
Using the two functions, the WHEN OTHERS clause of the above code could be
rewritten. But you need to declare two variables to hold the values returned by the
functions in the following way:
DECLARE
vErrCode NUMBER;
vErrMssg VARCHAR2(255);
vBkName Book.cBookName%TYPE;
BEGIN
SELECT cBookName
INTO vBkName
FROM Book
WHERE cAuthorName=vAuthorName;
EXCEPTION
author’||’- ’||vAuthorName);
vErrCode:= SQLCODE;
vErrMssg:= SQLERRM;
DBMS_OUTPUT.PUT_LINE(vErrCode||’-’||vErrMssg);
END;
/
On executing the above code, the functions SQLCODE and SQLERRM return the error
number and error message respectively on encountering an author’s name whose books
are not stored in the New Jersey Central Library.
Enter value for author: Jane Austen
100-ORA-01403: no data found
The Oracle server provides another method (other than using
DBMS_OUTPUT.PUT_LINE) to communicate predefined exceptions interactively. The
method uses RAISE_APPLICATION_ERROR procedure. This procedure returns a
non-standard error code and error message because they are user-defined rather than
137
© SQL Star International Ltd.
system defined. Therefore, this procedure returns error messages that are consistent with
other Oracle server errors. The syntax for using RAISE_APPLICATION_ERROR is:
RAISE_APPLICATION_ERROR (error_number, error_message);
Where,
error_number is a number the user specifies for the exception. The number specified
must be between -20000 and –20999.
error_message is a message the user specifies for the exception. It must be a character
string and can be up to 2,048 bytes.
The above code could be rewritten using RAISE_APPLICATION_ERROR as follows:
DECLARE
vAuthorName Book.cAuthorName%TYPE:=’&author’;
vBkName Book.cBookName%TYPE;
BEGIN
SELECT cBookName
INTO vBkName
FROM Book
WHERE cAuthorName=vAuthorName;
EXCEPTION
written by author’||’’||vAuthorName);
author’||vAuthorName);
END;
/
On executing the code, RAISE_APPLICATION_ERROR procedure displays the error
number and message defined within it.
Enter value for author: Shakespeare
138
© SQL Star International Ltd.
ORA-20002: more than one book written by author
Shakespeare
User-defined Exceptions
Predefined exceptions are handled implicitly. However, you might want to handle an
exception explicitly. An exception that is raised and handled explicitly is called user-
defined exception. User-defined exceptions are used to implement business rules that are
not trapped by the server. In case of user-defined exceptions, you need to write code in all
the sections of the block:
Declare the exception in the declarative section. The syntax for declaring an
exception is:
<exception_name> EXCEPTION, where exception_name is the name of the
exception.
In the execution section, write the code for the exception and raise it if the
test conditions are met. The syntax to raise an exception is:
RAISE exception_name, where exception_name is the name of the exception
declared.
In the exception handling section, include the WHEN clause, the name of the
exception and the code to handle it. When the exception is raised, control of
the block is transferred to this section. Include the WHEN OTHERS clause so
that it can catch all those exceptions that do not have a handler within the
code.
The following example shows how to handle exceptions that are not trapped by the
server.
A desk officer enters an invalid author name while updating the number of copies of their
books. While doing this, an exception is raised. To trap this exception, he would first
declare an exception, raise the exception and then handle it.
DECLARE
exInvalidAuthor EXCEPTION;
vAuthorName Book.cAuthorName%TYPE:=’&author’;
BEGIN
UPDATE Book
SET nNoOfCopies=nNoOfCopies+1
WHERE cAuthorName=vAuthorName;
IF SQL%NOTFOUND THEN
RAISE exInvalidAuthor;
END IF;
139
© SQL Star International Ltd.
EXCEPTION
END;
/
On executing the code, if the desk officer enters a name not listed in the Book table, he
would get an error.
The error is handled by declaring a user-defined exception exInvalidAuthor in the
declarative section, which is raised when the embedded query returns no rows.
exInvalidAuthor raised is then handled in the exception section, which displays the
following error message:
vAuthorName Book.cAuthorName%TYPE:=‘&author’;
BEGIN
UPDATE Book
SET nNoOfCopies=nNoOfCopies+1
WHERE cAuthorName=vAuthorName;
IF SQL%NOTFOUND THEN
END IF;
END;
/
On entering an invalid author’s name, you get the following error message:
Enter value for author: Ayn Rand
ORA-20201: the author name you have entered is not a
valid one
140
© SQL Star International Ltd.
Non-predefined Exceptions
You have seen how to handle an exception explicitly. You might want to customize
the predefined exceptions and thus extend the list. These errors are associated with
predefined errors. You can customize the predefined errors by assigning names to
the error number and writing code to handle these exceptions. You can implement
this by using the
PRAGMA EXCEPTION_INIT keyword. This statement is a compiler directive. It
instructs the compiler to associate the exception name given with the Oracle error
number. When you use this statement, you need not raise the exception. You need
to declare it and write exception handling code. Each time an error occurs during
execution, the control is shifted to the exception section and the error is handled.
There are situations where non-predefined exceptions(also known as Internal
Exceptions) need to be handled. For instance, whenever the database users of the
New Jersey Central Library try to delete any member’s details from the Member
table the server displays an error message, indicating an integrity constraint
violation. This is because the foreign key column in the Transaction table is
referencing the cMemberID column of the Member table. But the error message
displayed is not very descriptive. Also, there is no named predefined exception to
handle this. Therefore, the database developer should declare his own exception and
associate it with the Oracle error number for integrity constraint violation.
DECLARE
exMemberIssBks EXCEPTION;
PRAGMA EXCEPTION_INIT(ExMemberIssBks,-2292);
vMemberID Member.cMemberID%TYPE:=‘&memberid’;
BEGIN
COMMIT;
EXCEPTION
END;
141
© SQL Star International Ltd.
In this code, an exception exMemberIssBks is declared and associated with the Oracle
server error number –2292 (integrity constraint violation) using PRAGMA
EXCEPTION_INIT. Any attempt to delete details of a member raises the exception
implicitly. The control is passed to the exception handling section and the following
message is displayed:
142
© SQL Star International Ltd.
Performing Calculation
Cannot divide by zero
PL/SQL procedure successfully completed.
The output gives you a message before handling the error and after handling the
error.
Let us now modify the code a bit. Suppose your requirement is to view the
information about all the oracle defined errors raised during the execution of this
program along with your messages, then this is solved by using
DBMS_UTILITY.FORMAT_ERROR_STACK. This package actually gives you the
information about the errors raised, which are stored in the form of Stack.
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_STACK);
END;
/
Procedure created.
SQL> exec my_proc
Performing Calculation
Cannot divide by zero
ORA-01476: divisor is equal to zero
PL/SQL procedure successfully completed.
Moving further, if you want to know the line number at which an error has occurred,
then you can use DBMS_UTILITY.FORMAT_ERROR_BACKTRACE which is a new
feature in
Oracle10g.
143
© SQL Star International Ltd.
2 IS
3 v_num1 NUMBER:=1;
4 v_num2 NUMBER:=0;
5 v_result NUMBER;
6 BEGIN
7 DBMS_OUTPUT.PUT_LINE(‘calculation’);
8 v_result:= v_num1/v_num2;
9 EXCEPTION
10 WHEN ZERO_DIVIDE THEN
11 DBMS_OUTPUT.PUT_LINE(‘Cannot divide by zero’);
12
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_STACK);
13
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
14* END;
/
Procedure created.
SQL> EXEC my_proc
Performing Calculation
Cannot divide by zero
ORA-01476: divisor is equal to zero
144
© SQL Star International Ltd.