Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

PL/SQL & T-SQL (Oracle and SQL Server)  Module 11 – Subprograms, packages and robust error logging

Error logging, backtraces and autonomous logs

Record where a PL/SQL error happened with SQLERRM, backtraces and the call stack, and see how autonomous logs outlive a rollback.

  • Intermediate
  • 15 minutes
  • Examples run with oracle-free 23.26.3.0.0, mssql 17.0.5005.3, Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 5 of 15 minutes free
Free: The message says what failed, the backtrace says where · Numbered frames start at the origin · A log row written in the failing transaction rolls back with it. With a pass: 2 in-depth parts and 3 interview answers, about 10 minutes.

What you will learn

  • Record where an error happened with FORMAT_ERROR_BACKTRACE and UTL_CALL_STACK
  • Write a logging package whose entries survive a rollback
  • Avoid autonomous-transaction pitfalls, missing commits and self-deadlocks
  • Build log records that keep personal data out

Before you start

What you’ll learn · Before you start

What you will learn

  • Record where an error happened with FORMAT_ERROR_BACKTRACE and UTL_CALL_STACK
  • Write a logging package whose entries survive a rollback
  • Avoid autonomous-transaction pitfalls, missing commits and self-deadlocks
  • Build log records that keep personal data out

Before you start

On this page

Account 3 holds 760.25, and a month-end fee of 1000.00 stops the run with ORA-02290, three procedures deep. The message names the broken rule but not the place, and a log row written before the rollback disappears with the rollback.

Error logging answers both problems. SQLERRM gives the message, DBMS_UTILITY.FORMAT_ERROR_BACKTRACE gives the chain of line numbers from the failing statement up to the handler, and UTL_CALL_STACK numbers the same frames. A logger that runs as an autonomous transaction: A transaction of its own that a routine marked PRAGMA AUTONOMOUS_TRANSACTION runs while the main transaction waits; its COMMIT keeps its changes whatever the caller does afterwards. commits its own row, so the row stays when the caller rolls back. You will read a backtrace, name its origin and say what a safe log row holds.

The message says what failed, the backtrace says where

In the fee run of backtrace_demo.sql, close_month calls settle_account, which calls charge_fee, and charge_fee runs an UPDATE that would take account 3 below zero. The check constraint refuses it with ORA-02290.

SQLERRM returns the message of that error, ORA-02290: check constraint (LAB.ACCOUNTS_BALANCE_CK) violated, and says nothing about where it happened. It returns at most 512 bytes, so Oracle recommends DBMS_UTILITY.FORMAT_ERROR_STACK, which returns the whole error stack: The messages of an error and of the errors it caused. DBMS_UTILITY.FORMAT_ERROR_STACK returns them as text of up to 2000 bytes, where SQLERRM returns at most 512 bytes. up to 2000 bytes. The place comes from FORMAT_ERROR_BACKTRACE: The DBMS_UTILITY function that, inside a handler, returns one ORA-06512 line for each frame, from the statement that failed to the unit holding the handler; it returns NULL when no error is being handled.: one ORA-06512 line for each frame, from the statement that failed up to the unit that holds the handler. Backtraces are for reading inside a handler, because the function returns NULL when no error is being handled. Step the error up through the three units:

Interactive · step by step One error and the three frames of its backtrace Step from the failing UPDATE up to the unit that holds the handler, and watch each unit add a frame.
One error and the three frames of its backtrace, step 4 of 4. Showing close_month, settle_account, charge_fee, line 7: the call (index 3), line 6: the call (index 2), line 4: UPDATE (origin: index 1). In focus: line 4: UPDATE, line 6: the call, line 7: the call.error passes uperror passes upclose_monthholds the handlersettle_accountcharge_feeline 7: the callindex 3line 6: the callindex 2line 4: UPDATEorigin: index 1index 1 is here

The drawing shows the whole scene; its 4 steps are listed below.

