Quando um pacote tem estado e o cabeçalho é alterado, a primeira chamada recebe uma pilha de erros mais ou menos assim:
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
Uma chamada subseqüente da mesma sessão reinicializa o estado do pacote e, portanto, é executado com êxito. O interessante é que esse comportamento parece mudar quando o chamador captura a exceção e faz um raise_application_error. Como esperado, o raise_application_error está incluído na pilha, mas ao contrário das expectativas, o ORA-04068 não está. Aqui está um exemplo de pilha de erros:
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
Isso não parece ser apenas um problema de exibição, pois chamadas repetidas para o procedimento continuam obtendo o mesmo erro. Somente ao converter o raise_application_error de volta para um aumento simples (ou eliminar totalmente o bloco de exceção) a próxima execução inclui o ORA-04068 e a execução seguinte é bem-sucedida.
Alguém pode confirmar e/ou explicar esse comportamento? Aqui está uma receita para reproduzir o comportamento:
--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;
O bug 229349 parece semelhante, exceto que um gatilho está envolvido.
A resposta da Oracle é que isso não é realmente um bug porque o aplicativo está capturando o 4068 e manipulando-o, não permitindo assim que ocorra a resolução normal do erro. A explicação deles não me parece adequada porque se o pacote lançar um ORA-01476-Divide By Zero (por exemplo), fazer um raise_application_error não afeta se o ORA-01476 está incluído na pilha ou não.