Oracle 如何在没有包状态的情况下传递PL/SQL异常传播中的错误详细信息?
目前,我正在使用以下模式记录PL/SQL异常传播中的错误详细信息。有关详细信息,请参见下面的注释代码。我对此很满意,因为错误处理代码不会使整个代码库混乱,并且可以记录触发错误的所有细节 不幸的是,Oracle 如何在没有包状态的情况下传递PL/SQL异常传播中的错误详细信息?,oracle,plsql,oracle11g,Oracle,Plsql,Oracle11g,目前,我正在使用以下模式记录PL/SQL异常传播中的错误详细信息。有关详细信息,请参见下面的注释代码。我对此很满意,因为错误处理代码不会使整个代码库混乱,并且可以记录触发错误的所有细节 不幸的是,v_error变量引入了一个不必要的包状态副作用 如何在PL/SQL异常传播中传递错误详细信息而不引入包状态?(我想消除包状态以使部署更容易。) 使用不同的异常,如rule_2_failure_ex和rule_3_failure_ex不是我正在寻找的解决方案 不需要以不同的方式处理错误条件 对于故障排除
v_error
变量引入了一个不必要的包状态副作用
如何在PL/SQL异常传播中传递错误详细信息而不引入包状态?(我想消除包状态以使部署更容易。)
使用不同的异常,如rule_2_failure_ex
和rule_3_failure_ex
不是我正在寻找的解决方案
create or replace package body so50 is
processing_failure_ex exception;
pragma exception_init(processing_failure_ex, -20999);
并提出你想要的信息:
raise_application_error(-20999,
'Failed to process rule 3: (p_num = ' || p_num || ')', true);
如果要存储整个堆栈,可以使用:
因此,完全删除v_错误
:
create or replace package so50 is
procedure run(p_num in number);
end;
/
create or replace package body so50 is
processing_failure_ex exception;
pragma exception_init(processing_failure_ex, -20999);
-- in reality the processing and details are more complex
procedure p3(p_num in number) is
begin
if p_num = 3
then
-- it's important to be able to record arbitrary information at this point
raise_application_error(-20999,
'Failed to process rule 3: (p_num = ' || p_num || ')', true);
end if;
end;
-- the comments on p3 apply
procedure p2(p_num in number) is
begin
if p_num = 2
then
raise_application_error(-20999,
'Failed to process rule 2: (p_num = ' || p_num || ')', true);
end if;
end;
procedure p1(p_num in number) is
begin
p2(p_num);
p3(p_num);
exception
when others then
raise_application_error(-20999,
'Additional details of failure', true);
end;
procedure run(p_num in number) is
begin
begin
p1(p_num);
exception
when processing_failure_ex then
-- in reality an error recovery will be tried first and only then
-- the error will be forwarded to a monitoring framework that will
-- raise an alert for human action
dbms_output.put_line('Error details:');
dbms_output.put_line(dbms_utility.format_error_stack);
raise;
end;
exception
when others then
-- out of the scope of the question
raise;
end;
end;
/
打电话会得到:
SQL> set serveroutput on
SQL> exec so50.run(1);
PL/SQL procedure successfully completed.
SQL> exec so50.run(2);
ORA-20999: Additional details of failure
ORA-06512: at "STACKOVERFLOW.SO50", line 42
ORA-20999: Failed to process rule 2: (p_num = 2)
ORA-06512: at "STACKOVERFLOW.SO50", line 64
ORA-06512: at line 1
Error details:
ORA-20999: Additional details of failure
ORA-06512: at "STACKOVERFLOW.SO50", line 42
ORA-20999: Failed to process rule 2: (p_num = 2)
SQL> exec so50.run(3);
ORA-20999: Additional details of failure
ORA-06512: at "STACKOVERFLOW.SO50", line 42
ORA-20999: Failed to process rule 3: (p_num = 3)
ORA-06512: at "STACKOVERFLOW.SO50", line 64
ORA-06512: at line 1
Error details:
ORA-20999: Additional details of failure
ORA-06512: at "STACKOVERFLOW.SO50", line 42
ORA-20999: Failed to process rule 3: (p_num = 3)
在这两种情况下,“Error details:”之前的堆栈跟踪都来自最终的范围外提升;如果它被暂时挤压(只是为了演示,而不是建议你真的挤压!),你只会看到:
SQL> exec so50.run(3);
PL/SQL procedure successfully completed.
Error details:
ORA-20999: Additional details of failure
ORA-06512: at "STACKOVERFLOW.SO50", line 42
ORA-20999: Failed to process rule 3: (p_num = 3)
对于不同的过程和场景,您可以使用不同的异常编号。当然,我现在只使用了一个通用的异常编号来简化事情。如果您想按名称捕获它们,则只需命名它们(通过pragma与名称绑定)。如果您这样做,您可以在一个地方定义所有异常。我当前基于@AlexPoole answer的解决方案: 例外包
-- encapsulates the uglyness to keep calling code clean
create or replace package so50_ex is
-- exception type and error code reserved for this purpose only
general_ex exception;
general_ex_code constant number := -20999;
pragma exception_init(general_ex, -20999);
procedure raise(p_msg in varchar2, p_ex_code in number default -20999);
function full_error_stack return varchar2;
end;
/
show errors
create or replace package body so50_ex is
procedure raise(p_msg in varchar2, p_ex_code in number default -20999) is
begin
raise_application_error(p_ex_code,
substrb(p_msg, 1, 2048),
true);
end;
function full_error_stack return varchar2 as
-- will always fit to buffer as format_error_stack returns 2000 bytes at
-- maximum
v_stack varchar2(32767) := dbms_utility.format_error_stack;
begin
-- might not fit to buffer as format_error_backtrace return length is not
-- limited
v_stack := v_stack ||
substrb(dbms_utility.format_error_backtrace, 1, 30767);
return v_stack;
end;
end;
/
show errors
create or replace package so50 is
-- a user can always have his own exceptions
processing_failure_ex exception;
processing_failure_ex_code constant number := -20100;
pragma exception_init(processing_failure_ex, -20100);
procedure run(p_num in number);
end;
/
show errors
create or replace package body so50 is
procedure p3(p_num in number) is
begin
if p_num = 3
then
-- use specific exception
so50_ex.raise('Failed to process rule 3: (p_num = ' || p_num || ')',
processing_failure_ex_code);
end if;
end;
procedure p2(p_num in number) is
begin
if p_num = 2
then
-- use default exception
so50_ex.raise('Failed to process rule 2: (p_num = ' || p_num || ')');
end if;
end;
procedure p1(p_num in number) is
begin
p2(p_num);
p3(p_num);
exception
when processing_failure_ex then
dbms_output.put_line('ERROR RECOVERED SUCCESFULLY.');
dbms_output.put_line('DETAILS:');
dbms_output.put_line(so50_ex.full_error_stack);
when others then
so50_ex.raise('Additional details of failure.');
end;
procedure run(p_num in number) is
begin
p1(p_num);
exception
when others then
dbms_output.put_line('EXCEPTION: ' || so50_ex.full_error_stack);
raise;
end;
end;
/
show errors
用法示例
-- encapsulates the uglyness to keep calling code clean
create or replace package so50_ex is
-- exception type and error code reserved for this purpose only
general_ex exception;
general_ex_code constant number := -20999;
pragma exception_init(general_ex, -20999);
procedure raise(p_msg in varchar2, p_ex_code in number default -20999);
function full_error_stack return varchar2;
end;
/
show errors
create or replace package body so50_ex is
procedure raise(p_msg in varchar2, p_ex_code in number default -20999) is
begin
raise_application_error(p_ex_code,
substrb(p_msg, 1, 2048),
true);
end;
function full_error_stack return varchar2 as
-- will always fit to buffer as format_error_stack returns 2000 bytes at
-- maximum
v_stack varchar2(32767) := dbms_utility.format_error_stack;
begin
-- might not fit to buffer as format_error_backtrace return length is not
-- limited
v_stack := v_stack ||
substrb(dbms_utility.format_error_backtrace, 1, 30767);
return v_stack;
end;
end;
/
show errors
create or replace package so50 is
-- a user can always have his own exceptions
processing_failure_ex exception;
processing_failure_ex_code constant number := -20100;
pragma exception_init(processing_failure_ex, -20100);
procedure run(p_num in number);
end;
/
show errors
create or replace package body so50 is
procedure p3(p_num in number) is
begin
if p_num = 3
then
-- use specific exception
so50_ex.raise('Failed to process rule 3: (p_num = ' || p_num || ')',
processing_failure_ex_code);
end if;
end;
procedure p2(p_num in number) is
begin
if p_num = 2
then
-- use default exception
so50_ex.raise('Failed to process rule 2: (p_num = ' || p_num || ')');
end if;
end;
procedure p1(p_num in number) is
begin
p2(p_num);
p3(p_num);
exception
when processing_failure_ex then
dbms_output.put_line('ERROR RECOVERED SUCCESFULLY.');
dbms_output.put_line('DETAILS:');
dbms_output.put_line(so50_ex.full_error_stack);
when others then
so50_ex.raise('Additional details of failure.');
end;
procedure run(p_num in number) is
begin
p1(p_num);
exception
when others then
dbms_output.put_line('EXCEPTION: ' || so50_ex.full_error_stack);
raise;
end;
end;
/
show errors
此时,它将打印“Error details:”行,然后获取ORA-06510:PL/SQL:unhandled用户定义的异常(如果调用值为1或2)。您实际上是在尝试在异常堆栈跟踪中查看“错误详细信息”字符串?@AlexPoole是的,基本上是这样。IMO
raise\u application\u error
需要我想要避免的不必要的额外样板。但这在PL/SQL中并不总是可能的。