Every step as text
  1. The UPDATE breaks a rule. charge_fee runs its UPDATE, on line 4, for account 3, which holds 760.25. A fee of 1000.00 would take the balance below 0 and break accounts_balance_ck, so Oracle raises ORA-02290. charge_fee has no handler.
  2. Up to settle_account. Without a handler the error leaves charge_fee and arrives in settle_account at the statement that called it, on line 6. That line becomes a second frame of the backtrace.
  3. Up again to close_month. settle_account has no handler either, so the error arrives in close_month at its call on line 7. close_month has a handler, so the error stops climbing here, and line 7 is the third frame, the one nearest the handler.
  4. The handler reads the chain. FORMAT_ERROR_BACKTRACE returns one ORA-06512 line for each frame, origin first - CHARGE_FEE line 4, SETTLE_ACCOUNT line 6, CLOSE_MONTH line 7. UTL_CALL_STACK numbers the frames in the same order, index 1 for CHARGE_FEE and index 3, the depth, for CLOSE_MONTH. SQLERRM holds only the message.

The script runs both fee calls and prints what the handler in close_month sees. The Python model beside it finds each line number by searching the text of the three procedures, so the numbers cannot drift from the code:

backtrace_demo.sql: three nested procedures and what the handler prints SQL · backtrace/backtrace_demo.sql
-- Engine: Oracle AI Database 26ai Free, Release 23.26.3.0.0; user LAB in FREEPDB1. Client: SQL*Plus or SQLcl.
-- Three nested procedures: close_month calls settle_account, which calls charge_fee, and charge_fee breaks
-- accounts_balance_ck. The handler in close_month prints SQLERRM, the backtrace and the numbered frames of
-- UTL_CALL_STACK. Run schema_oracle.sql of practice-schema-and-dialect-basics first; examples/model/backtrace_model.py
-- derives the same line numbers from this source. The script rolls back its change and drops its procedures.
SET SERVEROUTPUT ON
SET LINESIZE 200

CREATE OR REPLACE PROCEDURE charge_fee (p_account_id IN NUMBER, p_fee IN NUMBER)
  AUTHID DEFINER IS
BEGIN
  UPDATE accounts SET balance = balance - p_fee WHERE account_id = p_account_id;
END charge_fee;
/

CREATE OR REPLACE PROCEDURE settle_account (p_account_id IN NUMBER, p_fee IN NUMBER)
  AUTHID DEFINER IS
  v_label CONSTANT VARCHAR2(20) := 'month-end fee';
BEGIN
  DBMS_OUTPUT.PUT_LINE('settling ' || v_label);
  charge_fee(p_account_id, p_fee);
END settle_account;
/

CREATE OR REPLACE PROCEDURE close_month (p_account_id IN NUMBER, p_fee IN NUMBER)
  AUTHID DEFINER IS
  v_run CONSTANT VARCHAR2(20) := 'month-end fee run';
BEGIN
  DBMS_OUTPUT.PUT_LINE('closing account ' || p_account_id || ' for ' || v_run);
  -- the fee run starts here
  settle_account(p_account_id, p_fee);
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
    DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    FOR i IN 1 .. UTL_CALL_STACK.BACKTRACE_DEPTH LOOP
      DBMS_OUTPUT.PUT_LINE(i || ' ' || UTL_CALL_STACK.BACKTRACE_UNIT(i) || ' line ' || UTL_CALL_STACK.BACKTRACE_LINE(i));
    END LOOP;
END close_month;
/
-- Expected: the three procedures are created, and each unit's line 1 is the line that holds PROCEDURE (the CREATE OR
-- REPLACE words count as part of it). The statement that fails is on line 4 of charge_fee, the call to charge_fee on
-- line 6 of settle_account and the call to settle_account on line 7 of close_month.

BEGIN
  close_month(3, 10.00);                    -- 760.25 - 10.00 = 750.25: no error, so the handler never runs
  close_month(3, 1000.00);                  -- 760.25 - 1000.00 breaks accounts_balance_ck (ORA-02290)
END;
/
-- Expected:
--   closing account 3 for month-end fee run
--   settling month-end fee
--   closing account 3 for month-end fee run
--   settling month-end fee
--   SQLERRM: ORA-02290: check constraint (LAB.ACCOUNTS_BALANCE_CK) violated
--   ORA-06512: at "LAB.CHARGE_FEE", line 4
--   ORA-06512: at "LAB.SETTLE_ACCOUNT", line 6
--   ORA-06512: at "LAB.CLOSE_MONTH", line 7
--   1 LAB.CHARGE_FEE line 4
--   2 LAB.SETTLE_ACCOUNT line 6
--   3 LAB.CLOSE_MONTH line 7
-- The backtrace text and UTL_CALL_STACK both start at the origin: index 1 is the failing UPDATE, and index
-- BACKTRACE_DEPTH, 3 here, the call in the unit that examines the backtrace. BACKTRACE_UNIT names each unit with its
-- owner.

