Advertisement Space
Handling errors gracefully in PL/SQL
Every production-quality PL/SQL program needs proper error handling. Oracle provides a rich exception handling framework that lets you catch errors, log them, and recover gracefully. Knowing the difference between predefined exceptions, user-defined exceptions, and the OTHERS handler is essential.
Recipe #1 - Catching predefined exceptions
Oracle provides named exceptions for common errors. The most frequently used ones are NO_DATA_FOUND and TOO_MANY_ROWS:
DECLARE
v_name VARCHAR2(100);
BEGIN
SELECT ename INTO v_name
FROM emp
WHERE empno = 9999;
DBMS_OUTPUT.put_line('Employee: ' || v_name);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.put_line('No employee found with that ID.');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.put_line('Multiple employees found — query is ambiguous.');
END;
Recipe #2 - User-defined exceptions
You can declare your own exceptions for business logic validation:
DECLARE
e_salary_too_high EXCEPTION;
v_salary NUMBER;
BEGIN
SELECT sal INTO v_salary FROM emp WHERE empno = 7839;
IF v_salary > 50000 THEN
RAISE e_salary_too_high;
END IF;
EXCEPTION
WHEN e_salary_too_high THEN
DBMS_OUTPUT.put_line('Salary exceeds the allowed maximum.');
END;
Recipe #3 - Using SQLCODE and SQLERRM
When you catch exceptions with the OTHERS handler, use SQLCODE and SQLERRM to get details about what went wrong:
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE nonexistent_table';
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line('Error code: ' || SQLCODE);
DBMS_OUTPUT.put_line('Error message: ' || SQLERRM);
END;
Recipe #4 - RAISE_APPLICATION_ERROR for custom error codes
Use RAISE_APPLICATION_ERROR to send meaningful error messages back to the calling application. Error numbers must be between -20000 and -20999:
CREATE OR REPLACE PROCEDURE withdraw(
p_account_id NUMBER,
p_amount NUMBER
) AS
v_balance NUMBER;
BEGIN
SELECT balance INTO v_balance
FROM accounts
WHERE account_id = p_account_id;
IF p_amount > v_balance THEN
RAISE_APPLICATION_ERROR(-20001,
'Insufficient funds. Balance: ' || v_balance
|| ', requested: ' || p_amount);
END IF;
UPDATE accounts
SET balance = balance - p_amount
WHERE account_id = p_account_id;
END;