Статьи про Oracle
->
Программирование
dbms_utility.format_error_backtrace — отслеживание ошибок в pl/sql
v:1.0 03.12.2011
Петрелевич Сергей
Часто при обработке исключений в pl/sql разработчики ограничиваются использованием встроенной функции sqlerrm, однако в Oracle есть и другие интересные
средства для обработки ошибок. Одно из этих средств — функция dbms_utility.format_error_backtrace.
Функция dbms_utility.format_error_backtrace возвращает список вызовов функций и процедур от места генерации исключения до места его обработки.
Для рассмотрения работы dbms_utility.format_error_backtrace создадим тестовый пакет с процедурами, которые подобно матрешкам вызываются одна из другой.
create or replace package Err asprocedure testProc1;
procedure testProc2;
procedure testProc3;
procedure testProc4;end;
Пример 1. dbms_utility.format_error_backtrace в каждом обработчике исключений
В первом примере функция dbms_utility.format_error_backtrace вставлена в обработчики исключений каждой процедуры.
- create or replace package body Err as
- procedure testProc1 is
- begin
- dbms_output.put_line('testProc1');
- testProc2;
- exception
- when others then
- dbms_output.put_line('testProc1 error:'||dbms_utility.format_error_stack);
- dbms_output.put_line('stack:'||dbms_utility.format_error_backtrace);
- end;
- procedure testProc2 is
- begin
- dbms_output.put_line('testProc2');
- testProc3;
- exception
- when others then
- dbms_output.put_line('testProc2 error:'||dbms_utility.format_error_stack);
- dbms_output.put_line('stack:'||dbms_utility.format_error_backtrace);
- raise;
- end;
- procedure testProc3 is
- begin
- dbms_output.put_line('testProc3');
- testProc4;
- exception
- when others then
- dbms_output.put_line('testProc3 error:'||dbms_utility.format_error_stack);
- dbms_output.put_line('stack:'||dbms_utility.format_error_backtrace);
- raise;
- end;
- procedure testProc4 is
- begin
- dbms_output.put_line('testProc4');
- raise no_data_found;
- exception
- when others then
- dbms_output.put_line('testProc4 error:'||dbms_utility.format_error_stack);
- dbms_output.put_line('stack:'||dbms_utility.format_error_backtrace);
- raise;
- end;
- end;
Выполняем первую процедуру.
Получаем результат:
testProc1 testProc2 testProc3 testProc4 testProc4 error:ORA-01403: no data found stack:ORA-06512: at "DEV.ERR", line 38 testProc3 error:ORA-01403: no data found stack:ORA-06512: at "DEV.ERR", line 43 ORA-06512: at "DEV.ERR", line 27 testProc2 error:ORA-01403: no data found stack:ORA-06512: at "DEV.ERR", line 32 ORA-06512: at "DEV.ERR", line 16 testProc1 error:ORA-01403: no data found stack:ORA-06512: at "DEV.ERR", line 21 ORA-06512: at "DEV.ERR", line 6
Видно, что функция dbms_utility.format_error_backtrace выводит пакет, в котором сработало исключение и номер строки. Надо отметить, что в данном примере
и строки вида dbms_output.put_line(‘testProc3 error:’||dbms_utility.format_error_stack); отлично формируют стек ошибки, dbms_utility.format_error_backtrace лишь
уточняет конкретную строку.
Пример 2. dbms_utility.format_error_backtrace в стартовой процедуре, во всех процедурах есть обработчики исключений
Рассмотрим другой пример.
На этот раз dbms_utility.format_error_backtrace будет в стартовой процедуре, из которой вызываются другие.
В других процедурах будут обработчики исключений, но в них не будет вызова dbms_utility.format_error_backtrace.
- create or replace package body Err as
- procedure testProc1 is
- begin
- dbms_output.put_line('testProc1');
- testProc2;
- exception
- when others then
- dbms_output.put_line('testProc1 error:'||dbms_utility.format_error_stack);
- dbms_output.put_line('stack:'||dbms_utility.format_error_backtrace);
- end;
- procedure testProc2 is
- begin
- dbms_output.put_line('testProc2');
- testProc3;
- exception
- when others then
- raise;
- end;
- procedure testProc3 is
- begin
- dbms_output.put_line('testProc3');
- testProc4;
- exception
- when others then
- raise;
- end;
- procedure testProc4 is
- begin
- dbms_output.put_line('testProc4');
- raise no_data_found;
- exception
- when others then
- raise;
- end;
- end;
Выполняем первую процедуру.
Получаем результат:
testProc1 testProc2 testProc3 testProc4 testProc1 error:ORA-01403: no data found stack:ORA-06512: at "DEV.ERR", line 19 ORA-06512: at "DEV.ERR", line 6
Информации не очень-то много. Складывается впечатление, что ошибка возникла в 19 строке кода, хотя правильное место — строка 34.
Причина в том, что dbms_utility.format_error_backtrace показывает стек не с места фактического появления ошибки, а с мест ее последнего перехвата.
В нашем случае это процедура proc2, строка 21.
Получается, в этом случае dbms_utility.format_error_backtrace ни только не помогает, а еще и мешает, запутывает следы.
Пример 3. dbms_utility.format_error_backtrace в стартовой процедуре, в других процедурах нет обработчиков исключений
На этот раз все исключения обрабатываются только в одном месте — вызывающей функции, и только в ней используется dbms_utility.format_error_backtrace.
- create or replace package body Err as
- procedure testProc1 is
- begin
- dbms_output.put_line('testProc1');
- testProc2;
- exception
- when others then
- dbms_output.put_line('testProc1 error:'||dbms_utility.format_error_stack);
- dbms_output.put_line('stack:'||dbms_utility.format_error_backtrace);
- end;
- procedure testProc2 is
- begin
- dbms_output.put_line('testProc2');
- testProc3;
- end;
- procedure testProc3 is
- begin
- dbms_output.put_line('testProc3');
- testProc4;
- end;
- procedure testProc4 is
- begin
- dbms_output.put_line('testProc4');
- raise no_data_found;
- end;
- end;
Выполняем первую процедуру.
Получаем результат:
testProc1 testProc2 testProc3 testProc4 testProc1 error:ORA-01403: no data found stack:ORA-06512: at "DEV.ERR", line 32 ORA-06512: at "DEV.ERR", line 25 ORA-06512: at "DEV.ERR", line 18 ORA-06512: at "DEV.ERR", line 7
На этот раз информации куда больше. По выводу функции dbms_utility.format_error_backtrace можно точно отследить, что ошибка появилась в функции testProc4,
строка 32, и какие процедуры выполнялись.
Из этих примеров можно вывести две основные тактики применения dbms_utility.format_error_backtrace.
Эту функцию надо вставлять в каждый обработчик исключений или обрабатывать все исключения в одной точке — стартовой процедуре(функции).
Метки:
PL/SQL
Внимание.
Комментировать могут только зарегистрированные пользователи.
Возможно использование следующих HTML тегов: <a>, <b>, <i>, <br>.
PL/SQL 101: Three ways to get error message/stack in PL/SQL
The PL/SQL Challenge quiz for 10 September — 16 September 2016 explored the different ways you can obtain the error message / stack in PL/SQL. Note: an error stack is a sequence of multiple error messages that can occur when an exception is propagated and re-raised through several layers of nested blocks.
The three ways are:
- SQLERRM — The original, traditional and (oddly enough) not currently recommended function to get the current error message. Not recommended because the next two options avoid a problem which you are unlikely to run into: the error stack will be truncated at 512 bytes, and you might lose some error information.
- DBMS_UTILITY.FORMAT_ERROR_STACK — Returns the error message / stack, and will not truncate your string like SQLERRM will.
- UTL_CALL_STACK API — Added in Oracle Database 12c, the UTL_CALL_STACK package offers a comprehensive API into the execution call stack, the error stack and the error backtrace.
Note: check out this LiveSQL script if you’d like to explore more of the nuances between SQLERRM and DBMS_UTILITY.FORMAT_ERROR_STACK.
Other helpful resources regarding error management in PL/SQL:
Nine Good to Knows for PL/SQL Error Management
PL/SQL Error Handling (doc)
Finally, here’s the code from our quiz that you can copy/paste into your editor to check out these alternatives.
CREATE OR REPLACE PROCEDURE plch_check_balance (
balance_in IN NUMBER) AUTHID DEFINER IS BEGIN IF balance_in < 0 THEN RAISE VALUE_ERROR; END IF; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.put_line (SQLERRM); END; / BEGIN plch_check_balance (-1); END; / CREATE OR REPLACE PROCEDURE plch_check_balance (
balance_in IN NUMBER) AUTHID DEFINER IS BEGIN IF balance_in < 0 THEN RAISE VALUE_ERROR; END IF; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_stack); END; / BEGIN plch_check_balance (-1); END; / CREATE OR REPLACE PROCEDURE plch_check_balance (
balance_in IN NUMBER) AUTHID DEFINER IS BEGIN IF balance_in < 0 THEN RAISE VALUE_ERROR; END IF; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.put_line ( 'ORA-' || TO_CHAR (UTL_CALL_STACK.error_number (1), 'fm00000') || ': ' || UTL_CALL_STACK.error_msg (1)); END; / BEGIN plch_check_balance (-1); END; / DROP PROCEDURE plch_check_balance /
Popular posts from this blog
A Twitter follower recently asked for more information on user-defined types in the PL/SQL language, and I figured the best way to answer is to offer up this blog post. PL/SQL is a strongly-typed language . Before you can work with a variable or constant, it must be declared with a type (yes, PL/SQL also supports lots of implicit conversions from one type to another, but still, everything must be declared with a type). PL/SQL offers a wide array of pre-defined data types , both in the language natively (such as VARCHAR2, PLS_INTEGER, BOOLEAN, etc.) and in a variety of supplied packages (e.g., the NUMBER_TABLE collection type in the DBMS_SQL package). Data types in PL/SQL can be scalars, such as strings and numbers, or composite (consisting of one or more scalars), such as record types, collection types and object types. You can’t really declare your own «user-defined» scalars, though you can define subtypes from those scalars, which can be very helpful from the p
EVERY once in a while, a developer gets in touch with a question like this: I am confused about the exact difference between deterministic and result_cache. Do they have different application use cases? I have used deterministic feature in many functions which retrieve data from some lookup tables. Is it essential to replace these ‘deterministic’ key words with ‘result_cache’? So I thought I’d write a post about the differences between these two features. But first, let’s make sure we all understand what it means for a function to be deterministic. From Wikipedia : In computer science, a deterministic algorithm is an algorithm which, given a particular input, will always produce the same output, with the underlying machine always passing through the same sequence of states. Another way of putting this is that a deterministic subprogram (procedure or function) has no side-effects. If you pass a certain set of arguments for the parameters, you will always get
We (the over-sized development team for the PL/SQL Challenge — myself and my son, Eli) have been busy creating a new website on top of the PLCH platform (tables and packages): The Oracle Dev Gym! In a few short months (and just a part time involvement by yours truly), we have leveraged Oracle Application Express 5 to create what I think is an elegant, easy-to-use site that our users will absolutely love. We plan to initially make the Dev Gym available only for current users of PL/SQL Challenge, so we can get feedback from our loyal user base. We will make the necessary adjustments and then offer it for general availability later this year. Anyway, more on that as the date approaches (the date being June 27, the APEX Open Mic Night at Kscope16 , where I will present it to a packed room of APEX experts). What I want to talk about today are two features of APEX that are making me so happy these days: Regional Display Selector and Cards. Regional Display Sel
Возможно стоит устаревший клиент. У меня получается полный стек исключения:
SQL> run
1 declare
2 PROCEDURE p1
3 AS
4 BEGIN
5 RAISE no_data_found;
6 END;
7
8 PROCEDURE p2
9 AS
10 BEGIN
11 RAISE no_data_found;
12 END;
13
14 PROCEDURE p
15 AS
16 BEGIN
17 p1;
18 p2;
19 EXCEPTION
20 WHEN OTHERS /*no_data_found*/ THEN
21 RAISE;
22 END;
23
24 BEGIN
25 p;
26* end;
declare
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 21
ORA-06512: at line 5
ORA-06512: at line 17
ORA-06512: at line 25
Видно, что при вызове процедуры P1
в 17 строке произошло исключение в 5 строке.
Если интереснна обработка исключения внутри блока EXCEPTION
, то следует воспользоваться функциями пакета DBMS_UTILITY, или более нового UTL_CALL_STACK.
Вот простой пример:
create or replace package pack as
procedure p1;
procedure p2;
procedure p;
end;
/
create or replace package body pack as
procedure p1 as
begin raise no_data_found; -- 3 строка
end;
procedure p2 as
begin raise no_data_found;
end;
procedure p as
begin
p1; -- 10 строка
p2;
exception when others then
dbms_output.put_line (sqlerrm||chr(10)||dbms_utility.format_error_backtrace ());
end;
end pack;
/
Даст обратный стек исключения, ошибка в 3 строке при вызове процедуры p1
в 10 строке:
begin
pack.p;
end;
/
ORA-01403: no data found
ORA-06512: at "ME.PACK", line 3
ORA-06512: at "ME.PACK", line 10
В Oracle 10g возможности для работы со стеком ошибок были расширены. В пакете DBMS_UTILITY появились функции, которые позволяют получить больше информации о том, как ведёт себя программа в случае возникновения исключительной ситуации.
Вот эти функции:
- FORMAT_ERROR_BACKTRACE — позволяет получить строку из программы, в которой произошла исключительная ситуация.
- FORMAT_CALL_STACK — отображает на экране стэк программы на момент возникновения исключения.
- FORMAT_ERROR_STACK — позволяет получить “полное” сообщение об ошибке (дело в том, что привычная всем функция SQLERRM имеет ограничение на длину выводимого текста 512 символов, новая функция имеет ограничение в 2000 символов).
Самый простой пример, который демонстрирует работу этих функций выглядит так:
DECLARE
local_exception EXCEPTION;
FUNCTION nested_local_function
RETURN BOOLEAN IS
retval BOOLEAN := FALSE;
BEGIN
RAISE local_exception;
RETURN retval;
END;
BEGIN
IF nested_local_function THEN
dbms_output.put_line(‘No raised exception’);
END IF;
EXCEPTION
WHEN others THEN
dbms_output.put_line(‘DBMS_UTILITY.FORMAT_CALL_STACK’);
dbms_output.put_line(‘——————————‘);
dbms_output.put_line(dbms_utility.format_call_stack);
dbms_output.put_line(‘DBMS_UTILITY.FORMAT_ERROR_BACKTRACE’);
dbms_output.put_line(‘————————————‘);
dbms_output.put_line(dbms_utility.format_error_backtrace);
dbms_output.put_line(‘DBMS_UTILITY.FORMAT_ERROR_STACK’);
dbms_output.put_line(‘——————————-‘);
dbms_output.put_line(dbms_utility.format_error_stack);
END;
Если его выполнить, то получим:
DBMS_UTILITY.FORMAT_CALL_STACK
——————————
—— PL/SQL Call Stack ——
object line object
handle number name
20909240 18 anonymous block
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
————————————
ORA-06512: at line 7
ORA-06512: at line 11
DBMS_UTILITY.FORMAT_ERROR_STACK
——————————-
ORA-06510: PL/SQL: unhandled user-defined exception
Скорее всего, самой востребованной функцией будет — DBMS_UTILITY.FORMAT_ERROR_BACKTRACE, рекомендую ознакомиться с более интересным примеров стека ошибок на сайте документации по Oracle 10g: http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_util.htm#i1003874
Often, it’s a head ache for me to
debug the unhandled exception in my programs. Now, I have a pill for it. It’s DBMS_UTILITY.FORMAT_ERROR_STACK
and DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
Let’s see how it’s useful for PLSQL
developers.
Test Package:
CREATE OR replace PACKAGE test_oracle
IS
PROCEDURE main;
END test_oracle;
/
CREATE OR replace PACKAGE BODY test_oracle
IS
PROCEDURE Fun5
IS
ln_dummy_number NUMBER;
BEGIN
ln_dummy_number := 1 / 0; — Kept to raise an exception
END;
PROCEDURE Fun4
IS
BEGIN
fun5;
END;
PROCEDURE Fun3
IS
BEGIN
fun4;
END;
PROCEDURE Fun2
IS
BEGIN
fun3;
END;
PROCEDURE Main
IS
BEGIN
fun2;
EXCEPTION
WHEN OTHERS THEN
dbms_output.Put_line(‘Format error
stack:’
||dbms_utility.Format_error_stack());
dbms_output.Put_line(‘Print error
stack:’
||Chr(10)
||dbms_utility.Format_error_backtrace());
END;
END test_oracle;
/
show errors;
Testing:
Now, I know the exact line which
caused the error. It mentioned standard oracle utilities gaves the complete
back trace. It’s a nice utility!!
Hopefully it helps!!
Do you think this Article is useful?
Disclaimer
The ideas, thoughts and concepts expressed here are my own. They, in no way reflect those of my employer or any other organization/client that I am associated. The articles presented doesn’t imply to any particular organization or client and are meant only for knowledge Sharing purpose. The articles can’t be reproduced or copied without the Owner’s knowledge or permission.