ROLLBACK;
DROP PROCEDURE close_month;
DROP PROCEDURE settle_account;
DROP PROCEDURE charge_fee;
backtrace_demo.sql, run in the lab Python · backtrace_demo_session.py
"""backtrace_demo.sql in the lab: SQL*Plus runs it as LAB on a freshly loaded practice schema."""

from oracle_session import Lab

with Lab() as lab:
    lab.sqlplus("backtrace/backtrace_demo.sql")

Output

$ sqlplus -s lab@//localhost/FREEPDB1 @backtrace/backtrace_demo.sql
Procedure created.


Procedure created.


Procedure created.

closing account 3 for month-end fee run
settling month-end fee
closing account 3 for month-end fee run
settling month-end fee
SQLERRM: ORA-02290: check constraint (LAB.ACCOUNTS_BALANCE_CK) violated
ORA-06512: at "LAB.CHARGE_FEE", line 4
ORA-06512: at "LAB.SETTLE_ACCOUNT", line 6
ORA-06512: at "LAB.CLOSE_MONTH", line 7


1 LAB.CHARGE_FEE line 4
2 LAB.SETTLE_ACCOUNT line 6
3 LAB.CLOSE_MONTH line 7

PL/SQL procedure successfully completed.


Rollback complete.


Procedure dropped.


Procedure dropped.


Procedure dropped.

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 backtrace_demo_session.py

Frames, lines and depths of the three procedures, modelled Python · model/backtrace_model.py
"""Where an error happened: the backtrace of three nested procedures, modelled.

The model holds the text of the three procedures of backtrace_demo.sql. It finds
the line of each statement by searching the text, as Oracle counts it (line 1 is
the line that holds PROCEDURE), and prints what the documented functions return
when charge_fee breaks accounts_balance_ck:

1. DBMS_UTILITY.FORMAT_ERROR_BACKTRACE lists one ORA-06512 line per frame, from
   the statement that failed to the line of the unit that holds the handler.
2. UTL_CALL_STACK numbers the same frames in the same order: BACKTRACE_LINE(1)
   is the origin, the line on which the error was raised, and
   BACKTRACE_LINE(BACKTRACE_DEPTH) is the call in the unit that examines the
   backtrace. BACKTRACE_UNIT names each unit with its owner. The depth is 0 with
   no error.

Edit HANDLERS to move the handler to another unit, or insert a line into a
procedure and watch the numbers follow.
"""

UPDATE = "UPDATE accounts SET balance = balance - p_fee "
SOURCE = {
    "CHARGE_FEE": [
        "PROCEDURE charge_fee (p_account_id IN NUMBER, p_fee IN NUMBER)",
        "  AUTHID DEFINER IS",
        "BEGIN",
        "  " + UPDATE + "WHERE account_id = p_account_id;",
        "END charge_fee;",
    ],
    "SETTLE_ACCOUNT": [
        "PROCEDURE settle_account (p_account_id IN NUMBER, p_fee IN NUMBER)",
        "  AUTHID DEFINER IS",
        "  v_label CONSTANT VARCHAR2(20) := 'month-end fee';",
        "BEGIN",
        "  DBMS_OUTPUT.PUT_LINE('settling ' || v_label);",
        "  charge_fee(p_account_id, p_fee);",
        "END settle_account;",
    ],
    "CLOSE_MONTH": [
        "PROCEDURE close_month (p_account_id IN NUMBER, p_fee IN NUMBER)",
        "  AUTHID DEFINER IS",
        "  v_run CONSTANT VARCHAR2(20) := 'month-end fee run';",
        "BEGIN",
        "  DBMS_OUTPUT.PUT_LINE('closing account ' || p_account_id);",
        "  -- the fee run starts here",
        "  settle_account(p_account_id, p_fee);",
        "EXCEPTION",
        "  WHEN OTHERS THEN",
        "    DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);",
        "END close_month;",
    ],
}
CALL_CHAIN = ["CLOSE_MONTH", "SETTLE_ACCOUNT", "CHARGE_FEE"]  # outermost first
ERROR = "ORA-02290: check constraint (LAB.ACCOUNTS_BALANCE_CK) violated"
HANDLERS = ["CLOSE_MONTH", "SETTLE_ACCOUNT"]  # one case per handler


