Reputation: 1061
I've wrapper procedure which looks like this:
Procedure A
BEGIN;
Procedure B
Procedure C
END;
/
Procedure B drops and re-creates a table used in Procedure C. Due to this, I get the below error:
ERROR at line 1:
ORA-04068: existing state of packages has been discarded ORA-04065: not executed, altered or dropped stored procedure "SCHEMA.PROCEDURE C"
ORA-06508: PL/SQL: could not find program unit being called: "SCHEMA.PROCEDURE C"
ORA-06512: at "SCHEMA.PROCEDURE A", line 4
ORA-06512: at line 1
How do I go about getting this procedure to work?
Upvotes: 1
Views: 4192
Reputation: 36807
I recommend using dynamic SQL to call the DML in procedure C. By removing the dependency nothing gets invalidated. This would likely be more reliable than dynamically re-compiling code or dynamically running the code and catching all exceptions.
You can see this in the below sample code. Comment out the static SQL call on line 10 in procedure C to replicate the error.
drop table drop_me;
create table drop_me(id number);
create or replace procedure C is
v_count number;
begin
--Static SQL would fail with this error:
-- ORA-04068: existing state of packages has been discarded
-- ORA-04065: not executed, altered or dropped stored procedure "JHELLER.C"
-- ORA-06508: PL/SQL: could not find program unit being called: "JHELLER.C"
-- ORA-06512: at "JHELLER.A", line 4
-- ORA-06512: at line 2
--select count(*) into v_count from drop_me;
--Dynamic SQL runs correctly:
execute immediate 'select count(*) from drop_me' into v_count;
end;
/
create or replace procedure B is
begin
execute immediate 'drop table drop_me purge';
execute immediate 'create table drop_me(id number)';
end;
/
create or replace procedure A is
begin
B;
C;
end;
/
begin
A;
end;
/
But I agree with Alex Poole that there is almost certainly a better way to do this without dropping and re-creating objects. I can think of a few reasons why a DROP
and CREATE
might run faster than a TRUNCATE
and INSERT
, but only because of some weird side-effect, like dropping bad table statistics. Investigate the difference more and you might find the real reason.
Upvotes: 2
Reputation: 6346
You can do something like it.
begin
procedureB;
begin
execute immediate 'begin procedureC; end;';
exception when others then
execute immediate 'begin procedureC; end;';
end;
end;
Upvotes: 0
Reputation: 366
So your proc get invalid during the execution, that is why you need recompile Procedure C. To achive this, you can call a dynamic SQL statement:
EXECUTE IMMEDIATE 'ALTER PROCEDURE my_procedure COMPILE';
Procedure_A IS
BEGIN;
Procedure_B;
EXECUTE IMMEDIATE 'ALTER PROCEDURE Procedure_C COMPILE';
Procedure_C;
END;
/
Upvotes: 2