PL/SQL by Example / Exceptions
As already indicated in the introduction, the part of the block introduced by the keyword EXCEPTION is used for catching program runtime errors. We distinguish between system errors, which are raised automatically when an error occurs, and user-defined errors, which must be raised explicitly using the RAISE command. The following examples describe several of the most common system errors.
System
VALUE_ERROR
DECLARE
l_Number NUMBER;
BEGIN
l_Number:='Francis';
EXCEPTION
WHEN VALUE_ERROR THEN
dbms_output.put_line('Implicit conversion failed!');
END;
ZERO_DIVIDE
DECLARE
l_Number NUMBER;
BEGIN
l_Number:=20/0;
EXCEPTION
WHEN ZERO_DIVIDE THEN
dbms_output.put_line('Division by zero!');
END;
NO_DATA_FOUND
DECLARE
l_Number NUMBER;
BEGIN
SELECT employee_id
INTO l_Number
FROM employees
WHERE (last_name='Sauce')
;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('Employee Sauce does not exist!');
END;
TOO_MANY_ROWS
DECLARE
l_Number NUMBER;
BEGIN
SELECT employee_id
INTO l_Number
FROM employees
WHERE (salary>3000)
;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
dbms_output.put_line('More than one row!');
END;
COLLECTION_IS_NULL
CREATE OR REPLACE TYPE Varchar_TT IS TABLE OF VARCHAR2(4000); /
DECLARE
lt_Array Varchar_TT;
BEGIN
--lt_Array:=Varchar_TT();
--lt_Array.EXTEND(1);
lt_Array(1):='test';
EXCEPTION
WHEN COLLECTION_IS_NULL THEN
dbms_output.put_line('Uninitialized object!');
END;
SUBSCRIPT_BEYOND_COUNT
DECLARE
lt_Array Varchar_TT;
l_Cnt NUMBER;
BEGIN
lt_Array:=Varchar_TT();
lt_Array.EXTEND(1);
lt_Array(2):='test';
EXCEPTION
WHEN SUBSCRIPT_BEYOND_COUNT THEN
dbms_output.put_line('Array index out of bounds!');
END;
OTHERS
It is possible to catch multiple types of errors in one block, however, if an error does not have its own handler, the program will terminate with the general exception OTHERS. The error message is returned by the SQLERRM function.
DECLARE
lt_Array Varchar_TT;
BEGIN
lt_Array:=Varchar_TT();
lt_Array.EXTEND(1);
lt_Array(2):='test';
EXCEPTION
WHEN COLLECTION_IS_NULL THEN
dbms_output.put_line('Uninitialized object!');
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM); -- ORA-06533: Subscript beyond count
END;
In situations where we know in advance that an operation will be potentially dangerous, it is good practice to prevent errors rather than just catch them. In very large systems, this simplifies subsequent problem finding.
DECLARE
l_DangerousNumber NUMBER:=0;
l_Count PLS_INTEGER;
l_Result NUMBER;
BEGIN
-- handling NO_DATA_FOUND and TOO_MANY_ROWS
SELECT COUNT(1)
INTO l_Count
FROM employees
WHERE (last_name='Russell')
;
IF (l_Count>0)
AND (l_Count<2)
THEN
-- exactly one exists
SELECT CASE -- handling ZERO_DIVIDE and NULL values
WHEN (NVL(l_DangerousNumber, 0)=0)
THEN 0
ELSE (salary/l_DangerousNumber)
END
INTO l_Result
FROM employees
WHERE (last_name='Russell')
;
dbms_output.put_line(l_Result);
ELSE
-- does not exist or there are more
dbms_output.put_line('Number of employees: '||l_Count);
END IF;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Unknown error!');
END;
User-defined
If the predefined Oracle exceptions are not sufficient for us, the next step is to define our own in the declarative part of an anonymous block or package. The RAISE command is used to raise a user-defined exception.
DECLARE
MY_EXCEPTION EXCEPTION;
BEGIN
-- potentially
-- dangerous
-- operations
RAISE MY_EXCEPTION;
EXCEPTION
WHEN MY_EXCEPTION THEN
dbms_output.put_line('My exception');
END;
Exception Propagation
The next example explains the system of catching and propagating exceptions through several levels of code blocks. In this case, the exceptions are declared in a separate package.
CREATE OR REPLACE PACKAGE ExceptionsPackage AS OUTER_EXCEPTION EXCEPTION; INNER_EXCEPTION EXCEPTION; END; /
BEGIN
/* START OF INNER BLOCK */
BEGIN
-- potentially
-- dangerous
-- operations
RAISE ExceptionsPackage.INNER_EXCEPTION;
EXCEPTION
WHEN ExceptionsPackage.INNER_EXCEPTION THEN
dbms_output.put_line('Inner exception');
END;
/* END OF INNER BLOCK */
-- inner exception was caught, continuing
-- another
-- dangerous
-- operation
RAISE ExceptionsPackage.OUTER_EXCEPTION;
EXCEPTION
-- OUTER_EXCEPTION has no handler, program ends in the general one
WHEN OTHERS THEN
dbms_output.put_line('Another unexpected error');
END;