def line_of(unit, start):
    """Number of the first line of the unit that starts with the text."""
    for number, text in enumerate(SOURCE[unit], start=1):
        if text.strip().startswith(start):
            return number
    raise ValueError(f"{start!r} not found in {unit}")


def statement_line(unit):
    """Line of the statement that raises, or that calls the next unit."""
    if unit == CALL_CHAIN[-1]:
        return line_of(unit, "UPDATE accounts"), "UPDATE"
    callee = CALL_CHAIN[CALL_CHAIN.index(unit) + 1].lower()
    return line_of(unit, callee + "("), "call to " + callee


def frames(handler):
    """Backtrace frames, origin first, ending with the handler's own unit."""
    inner = CALL_CHAIN[CALL_CHAIN.index(handler):]
    return [(unit, statement_line(unit)[0]) for unit in reversed(inner)]


print("Lines found by searching the source of each unit")
for unit in CALL_CHAIN:
    line, what = statement_line(unit)
    print(f"  {unit:<15}{what} at line {line}")

for handler in HANDLERS:
    stack = frames(handler)
    print(f"\nHandler in {handler}")
    print(f"  SQLERRM: {ERROR}")
    print("  FORMAT_ERROR_BACKTRACE:")
    for unit, line in stack:
        print(f'    ORA-06512: at "LAB.{unit}", line {line}')
    print(f"  UTL_CALL_STACK.BACKTRACE_DEPTH = {len(stack)}")
    for index, (unit, line) in enumerate(stack, start=1):  # index 1 is the origin
        mark = ""
        if index == 1:
            mark += "  <- origin"
        if index == len(stack):
            mark += "  <- the handler's unit"
        print(f"    {index} LAB.{unit} line {line}{mark}")

print("\nNo error being handled")
print("  FORMAT_ERROR_BACKTRACE = NULL")
print("  UTL_CALL_STACK.BACKTRACE_DEPTH = 0")

Output

Lines found by searching the source of each unit
  CLOSE_MONTH    call to settle_account at line 7
  SETTLE_ACCOUNT call to charge_fee at line 6
  CHARGE_FEE     UPDATE at line 4

Handler in CLOSE_MONTH
  SQLERRM: ORA-02290: check constraint (LAB.ACCOUNTS_BALANCE_CK) violated
  FORMAT_ERROR_BACKTRACE:
    ORA-06512: at "LAB.CHARGE_FEE", line 4
    ORA-06512: at "LAB.SETTLE_ACCOUNT", line 6
    ORA-06512: at "LAB.CLOSE_MONTH", line 7
  UTL_CALL_STACK.BACKTRACE_DEPTH = 3
    1 LAB.CHARGE_FEE line 4  <- origin
    2 LAB.SETTLE_ACCOUNT line 6
    3 LAB.CLOSE_MONTH line 7  <- the handler's unit

Handler in SETTLE_ACCOUNT
  SQLERRM: ORA-02290: check constraint (LAB.ACCOUNTS_BALANCE_CK) violated
  FORMAT_ERROR_BACKTRACE:
    ORA-06512: at "LAB.CHARGE_FEE", line 4
    ORA-06512: at "LAB.SETTLE_ACCOUNT", line 6
  UTL_CALL_STACK.BACKTRACE_DEPTH = 2
    1 LAB.CHARGE_FEE line 4  <- origin
    2 LAB.SETTLE_ACCOUNT line 6  <- the handler's unit

No error being handled
  FORMAT_ERROR_BACKTRACE = NULL
  UTL_CALL_STACK.BACKTRACE_DEPTH = 0

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 backtrace_model.py

Move the origin by one line

Press Edit and add the string " -- fee check", after "BEGIN", in the CHARGE_FEE list, then run it again: the origin becomes line 5 of CHARGE_FEE, and the other two frames stay at lines 6 and 7.

Checkpoint

