当一个包有状态并且头部改变时,第一次调用会得到一个错误堆栈,如下所示:
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package "LRIFFEL.PKG1" has been invalidated
ORA-04065: not executed, altered or dropped package "LRIFFEL.PKG1"
ORA-06508: PL/SQL: could not find program unit being called: "LRIFFEL.PKG1"
ORA-06512: at "LRIFFEL.PKG2", line 7
ORA-06512: at line 1
来自同一会话的后续调用会重新初始化包状态并因此成功运行。有趣的是,当调用者捕获异常并执行 raise_application_error 时,这种行为似乎发生了变化。正如预期的那样,raise_application_error 包含在堆栈中,但与预期相反,ORA-04068 没有。这是一个示例错误堆栈:
ERROR at line 1:
ORA-20001: Failed
ORA-06512: at "LRIFFEL.PKG2", line 7
ORA-04061: existing state of package "LRIFFEL.PKG1" has been invalidated
ORA-04065: not executed, altered or dropped package "LRIFFEL.PKG1"
ORA-06508: PL/SQL: could not find program unit being called: "LRIFFEL.PKG1"
ORA-06512: at line 1
这似乎不仅仅是一个显示问题,因为重复调用该过程继续得到相同的错误。只有当将 raise_application_error 转换回简单的 raise(或完全消除异常块)时,下一次执行才会包含 ORA-04068,并且下一次执行成功。
任何人都可以确认和/或解释这种行为吗?这是重现该行为的方法:
--Session 1 - Create Objects
create or replace package pkg1 as
vInteger Integer := 7;
procedure procA;
end;
/
create or replace
package body pkg1 as
procedure procA is
begin
DBMS_Output.Put_Line('ProcA');
end;
end;
/
create or replace
package pkg2 as
procedure procB;
end;
/
create or replace
package body pkg2 as
procedure procB is
begin
pkg1.procA;
exception
when others then
raise;
end;
end;
/
--Session 2 - Test execution.
execute pkg2.procB;
--Session 1 - Change package header and thus invalidate package state.
create or replace package pkg1 as
vInteger Integer := 8;
procedure procA;
end;
/
--Session 2 - Observe failure due to changed package state.
execute pkg2.procB;
--Session 2 - Observe success due to re-initialized package state.
execute pkg2.procB;
--Session 1 - Change Raise to Raise_Application_Error.
create or replace
package body pkg2 as
procedure procB is
begin
pkg1.procA;
exception
when others then
raise_application_error(-20001,'Failed',True);
end;
end;
/
--Session 1 - Change package header and thus invalidate package state.
create or replace package pkg1 as
vInteger Integer := 9;
procedure procA;
end;
/
--Session 2 - Observe failure due to changed package state.
execute pkg2.procB;
--Session 2 - Observe unexpected continued failures.
execute pkg2.procB;
execute pkg2.procB;
execute pkg2.procB;
execute pkg2.procB;
execute pkg2.procB;
execute pkg2.procB;
execute pkg2.procB;
--Session 1 - Change back to raise.
create or replace
package body pkg2 as
procedure procB is
begin
pkg1.procA;
exception
when others then
raise;
end;
end;
/
--Session 2 - Observe failure on the first execution.
execute pkg2.procB;
--Session 2 - Observe success.
execute pkg2.procB;
除了涉及触发器之外,错误 229349 看起来很相似。
Oracle 的回应是,这并不是真正的错误,因为应用程序正在捕获 4068 并对其进行处理,因此无法正常解决错误。他们的解释对我来说似乎不够充分,因为如果包抛出 ORA-01476-除以零(例如),执行 raise_application_error 不会影响 ORA-01476 是否包含在堆栈中。