PL/SQL25 min readBy Priyanshu Pandey

PL/SQL Masterclass: Error Handling & Application Logging

Master PL/SQL Exception Handling. Learn how to trap ZERO_DIVIDE, handle NO_DATA_FOUND, define custom PRAGMA EXCEPTION_INIT, and build autonomous logging.

Development Guide · PL/SQL Masterclass

Exception Handling: Bulletproofing Your PL/SQL Code

Don't let a single bad row crash a 5-hour batch job. Learn how to intercept system errors, raise custom business exceptions, and build rock-solid logging mechanisms using Autonomous Transactions.

25 min read📅August 7, 2026✍️Priyanshu Pandey📚PL/SQL Masterclass

The Anatomy of an Exception Block

Every PL/SQL block (BEGIN ... END) can optionally include an EXCEPTION section. If a runtime error occurs, execution immediately jumps to this section, bypassing the rest of the code.

PL/SQL
DECLARE
  v_num NUMBER;
BEGIN
  -- This will trigger a ZERO_DIVIDE error
  v_num := 10 / 0;
  
  -- This line will NEVER execute
  DBMS_OUTPUT.PUT_LINE('Calculation complete'); 
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('An error occurred!');
END;
/

Handling Predefined Exceptions

Oracle provides predefined names for common errors. It is best practice to handle specific errors rather than using a blanket WHEN OTHERS.

PL/SQL
DECLARE
  v_name VARCHAR2(100);
BEGIN
  SELECT first_name INTO v_name FROM employees WHERE emp_id = 999;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('Employee 999 does not exist.');
  WHEN TOO_MANY_ROWS THEN
    DBMS_OUTPUT.PUT_LINE('Data corruption: Multiple employees share ID 999.');
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('Unexpected error: ' || SQLERRM);
END;
/
  • SQLERRM: Returns the actual error message string.
  • SQLCODE: Returns the negative integer error code (e.g., -1403).

Raising User-Defined (Business) Exceptions

Sometimes the data is technically valid, but it violates a business rule. You can create your own exceptions and intentionally trigger them using the RAISE statement.

PL/SQL
DECLARE
  -- 1. Declare the custom exception
  e_insufficient_funds EXCEPTION;
  v_balance NUMBER := 100;
  v_withdrawal NUMBER := 500;
BEGIN
  IF v_withdrawal > v_balance THEN
    -- 2. Trigger it
    RAISE e_insufficient_funds;
  END IF;
EXCEPTION
  -- 3. Catch it
  WHEN e_insufficient_funds THEN
    DBMS_OUTPUT.PUT_LINE('Transaction rejected: Insufficient funds.');
END;
/

Naming ORA Errors (PRAGMA EXCEPTION_INIT)

Not all of Oracle's thousands of ORA- errors have predefined names. For example, ORA-02292: integrity constraint violated (trying to delete a parent with child rows) has no name.

You can bind a custom name to a specific Oracle error code using a compiler directive called PRAGMA EXCEPTION_INIT.

PL/SQL
DECLARE
  e_child_exists EXCEPTION;
  -- Bind our name to ORA-02292
  PRAGMA EXCEPTION_INIT(e_child_exists, -2292); 
BEGIN
  DELETE FROM departments WHERE dept_id = 10;
EXCEPTION
  WHEN e_child_exists THEN
    DBMS_OUTPUT.PUT_LINE('Cannot delete department; it still has employees.');
END;
/
Logging

Building an Autonomous Logger

If an error occurs deep inside a massive batch job, you want to write that error to an ERROR_LOGS table.

The Problem: If the batch job fails and issues a ROLLBACK, it will also rollback your INSERT INTO error_logs statement! Your log disappears.

The Solution: Use PRAGMA AUTONOMOUS_TRANSACTION. This tells Oracle that the logging procedure operates in an independent transaction space. It can commit its logs even if the parent transaction rolls back.

PL/SQL
CREATE OR REPLACE PROCEDURE log_error(p_msg VARCHAR2) IS
  -- Declare this procedure as independent!
  PRAGMA AUTONOMOUS_TRANSACTION; 
BEGIN
  INSERT INTO error_logs (log_date, message) VALUES (SYSDATE, p_msg);
  
  -- This commit ONLY applies to the INSERT above, not the parent!
  COMMIT; 
END;
/

Now, in your main code:

PL/SQL
BEGIN
  -- Attempt a complex update
  UPDATE employees SET salary = salary * 10;
  
  -- Force an error
  RAISE NO_DATA_FOUND;
EXCEPTION
  WHEN OTHERS THEN
    -- Write to the log table (and commit autonomously)
    log_error('Batch failed: ' || SQLERRM);
    
    -- Rollback the massive update
    ROLLBACK; 
END;
/

Common Gotchas

Important Gotchas

  • !

    Never, ever write WHEN OTHERS THEN NULL;. This silently swallows every error in the system. The application will continue running in a corrupted state, and you will never know an error occurred until angry users call you.

  • !

    If you catch an error and log SQLERRM, you only get the error string. You lose the exact line number where the error occurred. For deep debugging, use DBMS_UTILITY.FORMAT_ERROR_BACKTRACE to capture the line number of the original crash.

Key Takeaways

Key Takeaways

  • Handle specific predefined exceptions (NO_DATA_FOUND) before using a generic WHEN OTHERS block.
  • Define business-rule exceptions using RAISE, or map them to Oracle errors using PRAGMA EXCEPTION_INIT.
  • Always use PRAGMA AUTONOMOUS_TRANSACTION for your logging procedures so error logs survive a rollback.
RetailCoder
All systems operational
v1.0 Live

RC:OMS

Multi-channel order management with double-entry inventory ledger. Amazon, Flipkart, Shopify, WooCommerce — one source of truth.

Launch demo →
v1.0 Live

RC:Storefront

Self-hosted headless e-commerce. Your server, your data, zero transaction fees. Native RC:OMS inventory sync.

Visit Storefront →
Pipeline

RC:Pulse

AI-powered retail analytics and demand forecasting — built natively on top of your RC:OMS and Storefront data.

Request early access →
Built in India 🇮🇳  ·  Architected by Priyanshu PandeyTalk to an engineer →