Check: The message and the backtrace

  1. Question 1 of 2 A handler needs the unit and the line number of the statement that failed. Which call returns them?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: DBMS_UTILITY.FORMAT_ERROR_BACKTRACE

    The message says which rule broke and the backtrace says where. A log row needs both, and the number from SQLCODE is only a short way to name the first.

  2. Question 2 of 2 In the model, a comment line is added right after BEGIN in charge_fee, so the UPDATE moves down one line. Which line does the origin frame report now?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Line 5 of CHARGE_FEE

    The origin is the frame of the statement that raised the error, so it moves when the lines above that statement change. The other two frames are calls in other units and stay at lines 6 and 7.

Numbered frames start at the origin

UTL_CALL_STACK: The PL/SQL package that returns the frames of a backtrace or of the call stack as numbers and names, such as BACKTRACE_DEPTH, BACKTRACE_UNIT and BACKTRACE_LINE, instead of one formatted text. gives backtraces as numbers instead of text. UTL_CALL_STACK.BACKTRACE_DEPTH counts the frames, and BACKTRACE_UNIT(i) and BACKTRACE_LINE(i) return the unit and the line of frame i. The numbers start at the origin: index 1 is the unit where the error was raised, and the highest index, backtrace depth: The number of frames in a backtrace, returned by UTL_CALL_STACK.BACKTRACE_DEPTH. Index 1 is the origin of the error, the highest index is the unit that examines the backtrace, and the depth is 0 when no error is being handled., is the unit that examines the backtrace. So BACKTRACE_LINE(1) is the line that raised the error, and BACKTRACE_LINE(BACKTRACE_DEPTH) the call in the handler’s unit. The handler in close_month prints, and the model with it:

Index Unit Line What the frame is
1 LAB.CHARGE_FEE 4 the origin, the failing UPDATE
2 LAB.SETTLE_ACCOUNT 6 the call to charge_fee
3 LAB.CLOSE_MONTH 7 the call in the unit with the handler

That is the order of the FORMAT_ERROR_BACKTRACE text, and BACKTRACE_UNIT names each unit with its owner. With the handler in settle_account the same error has two frames, CHARGE_FEE at index 1 and SETTLE_ACCOUNT at index 2, because a backtrace ends where it is examined. With no error being handled the depth is 0. The call stack also counts from the innermost frame: its dynamic depth 1 is the subprogram running now.

Checkpoint

Check: Numbered frames, origin first

  1. Question 1 of 2 A handler in close_month wants the line on which the error was raised. Which call returns it?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: UTL_CALL_STACK.BACKTRACE_LINE(1)

    The numbers start at the origin: index 1 is charge_fee, where the UPDATE failed, index 2 settle_account and index 3, the depth, close_month, which holds the handler. The FORMAT_ERROR_BACKTRACE text runs the same way.

  2. Question 2 of 2 The same error is caught by a handler in settle_account instead of close_month. What are BACKTRACE_DEPTH and the unit at index 2?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Depth 2, and index 2 is SETTLE_ACCOUNT

    A handler lower in the chain sees a shorter backtrace. The depth counts the frames from the origin up to the handler's own unit, here two, and the origin keeps index 1.

A log row written in the failing transaction rolls back with it

Suppose the handler inserts a log row into the table app_log and the caller then rolls back. The row was part of the caller’s transaction, so the rollback removes it together with the fee, and the failure leaves no trace. Good error logging writes the row where a rollback cannot reach it. The table sets the two places side by side:

Where the row is written After the caller’s ROLLBACK
In the caller’s transaction gone, with everything else the caller changed
In an autonomous transaction kept, because it committed on its own

Autonomous logs take the second route. PRAGMA AUTONOMOUS_TRANSACTION gives the logger a transaction of its own, so its COMMIT keeps its row whatever the caller does later. Two pitfalls come with autonomous logs. A routine that returns without COMMIT or ROLLBACK raises ORA-06519, and one that updates a row its caller has locked deadlocks with the caller and raises ORA-00060. Safe log design decides what a row may hold: the error stack, the backtrace, the module and a correlation id, and never full account numbers, phone numbers or names. SQL Server has the same problem, treated under doomed transactions, and the logger is a package, as in the lesson on packages.

Checkpoint

