views:

231

answers:

2

I have a script that makes use of a package (PKG_MY_PACKAGE). I will change some of the fields in a query in that package and then recompile it (I don't change or compile any other packages). I run the script and I get an error that looks like

    ORA-04068: existing state of packages has been discarded
    ORA-04061: existing state of package body "USER3.PKG_MY_PACKAGE" has been invalidated
    ORA-04065: not executed, altered or dropped package body "USER3.PKG_MY_PACKAGE"
    ORA-06508: PL/SQL: could not find program unit being called: "USER3.PKG_MY_PACKAGE"
    ORA-06512: at line 34

I run the script again (without changing anything else in the system) and the script executes successfully.

I thought that when I compiled before I executed the script that would fix any invalid references. This is 100% reproducible, and the more I use this script the more annoying it gets. What could cause this, and what would fix it?

(oracle 10g, using PL/SQL Developer 7)

+5  A: 

existing state of packages has been discarded means, that your Package had some sort of state.

This is caused by a global variable (or constant) stored in your Package Body.

Since the package has already been used in your session, Oracle assumes that this state is relevant for you. Some of these variables might have different values now, and when you recompile the Body, the values are reset.

This exception is thrown, so that your clients know that they can't rely on those variables any more.

You could try to remove all global variables and constants from the Package Body, or close your session and reconnect before calling the package again.

Peter Lang
Indeed, I do have some globals! I'll see if I can find a way around that, maybe make them non-globals... Is there a way to have static values for procedures in PL/SQL?
FrustratedWithFormsDesigner
What exactly do you mean by "static values for procedures"? Those global variables are more or less static variables (per session). The easiest work-around for you would be to put the global variables in the Package Header instead of the Body - state will not be invalidated any more when compiling the Body. Why do you need those globals?
Peter Lang
They hold configuration values that only need to be set once and drive the rest of the system. I didn't want to put them into the header because I didn't want any other code to have access to them (they get passed into the one relevant procedure from a script). I suppose they could be stored in a table, but there could be a LOT of reads on that table if I did it.
FrustratedWithFormsDesigner
Guess I would have put configuration into the Body too. Reading it from a table might slow down your process. Are you still going to recompile your Body in future or is this only now for testing? One other way would be to define a `RECORD` containing all necessary variables and pass it to the procedures that you call.
Peter Lang
@Peter Lang: I think for now I will just read from the table. I've rewritten part of the affected code so I don't think it will have too many reads, so probably not major performance problem now. I'm only going through all this recompiling for dev/test, so this shouldn't be an issue in production systems.
FrustratedWithFormsDesigner
+4  A: 

If you're running stuff in a script try these commands in there prior to running the re-compiled code..

exec DBMS_SESSION.RESET_PACKAGE
exec DBMS_SESSION.MODIFY_PACKAGE_STATE( DBMS_SESSION.REINITIALIZE )

They do what the name might suggest.

Paul James
Interesting... I'll have to try this.
FrustratedWithFormsDesigner
Man, I wish I could mark two answers as the accepted answer. One of the other devs here said this works fine, and it means I don't have to worry about re-writing and re-testing code.
FrustratedWithFormsDesigner