PL/SQL Exceptions  «Prev  Next»

Lesson 7 Functions and procedures for exception handling
Objective Describe the use of functions and procedures within error handling.

Functions and Procedures for Error Handling in PL/SQL

In Oracle 23ai, exception handling is still built around the same PL/SQL fundamentals: you trap exceptions in an EXCEPTION section, use functions such as SQLCODE and SQLERRM to capture diagnostic details, and use procedures (most commonly RAISE_APPLICATION_ERROR) to return meaningful errors to the caller.

The key best practice is to treat error handling as a design feature. Your PL/SQL blocks should: 1) detect expected business-rule errors early, 2) raise clear application errors for those conditions, and 3) record enough diagnostics for unexpected failures without exposing internal details to end users.

Functions used inside exception handlers

When an exception occurs, PL/SQL provides built-in functions that you can call inside the exception handler to learn what went wrong. The two most common are SQLCODE and SQLERRM.
Function Description
SQLCODE Returns the numeric error code for the exception currently being handled. Typical values include:
  • 0 — no exception encountered
  • 100NO_DATA_FOUND
  • < 0 — Oracle error number (for example, -1 for unique constraint violations)
  • 1 — user-defined exception (raised with RAISE)
SQLERRM Returns the error message text for the exception currently being handled. You can call SQLERRM with no arguments for the current error, or pass an error number if needed.

Example: capture error code and message

The block below shows a modern, readable pattern: capture the error details, roll back the unit of work, and print (or log) the diagnostics. In a production application, you would typically log diagnostics to a table (or a centralized logging system) rather than relying on DBMS_OUTPUT.


DECLARE
  v_error_code    PLS_INTEGER;
  v_error_message VARCHAR2(4000);
BEGIN
  DELETE FROM product
  WHERE product_id = 22;

  COMMIT;

EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK;

    v_error_code    := SQLCODE;
    v_error_message := SQLERRM;

    DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || v_error_code);
    DBMS_OUTPUT.PUT_LINE('SQLERRM : ' || v_error_message);

    -- In a real application, consider re-raising or returning a controlled error.
END;

Procedures used for controlled error reporting

The most important procedure for application-grade error handling is RAISE_APPLICATION_ERROR. It lets you raise a custom error number and message that your calling layer (APEX, JDBC, OCI, ORDS, etc.) can reliably interpret.

RAISE_APPLICATION_ERROR

RAISE_APPLICATION_ERROR (error_number, message [, add_to_stack]);

DECLARE
  l_pet_id  NUMBER := 42;
  l_count   PLS_INTEGER;
BEGIN
  SELECT COUNT(*)
  INTO   l_count
  FROM   pets
  WHERE  pet_id = l_pet_id;

  IF l_count = 0 THEN
    RAISE_APPLICATION_ERROR(-20001, 'Pet is not in the database.');
  END IF;
END;
  1. Error Number (error_number)
    • A user-defined error number in the range -20000 to -20999.
    • Use a consistent numbering scheme so your application can map errors to user-friendly guidance.
  2. Error Message (message)
    • A concise message describing the business condition or failure.
    • Avoid exposing internal object names or sensitive details to end users.
  3. Add-to-Stack Flag (add_to_stack)
    • Optional boolean. When TRUE, the error is added to the stack (preserves the prior error context).
    • When FALSE (default), this error replaces the prior stack top message.

Putting it together: a robust PL/SQL block with expected and unexpected errors

The scenario below illustrates a practical pattern in Oracle 23ai:
  • Use normal SQL logic for the “happy path.”
  • Use explicit checks for business rules (for example, price must be greater than zero).
  • Use named exceptions and RAISE_APPLICATION_ERROR for clear, controlled outcomes.
  • Use WHEN OTHERS to catch unexpected errors, log details, and re-raise a controlled error.

Example: validate input, compute totals, and handle exceptions


DECLARE
  -- Inputs (in real apps these come from parameters)
  l_product_id  product.product_id%TYPE := 101;

  -- Data
  l_base_price  product.base_price%TYPE;
  l_total_price NUMBER;

  -- Business-rule exception
  e_invalid_price EXCEPTION;
BEGIN
  -- Look up price (NO_DATA_FOUND will be raised automatically if missing)
  SELECT base_price
  INTO   l_base_price
  FROM   product
  WHERE  product_id = l_product_id;

  -- Business rule
  IF l_base_price <= 0 THEN
    RAISE e_invalid_price;
  END IF;

  -- Example computation (replace with your own business logic)
  l_total_price := l_base_price
                   + (l_base_price * 0.05)     -- tax
                   + (l_base_price * 0.001);   -- shipping/handling (0.10%)

  DBMS_OUTPUT.PUT_LINE('Total price: ' || TO_CHAR(l_total_price));

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    -- Controlled, user-facing error
    RAISE_APPLICATION_ERROR(-20001, 'Product ID does not exist.');

  WHEN e_invalid_price THEN
    RAISE_APPLICATION_ERROR(-20002, 'Product price is invalid (must be greater than zero).');

  WHEN OTHERS THEN
    -- Capture diagnostics for troubleshooting (log in real systems)
    DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
    DBMS_OUTPUT.PUT_LINE('SQLERRM : ' || SQLERRM);

    -- Return a controlled error to the application layer
    RAISE_APPLICATION_ERROR(-20099, 'Unexpected error while processing the order.');
END;

Operational guidance for Oracle 23ai

The next lesson concludes this module.


SEMrush Software 7 SEMrush Banner 7