Check: A log row that a rollback removes

  1. One question A handler inserts a log row in the same transaction as the failed work, and the caller then rolls back. What is left in the log table?

    Choose one answer.

    Show the answer: One question

    Answer: Nothing, because the row was part of the transaction that rolled back

    A log row has to be written in a transaction that the caller's rollback does not own, which is what an autonomous transaction gives it.

A logger whose rows survive a caller rollback Pro: opens with a Pro, Premium or Ultimate pass

A logger that commits in a transaction of its own keeps its row when the caller rolls back. It pays for that with a blind spot and two traps, and all three are reproduced below on account 3.

In this part:

  • Writing a logger that commits its own row
  • What the logger can see while the fee is pending
  • Two pitfalls reproduced: ORA-06519 and ORA-00060

1 diagram · 5 runnable examples (Python, SQL) · about 8 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Backtraces that pinpoint the failing line, safely Pro: opens with a Pro, Premium or Ultimate pass

A log row is only as useful as the place it names and only as safe as the data it holds. The position of the handler, the fields of the row and the width of its columns decide both.

In this part:

  • Where the handler sits decides how many frames you see
  • Choosing what a log row keeps and what it leaves out
  • Storing the whole error stack in a column that fits it

3 runnable examples (Python, SQL) · about 12 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Practise: place the error, then place the log row

Each question gives a failing call chain or a log design. Name the frame or the transaction first, then choose:

Practice that adapts to you

Practise this lesson

7 questions about 9 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 7 Which call returns the text of the error being handled, limited to 512 bytes?

    Choose one answer.

    Show the answer: Question 1 of 7

    Answer: SQLERRM

    SQLERRM is the short message; the stack function is the better source when the whole text matters.

  2. Question 2 of 7 A helper procedure calls DBMS_UTILITY.FORMAT_ERROR_BACKTRACE after the handler that caught the error has ended. What does the function return?

    Choose one answer.

    Show the answer: Question 2 of 7

    Answer: NULL, because no error is being handled

    Read the backtrace inside the handler and pass the text on, because the function has nothing to report once the handler is over.

  3. Question 3 of 7 A backtrace has three ORA-06512 lines, for LAB.CHARGE_FEE line 4, LAB.SETTLE_ACCOUNT line 6 and LAB.CLOSE_MONTH line 7. Which line holds the statement that raised the error?

    Choose one answer.

    Show the answer: Question 3 of 7

    Answer: LAB.CHARGE_FEE line 4, the first line

    Read the first line for the cause and the rest for the route the error took to the handler.

  4. Question 4 of 7 What does UTL_CALL_STACK.BACKTRACE_DEPTH return when no exception is being handled?

    Choose one answer.

    Show the answer: Question 4 of 7

    Answer: 0

    A loop from 1 to BACKTRACE_DEPTH therefore does nothing outside a handler, instead of failing.

  5. Question 5 of 7 Which statement about UTL_CALL_STACK depths is correct?

    Choose one answer.

    Show the answer: Question 5 of 7

    Answer: Dynamic depth 1 is the subprogram running now, and backtrace index 1 is where the error began

    Use the dynamic depth to report the call stack of running code, and BACKTRACE_LINE(1) to report the line where an error began.

  6. Question 6 of 7 Where does a log row have to be written to remain after the caller's ROLLBACK?

    Choose one answer.

    Show the answer: Question 6 of 7

    Answer: In a transaction of its own, which commits

    The caller decides about its own transaction, so the log row must belong to a transaction that it does not own.

  7. Question 7 of 7 A handler writes its log row as its very last statement, after the error was handled. Does that position let the row survive the caller's later ROLLBACK?

    Choose one answer.

    Show the answer: Question 7 of 7

    Answer: No, any uncommitted row of the caller's transaction is removed by the rollback

    A log row survives only if it is committed in a transaction of its own; the order of statements in the handler cannot do that.

Interview questions

Warm-up (fresher): how do SQLERRM and FORMAT_ERROR_BACKTRACE differ?

SQLERRM returns the text of the error being handled, up to 512 bytes. DBMS_UTILITY.FORMAT_ERROR_BACKTRACE returns where it happened: one ORA-06512 line for each frame, with the unit and the line number, from the failing statement to the handler. The first says which rule broke and the second which line broke it, so a log row needs both. Outside a handler the backtrace function returns NULL.

Three longer questions cover an empty log table, a hanging logger and customer details in log messages:

  1. Mid to senior

    A nightly settlement job catches each failure in an OTHERS handler, inserts a row into an error table and raises the error again. The scheduler rolls the batch back on the error, and next morning the table is empty although the job log shows 40 failed accounts. Explain the empty table and change the logging.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Senior to staff

    A procedure marks an invoice paid and then calls a logging procedure declared with PRAGMA AUTONOMOUS_TRANSACTION. The logger also updates the note column of the same invoice row. With one user on the system, calls fail with ORA-00060. Explain the error and redesign the logger.

    Model answer, Pro. First step and follow-ups

  3. Mid to staff

    Support asks the developers of a payments module to add the customer's name, phone number and full account number to every error row, so that tickets move faster. Decide what each row holds instead, and how support still finds the customer.

    Model answer, Pro. First step and follow-ups

Flashcards · 7 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. What does SQLERRM tell you, and what does it leave out?

    The error's message, such as ORA-02290 naming the broken check constraint, and nothing about where it happened. It returns at most 512 bytes, so Oracle recommends DBMS_UTILITY.FORMAT_ERROR_STACK, which returns the whole error stack up to 2000 bytes.

  2. What does DBMS_UTILITY.FORMAT_ERROR_BACKTRACE return?

    One ORA-06512 line for each frame, from the statement that failed up to the unit holding the handler. It is for reading inside a handler: the function returns NULL when no error is being handled.

  3. Which end do UTL_CALL_STACK's backtrace indexes start from?

    Index 1 is the origin, the frame of the statement that raised the error, and the highest index, BACKTRACE_DEPTH, is the unit that examines the backtrace, the handler's own unit. So BACKTRACE_LINE(1) is the failing line, in the same order as the FORMAT_ERROR_BACKTRACE text, which starts at the origin too.

  4. How many frames does a backtrace have, and what is the depth outside a handler?

    It ends where it is examined, so the same error seen by a handler one level down has one frame fewer. With no error being handled the depth is 0. The call stack counts the same way: dynamic depth 1 is the subprogram running now.

  5. What happens to a log row the handler wrote in the caller's transaction?

    The caller's ROLLBACK removes it together with everything else the caller changed, so the failure leaves no trace. A row written in a transaction of its own is kept, because it committed on its own.

  6. What does PRAGMA AUTONOMOUS_TRANSACTION give a logger?

    A transaction of its own, so its COMMIT keeps its row whatever the caller does later.

  7. Which two errors wait for a careless autonomous routine?

    ORA-06519 when it returns without a COMMIT or ROLLBACK, and ORA-00060 when it updates a row its caller has locked, because it deadlocks with its own caller.

Key takeaways

  • The message of an error says which rule broke, and the backtrace says where, as one ORA-06512 line for each frame from the failing statement to the handler.
  • UTL_CALL_STACK numbers the same frames in the same order: index 1 is the origin, the unit that examines the backtrace is at index BACKTRACE_DEPTH, and the depth is 0 outside a handler.
  • A log row written in the caller’s transaction is rolled back with it, so a logger needs a transaction of its own.

Terms in this lesson

autonomous transaction
A transaction of its own that a routine marked PRAGMA AUTONOMOUS_TRANSACTION runs while the main transaction waits; its COMMIT keeps its changes whatever the caller does afterwards.
backtrace depth
The number of frames in a backtrace, returned by UTL_CALL_STACK.BACKTRACE_DEPTH. Index 1 is the origin of the error, the highest index is the unit that examines the backtrace, and the depth is 0 when no error is being handled.
error stack
The messages of an error and of the errors it caused. DBMS_UTILITY.FORMAT_ERROR_STACK returns them as text of up to 2000 bytes, where SQLERRM returns at most 512 bytes.
FORMAT_ERROR_BACKTRACE
The DBMS_UTILITY function that, inside a handler, returns one ORA-06512 line for each frame, from the statement that failed to the unit holding the handler; it returns NULL when no error is being handled.
UTL_CALL_STACK
The PL/SQL package that returns the frames of a backtrace or of the call stack as numbers and names, such as BACKTRACE_DEPTH, BACKTRACE_UNIT and BACKTRACE_LINE, instead of one formatted text.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.