Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Anthony.

Asked: April 23, 2002 - 10:35 pm UTC

Last updated: February 10, 2012 - 5:03 pm UTC

Version: 8.1.7.2.1 EE

Viewed 10K+ times! This question is

You Asked

HI TOM,

Tnx for this oppurtunity again, Can You explain how does the ORA-4068 occurs and how can I go about it?

How does oracle manages the freelist (8i) on LMT's? And how can we track the freespace, used space, and fragmentation on LMT's?

What's the difference between creating the index with parallel option and not in parallel mode ?

TNX
NOTNA

and Tom said...

That error occurrs when

- you have a package
- someone used the package
- the package maintains a state
- you recreate the package, killing their state.


Freelists on LMT's are no different then freelists on DMT's. Freelists are based on SEGMENTS, not tablespaces. LMT's do not get fragemented, that is one of their properties. No need to track that which does not happen.

Search for free.sql on this site to get a script that'll list free space, used space and more by tablespace.


As for the index -- isn't it obvious? One creates the index using more then one thread/process (in parallel). The other -- doesn't.

Rating

  (33 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

ora-4068

Anthony Velarde, April 24, 2002 - 9:05 pm UTC

Actually here's what's happenning,

We have a two schema on one DB and two separate folders for the FMX. One for development and one for QA. When we apply a fix on a certain procedure we development was updated then after testing on development we update the QA schema and recompile the forms from QA folder. When we execute the FMX on the QA folder it's running well, but when we execute the FMX using the QA folder on the DEVELOPMENT schema (I assure you that nobody updated the DEVELOPMENT schema after the update on QA schema) we encountered the error ora-4068, but when we compile the FMX from the QA folder using the DEVELOPMENT environment the problem disappears. Sometimes I change the FORMS60_PATH from the regedit and the problem disappears again (again I assure you that nobody is compiling procedures or forms on both environments.
I hope you can give me an explaination on this.
TNX.
ANTHONY

Tom Kyte
April 25, 2002 - 7:12 am UTC

This is fixed by simply re-executing the package. The default mode of checking to see if things have changed is a timestamp mode. When you compiled the forms against different databases, the timestamps are different.

You can also look into using remote_dependencies_mode = signature mode instead of timestamp (database level parameter)

changing it to SIGNATURE

Pushparaj Arulappan, March 12, 2004 - 10:01 am UTC

Tom,

In all our production instances we currently have
remote_dependencies_mode is set to "TIMESTAMP"
and we are planning to change that to "SIGNATURE".

My question is, after changing the parameter to
"SIGNATURE", do we need to re-compile all the
stored programs and the packages.

These programs are called from many other remote databases.

Thanks
Pushparaj

Tom Kyte
March 12, 2004 - 11:00 am UTC

no, you do not

remote_dependencies_mode

Js, July 28, 2004 - 3:47 am UTC

Hello Sir,
Does it mean .. IF we set remote_dependencies_mode
= Signature .. Then this error will not come [ ORA-04068 ]



Tom Kyte
July 28, 2004 - 8:16 am UTC

no, your state would still be destroyed -- this isn't just about an arbitrary compile of code -- this is a compilation of a piece of code that your session USED and had established a state (variable values) with. the compilation just wiped out your "memory" if you will -- this is the databases way of telling you "sorry, but you've just gotten amnesia"

Thanks :)

Js, July 28, 2004 - 9:09 am UTC


One Doubt

Js, July 29, 2004 - 2:40 am UTC

Hi,
Sir, If I use package with any variable ..
Then should this error not come ?

Thanks,

Re:

Js, July 29, 2004 - 7:50 am UTC

Sorry, Package .. Without any variable

Tom Kyte
July 29, 2004 - 11:56 am UTC

as long as the package didn't have a state, yes.

Cause of Invalid Package State

Js, July 30, 2004 - 12:52 am UTC

Is there any way to know the Cause of Invalid state of my
Package.


Thanks,

Tom Kyte
July 30, 2004 - 7:49 am UTC

we do not record why the package went invalid, only that it did.

Look at the things it is dependent on (dba_dependencies) and look at the last_ddl_times of those objects.

grants would be the other "big thing", a revoke can definitely cause cascading invalidations

Strange problem

A reader, November 22, 2004 - 12:03 pm UTC

I have a strange problem..

update t set col=col where rownum=1;

fails with the following error stack

ORA-4068
ORA-4065
ORA-6508
ORA-6512
ORA-4088

The ORA-6512 refers to a row-level before insert/update trigger.

If I disable the trigger, the update goes fine.

The trigger reads a global package variable

if (package.variable) ... end if;

If I do

exec package.variable := true (or even false)

update t set col=col where rownum=1; -- works fine!

So, it seems that the trigger is unable to load the package into memory? I tried flush shared pool, even restarted the instance, didnt help.

There are no invalid objects in any of the schemas being referenced.

So, I changed the trigger to

package.variable := false;
if (package.variable) ... end if;

This works fine!

Why would reading the package variable fail, but setting it and reading it succeed?

Help? Thanks



Tom Kyte
November 22, 2004 - 3:32 pm UTC

test case please. help me reproduce the issue.

Downsides?

Dc, November 22, 2004 - 2:11 pm UTC

Tom - what are the downsides to using "signature"?


Tom Kyte
November 22, 2004 - 4:13 pm UTC

I'm not really aware of any

Developer Forms siganture Problem

Paul, December 23, 2004 - 4:45 pm UTC

Hi Sir,

I need to ask about Developer Forms problem?

We have one software version for many clients, but somtime we get runtime message ... ORA-04062 (Signature has been changed)... on our forms ... and we have to recompile the form source ... but in some cases this is not posible because we don't have the apropiate enviroment... get it?

Now my question, Is there some way to catch (Database way maybe) why the signature problem is showing ?, in other words, How can I get the extactly declaration or specification or whatever, is causing the problem ... basically because we don't have the enviroment and the time to go watching into the code source...

Thanks in advanced,




Tom Kyte
December 23, 2004 - 7:41 pm UTC

please contact support for this, i haven't touched forms in a decade.

Revalidate state of package for all other sessons

Andrew, February 24, 2005 - 8:01 am UTC

Hi Tom,

Thanks for your answer, but I still have a question:
How I can revalidate state of changed package in all connected sessions (or some of them) to avoid ORA-04068?


Tom Kyte
February 24, 2005 - 8:28 am UTC

you have two choices:

a) don't maintain a state (you cannot "revalidate" a state, the client must know the state they depend on has been wiped out -- you would have to remove the need for a state to even exist)

b) don't compile code into a running production system.


I shouldn't even have called this an error in hindsight. It is not an error, it is a mandatory informational message your client application must receive so it can decide whether it needs to "stop" or not.

A reader, July 07, 2005 - 7:20 am UTC

create or replace package depds as
test_var number;
procedure a;
function x return number;
end;
/


create or replace package body depds as

procedure a
is begin
null;
end;

function x return number is
begin
return depds.test_var;
end;

begin
test_var := 3;
end depds;
/

Test Select statement
=====================
select depds.x from dual
/

3
Now if I get Ora 4061 and 4065 if I do the Test Select Statement from ANOTHER session.

But if I were in the SAME session and do following in given order

1) Run the SQL Select (returns value 3)
2)REcompile package body
3) Run the SQL Select again (returns value 3)

Question:

1) Am I right in saying that when I do step 3, it is actually reloading the package and hence I do not get an error.


---------------

Here's something I am not quite sure:

If in the other session

Question 2)
I understand this has LOST the current state values, is that why no matter HOW MANY times I do the Select, I still get 4061 and 4065 over and over again

Question 3) In this other session, is there any way to clear the package state and reload it with out getting 4061 and 4065 over and over again?


Tom Kyte
July 07, 2005 - 9:43 am UTC


ops$tkyte@ORA9IR2> select depds.x from dual;
select depds.x from dual
*
ERROR at line 1:
ORA-04061: existing state of package body "OPS$TKYTE.DEPDS" has been
invalidated
ORA-04065: not executed, altered or dropped package body "OPS$TKYTE.DEPDS"
 
 
ops$tkyte@ORA9IR2> select depds.x from dual;
select depds.x from dual
*
ERROR at line 1:
ORA-04061: existing state of package body "OPS$TKYTE.DEPDS" has been
invalidated
ORA-04065: not executed, altered or dropped package body "OPS$TKYTE.DEPDS"

 
<b>interesting, the select pgk.x from t is not sufficient, but:</b>
 
ops$tkyte@ORA9IR2> exec dbms_output.put_line( depds.x );
BEGIN dbms_output.put_line( depds.x ); END;
 
*
ERROR at line 1:
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "OPS$TKYTE.DEPDS" has been
invalidated
ORA-04065: not executed, altered or dropped package body "OPS$TKYTE.DEPDS"
ORA-06508: PL/SQL: could not find program unit being called
ORA-06512: at line 1
 
 
ops$tkyte@ORA9IR2> exec dbms_output.put_line( depds.x );
3
 
PL/SQL procedure successfully completed.


<b>using straight plsql it works as I would expect it to.

It does not reproduce in 10g however, there it works correctly</b>



 

A reader, July 07, 2005 - 7:35 am UTC

In retrospect can I ask that because Oracle puts the burden on the session that compiles and interrogates the variable, it is not returning an error?

Something like "Hey you know you are compiling it, and when you access the package AGAIN, you SHOULD KNOW you have lost the STate?"

After all, that session is losing its State as well, is it not?


Tom Kyte
July 07, 2005 - 9:45 am UTC

it looks like an issue in 9i, but fixed in 10g, please feel free to contact support to see if anything exists in 9i to patch it (might not, might never have been filed as a bug in 9i and before)

Followup question

Robert Martin, October 28, 2005 - 9:03 am UTC

I just got this error for the first time on one of my databases, my question would be:

In a RAC environment, how do you resolve this error? I ask this because I have some nightly jobs that call this procedure and pass it several different parameters for each pass. However, on some passes the job completed successfully and on some passes the job failed with the ORA-4068 error.

Is it possible that one node of the cluster is still holding the older state of the procedure and if so, will flushing the shared pool discard the cached copy or is there another way to ensure that the pre-existing state of the procedure gets ddiscarded from memory to avoid this error in the future?



Tom Kyte
October 28, 2005 - 1:09 pm UTC

the "state" here is a package state which is private to a SESSION, the session lives on a single node.


someone recompiled the code.

Followup to Followup

Robert Martin, October 28, 2005 - 3:59 pm UTC

Tom,

Just as an FYI - I ended up just dropping the procedure and recreating it in order to make the 4068 go away. I tried clearing all application sessions from the database and then allowing them to connect again but the error kept recurring over and over. Recompiling and Flushing and all other attempts were not successful.

Dropping and recreating is the only way around.

Tom Kyte
October 29, 2005 - 10:50 am UTC

coincidence more likely.


You destroyed the state, ever connected session would get the 4068 on their next attempt to execute the package - since you destroyed their state. Eventually, they would have fixed themselves - so, pure coincidence that the drop+create happened about the same time (guess on my part, a create or replace is not much different from a drop and create physically)

New question in regards to this same error code

Robert Martin, May 12, 2006 - 9:40 am UTC

Tom,

I currently have a procedure (call it PCD_A) in database A pointing at a synonym that in turn points to a procedure (call it PCD_n) in database B,C,D..x.

Now, in my procedure on database A I perform the following:

EXECUTE IMMEDIATE 'DROP DATABASE LINK DBLINK';
EXECUTE IMMEDIATE 'CREATE DATABASE LINK DBLINK USING '''||rec.db_name||''' ';
EXECUTE IMMEDIATE 'CREATE or replace SYNONYM PCD_ANY FOR PCD_n@DBLINK';

And with this procedure, it is supposed to loop through all records found in the cursor and execute the procedure in the remote database. However, I get the same ORA-04068 informational message after the procedure completes the first loop and tries to execute on subsequent records found in the cursor.

I tried adding the following within my LOOP in PCD_A

EXECUTE IMMEDIATE 'alter procedure PCD_A compile';

But with the procedure currently running, it is locked and will not recompile (thereby locking itself) on execution.

Do you see any way around this or have you ever tried doing this yourself?

Thanks Tom!

Tom Kyte
May 12, 2006 - 4:20 pm UTC

you would have to either

a) remove all session state from the affected packages (eg: NO GLOBALS)
b) call the packaged procedure twice (deal with the fact that state is gone)
c) don't use static SQL - break the dependency.



A reader, May 18, 2006 - 5:10 am UTC


detecting stateful packages

gho, March 31, 2008 - 9:43 am UTC

How can I detemine if a package is stateful or not (without analyzing the code)? Any system view getting this answer?


Tom Kyte
March 31, 2008 - 9:48 am UTC

analyzing code is going to be the only way. You'll need to look at the specifications and the bodies.


Getting ORA-04068 from SQL*Plus but not when called by DB JOB

Santanu, August 26, 2009 - 8:21 am UTC

Hi Tom,

Need help.

I am getting following msg when executing the package first time after a successful run. When executing second time solves the problem and execute successfully
And so on.
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "schema_name.package_name" has been invalidated
ORA-06508: PL/SQL: could not find program unit being called: "schema_name.package_name"

I am getting this error when executing from SQL*PLUS. But not when executing from the test window of PL/SQL developer tool OR by a Database JOB. I need to execute this package by a database job on daily basis.

This package is having 10 global variables, 7 local procedure in the pkg body(doing update, delete, insert, drop/create index), 1 main procedure declared in the pkg specification, 1 function called in the sql-query in one of the local procedures -- this function is also declared in the pkg specification also to get it available in the local procedure SQL query -

1. Can you pls let me know how to solve the problem?
2. As this package is required to be run by a db job everyday, can we live with it?


Thanks,
Santanu

Tom Kyte
August 26, 2009 - 7:25 pm UTC

1) you'd need to help me reproduce the issue. It would only happen if something caused the package to go invalid while the package runs - which should not be possible.

2) you are the only person on the planet that can answer that.

More info

Re-post, August 27, 2009 - 4:21 am UTC

Following are more details for you -
Data base is in RAC environment Oracle 10.2.0.3.0 - 64bit.
Data Load: 23million rows.

As per my understanding, session pkg state of the global variable is causing the issue. When executing with a DB JOB it should run in different session every time is it invoked.

Package xyz
procedure proc_MAIN;
function f_id return varchar2;
End package xyz;

Package body xyz
-- These 2 variables are only read inside all the local
-- procedure like constants.
v_1 number:=1000;
v_2 number:=10;
-- Data into these 4 variables are populated in the
-- Proc_main and used in other local procedures/functions.
v_3 varchar2;
v_4 varchar2;
v_5 varchar2;
v_6 varchar2;
-- Thses 4 variables are used for error handling. error raised from each local procedure/funcation and handeled in the proc_main.
v_7 varchar2;
v_8 varchar2;
v_9 varchar2;
v_10 varchar2;
Begin

Function f_id return varchar2
--code
End;

Procedure proc_exception_logger
-- Code
End;

Procedure proc_execution_logger
-- Code
End;

Procedure proc_send_email
--code
End;

procedure proc_audit_status
--code
End;

Procedure proc_update
--code
End;

procedure proc_insert
-- F_id function is called here from SQL query
End;

procedure proc_delete
--code
End;

Procedure Proc_MAIN
-- All the logic abut when and how to run dataload is in
-- the proc_MAIN.
-- All other procedures are called from Proc_MAIN.
Exception
-- All exception raised from other local procedure
-- handled here and saved into exception logger table.
End;
End package body xyz;

When we execute in a new session error occurred in the
Following sequence --
1. First time execute -- Success;
2. Second time execute --
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "schema_name.package_name" has been invalidated
ORA-06508: PL/SQL: could not find program unit being called: "schema_name.package_name"
3. Third time execute --Success
4. And so on.


1. Is there any way to solve the problem without making all the global variables Local and passing as parameters in the Local pkg procedures?
2. Is there any chance that it will cause the problem by throwing error when running by JOB? JOB called proc_MAIN every day.
3. Are there any other reasons behind it other than global variables are keeping state?

I think these are enough info for master like you.
Thanks

Tom Kyte
August 28, 2009 - 4:40 pm UTC

... I think these are enough info for master like you. ...

you are not correct.

You are doing something that invalidates the package in the package. Like I said, you'll need to give us something to reproduce with.

Few more info

Re-post, August 27, 2009 - 5:11 am UTC

There are 2 more local procedures in the package body as -

Procedure proc_create_index
--code
end;
procedure proc_drop_index
--code
end;

There is NO remote database connectivity in the package by dblink. Within the same database data fetched and inserted/updated into different schemas.

Not sure why package body is getting invalidated after one execution.







Tom Kyte
August 28, 2009 - 4:41 pm UTC

... Not sure why package body is getting invalidated after one execution....

and you have given me as much information as I will give to you in my question I'll ask of you:

my car won't start.

It is a white car, it has many pieces like wheels, windows, ignition switches. You should be able to use your knowledge of car to tell me why it won't start.


Error handling for ORA-04068

Jon Edwards, September 15, 2009 - 9:39 pm UTC

A few things I've observed about ORA-04068, would be interested to know if this is all expected:

1. ORA-04068 indicates the loss of *all* package state on the current session,
even for packages unrelated to the source of the error.

This loss of state is the same as if the session explicitly called DBMS_SESSION.RESET_PACKAGE.


2. ORA-04068 does not occur when the original error (e.g. ORA-06508) is caught and handled in PL/SQL code.

In this case, re-attempting the call will still fail, unless there's an explicit call to DBMS_SESSION.RESET_PACKAGE first.


I'd also like to know if there's any way to reinitialize just the invalidated state, rather than all state. Calling DBMS_SESSION.RESET_PACKAGE could have unexpected side-effects such as loss of output from DBMS_OUTPUT.

Tom Kyte
September 16, 2009 - 9:44 am UTC

give us an example to reproduce with please.


I did not follow you on this one. If I'm not mistaken, when I read this:

2. ORA-04068 does not occur when the original error (e.g. ORA-06508) is caught and handled in PL/SQL code.

I get the impression you are coding:

when others then null;

somewhere - and you haven't handled anything, you've really broken the code - so example please - or at least a level of detail sufficient to reproduce ourselves.

RE: Error handling for ORA-04068

Jon Edwards, September 16, 2009 - 8:13 pm UTC

Hi Tom,

This came up in a 'when others' handler in the main event loop of a daemon job. The handler logs the error and continues - a good use of 'when others' if ever I saw one.

Here's an example that illustrates both points...


Oracle 11.1.0.7.0
(also tested on 10.2.0.4.0 with the same results)

Test setup:

create or replace package gets_recompiled
as
  procedure do_stuff;
  call_count integer := 0;
end;
/

create or replace package body gets_recompiled
as
  version_ constant integer := 1;
  procedure do_stuff
  is
  begin
  call_count := call_count + 1;
  dbms_output.put_line('gets_recompiled version ' || version_ || ', call number ' || call_count);
  end;
end;
/

create or replace package caller
as
  procedure call_no_catch;
  procedure call_and_catch(do_reset boolean := false);
  call_count integer := 0;
end;
/

create or replace package body caller
as
  procedure call_no_catch
  is
  begin
  call_count := call_count + 1;
  dbms_output.put_line('caller call number ' || call_count);
  gets_recompiled.do_stuff;
  end;
  procedure call_and_catch(do_reset boolean := false)
  is
  begin
  call_count := call_count + 1;
  dbms_output.put_line('caller call number ' || call_count);
  gets_recompiled.do_stuff;
  exception
    when others then
      dbms_output.put_line(DBMS_UTILITY.FORMAT_ERROR_STACK);
      if do_reset then
        dbms_session.reset_package;
      end if;
  end;
end;
/


Test without catching error in PL/SQL - re-executing procedure works as expected:

SQL> -- session 1 (user)
SQL> exec dbms_session.reset_package;

PL/SQL procedure successfully completed.

SQL> set serveroutput on
SQL> exec caller.call_no_catch;
caller call number 1                                                            
gets_recompiled version 1, call number 1                                        

PL/SQL procedure successfully completed.

SQL> -- session 2 (operator)
SQL> create or replace package body gets_recompiled
  2  as
  3    version_ constant integer := 2;  -- new version
  4    procedure do_stuff
  5    is
  6    begin
  7    call_count := call_count + 1;
  8    dbms_output.put_line('gets_recompiled version ' || version_ || ', call number ' || call_count);
  9    end;
 10  end;
 11  /

Package body created.

SQL> -- session 1 (user)
SQL> exec caller.call_no_catch;
BEGIN caller.call_no_catch; END;

*
ERROR at line 1:
ORA-04068: existing state of packages has been discarded 
ORA-04061: existing state of package body "MDBOWN.GETS_RECOMPILED" has been 
invalidated 
ORA-04065: not executed, altered or dropped package body 
"MDBOWN.GETS_RECOMPILED" 
ORA-06508: PL/SQL: could not find program unit being called: 
"MDBOWN.GETS_RECOMPILED" 
ORA-06512: at "MDBOWN.CALLER", line 8 
ORA-06512: at line 1 


SQL> set serveroutput on
SQL> exec caller.call_no_catch;
caller call number 1                                                            
gets_recompiled version 2, call number 1                                        

PL/SQL procedure successfully completed.



Test with error caught in PL/SQL - re-executing procedure still fails:

SQL> -- session 1 (user)
SQL> exec dbms_session.reset_package;

PL/SQL procedure successfully completed.

SQL> set serveroutput on
SQL> exec caller.call_and_catch(false);
caller call number 1                                                            
gets_recompiled version 2, call number 1                                        

PL/SQL procedure successfully completed.

SQL> -- session 2 (operator)
SQL> create or replace package body gets_recompiled
  2  as
  3    version_ constant integer := 3;  -- new version
...
 11  /

Package body created.

SQL> -- session 1 (user)
SQL> exec caller.call_and_catch(false);
caller call number 2                                                            
ORA-04061: existing state of package body "MDBOWN.GETS_RECOMPILED" has been     
invalidated
ORA-04065: not executed, altered or dropped package body            
"MDBOWN.GETS_RECOMPILED"
ORA-06508: PL/SQL: could not find program unit being   
called: "MDBOWN.GETS_RECOMPILED"
                                               

PL/SQL procedure successfully completed.

SQL> exec caller.call_and_catch(false);
caller call number 3                                                            
ORA-04061: existing state of package body "MDBOWN.GETS_RECOMPILED" has been     
invalidated
ORA-04065: not executed, altered or dropped package body            
"MDBOWN.GETS_RECOMPILED"
ORA-06508: PL/SQL: could not find program unit being   
called: "MDBOWN.GETS_RECOMPILED"
                                               

PL/SQL procedure successfully completed.



Test with error caught in PL/SQL and reset packages - re-executing procedure works:

SQL> -- test with call_and_catch(true)
SQL> -- session 1 (user)
SQL> exec dbms_session.reset_package;

PL/SQL procedure successfully completed.

SQL> set serveroutput on
SQL> exec caller.call_and_catch(true);
caller call number 1                                                            
gets_recompiled version 3, call number 1                                        

PL/SQL procedure successfully completed.

SQL> -- session 2 (operator)
SQL> create or replace package body gets_recompiled
  2  as
  3    version_ constant integer := 4;  -- new version
...
 11  /

Package body created.

SQL> -- session 1 (user)
SQL> exec caller.call_and_catch(true);

PL/SQL procedure successfully completed.

SQL> -- note DBMS_OUTPUT output is lost here
SQL> set serveroutput on
SQL> exec caller.call_and_catch(true);
caller call number 1                                                            
gets_recompiled version 4, call number 1                                        

PL/SQL procedure successfully completed.


Tom Kyte
September 17, 2009 - 8:42 am UTC

... This came up in a 'when others' handler in the main event loop of a daemon job. The handler logs the error and continues - a good use of 'when others' if ever I saw one. ....

false, entirely false - an extremely, excessively BAD PRACTICE



do not, repeat: DO NOT use when others, that is a worst practice, a really "bad idea"(tm). The approach to never take.


do you understand the huge flaw in your logic, in your code? what you have done to the transactional capability of the database (You have lobotomized it, killed it, destroyed it)


I added to your example:

create sequence s;
create table t ( id number, msg varchar2(80) );



and changed all of your "dbms_output.put_line(" strings to "insert into t values ( s.nextval, "

Now, let's run your excessively fragile, faulty, unstable code:

ops$tkyte%ORA10GR2> connect /
Connected.
ops$tkyte%ORA10GR2> set linesize 1000
ops$tkyte%ORA10GR2> exec caller.call_and_catch(true);

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> set echo off
run @x 4

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> exec caller.call_and_catch(true);

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> exec caller.call_and_catch(true);

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> select * from t order by id;

        ID MSG
---------- --------------------------------------------------------------------------------
         1 caller call number 1
         2 gets_recompiled version 1, call number 1

         3 caller call number 2
         4 ORA-04061: existing state of package body "OPS$TKYTE.GETS_RECOMPILED" has been i

         5 caller call number 1
         6 gets_recompiled version 4, call number 1

6 rows selected.




Note, id=1,2 - success, transaction ran from start to finish.

Note, id=3,4 - ugh, we did half of our transaction - and it is still there! but the other half (UNBEKNOWN TO US) did not ever execute, we have no clue, no way to find out - data integrity = 0%

Note, id=5,6 - success, however, it falls on the heels of a half done transaction - we probably did the work of "caller" twice and didn't really realize it.




Now, if I FIX THE BUG IN YOUR CODE:

create or replace package body caller
as
  procedure call_no_catch
  is
  begin
  call_count := call_count + 1;
  insert into t values ( s.nextval, 'caller call number ' || call_count);
  gets_recompiled.do_stuff;
  end;
  procedure call_and_catch(do_reset boolean := false)
  is
  begin
  call_count := call_count + 1;
  insert into t values ( s.nextval, 'caller call number ' || call_count);
  gets_recompiled.do_stuff;
<b>  /*
  exception
    when others then
      insert into t values (s.nextval, substr(DBMS_UTILITY.FORMAT_ERROR_STACK,1,80) );
      if do_reset then
        dbms_session.reset_package;
      end if;
  */
  </b>end;
end;
/



and re-execute:

ops$tkyte%ORA10GR2> exec caller.call_and_catch(true);

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> set echo off
run @x 4

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> exec caller.call_and_catch(true);
BEGIN caller.call_and_catch(true); END;

*
ERROR at line 1:
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "OPS$TKYTE.GETS_RECOMPILED" has been invalidated
ORA-04065: not executed, altered or dropped package body "OPS$TKYTE.GETS_RECOMPILED"
ORA-06508: PL/SQL: could not find program unit being called: "OPS$TKYTE.GETS_RECOMPILED"
ORA-06512: at "OPS$TKYTE.CALLER", line 15
ORA-06512: at line 1


ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> exec caller.call_and_catch(true);

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> select * from t order by id;

        ID MSG
---------- --------------------------------------------------------------------------------
         1 caller call number 1
         2 gets_recompiled version 1, call number 1
         4 caller call number 1
         5 gets_recompiled version 4, call number 1




I get exactly, precisely, what I should get - what should happen.


id=1,2 - all is well, perfection

id=4,5 = all is well, perfection

failed transaction - the INVOKER, the client, the caller KNOWS "transaction failed". Not only do they know this, they also know "transaction failed, but database has be restored (rolled back) to a known stable state - exactly the state I put it in right before making the failed call"


Your when others - broke that all

Your when others - hate it, it is wrong, it is bad, it is inexcusable, it is extremely poor programming/error handling, it must be erased.

This is why I would like "when others" removed from the language specification altogether...



If you want that error logged on the server, FINE, but you MUST let the invoker know "I've died, you've been rolled back, all is well - we can recover - you just need to RETRY"


<b>
ops$tkyte%ORA10GR2> create table log( msg clob );

Table created.

ops$tkyte%ORA10GR2> create or replace procedure log_error
  2  as
  3      pragma autonomous_transaction;
  4  begin
  5      insert into log values ( dbms_utility.FORMAT_ERROR_BACKTRACE );
  6      COMMIT;
  7  end;
  8  /

Procedure created.
</b>
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> create or replace package body caller
  2  as
  3    procedure call_no_catch
  4    is
  5    begin
  6    call_count := call_count + 1;
  7    insert into t values ( s.nextval, 'caller call number ' || call_count);
  8    gets_recompiled.do_stuff;
  9    end;
 10    procedure call_and_catch(do_reset boolean := false)
 11    is
 12    begin
 13    call_count := call_count + 1;
 14    insert into t values ( s.nextval, 'caller call number ' || call_count);
 15    gets_recompiled.do_stuff;
 16<b>
 17    exception
 18      when others then
 19          log_error;
 20          raise;
 21    end;</b>
 22  end;
 23  /

Package body created.



and now:


ops$tkyte%ORA10GR2> exec caller.call_and_catch(true);

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> set echo off
run @x 4

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> exec caller.call_and_catch(true);
BEGIN caller.call_and_catch(true); END;

*
ERROR at line 1:
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "OPS$TKYTE.GETS_RECOMPILED" has been invalidated
ORA-04065: not executed, altered or dropped package body "OPS$TKYTE.GETS_RECOMPILED"
ORA-06508: PL/SQL: could not find program unit being called: "OPS$TKYTE.GETS_RECOMPILED"
ORA-06512: at "OPS$TKYTE.CALLER", line 20
ORA-06512: at line 1


ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> exec caller.call_and_catch(true);

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> select * from t order by id;

        ID MSG
---------- --------------------------------------------------------------------------------
         1 caller call number 1
         2 gets_recompiled version 1, call number 1
         4 caller call number 1
         5 gets_recompiled version 4, call number 1





we have the error logged, you can capture whatever you want - but (and this is key) the CLIENT MUST BE INFORMED

and all is reset without invoking that extremely "brain killing dbms_session.reset_package"

This is the correct and proper way to deal with this

when others then null - NO

RE: Error handling for ORA-04068

Jon Edwards, September 17, 2009 - 7:37 pm UTC

The 'when others' handler in the example isn't really the focus here - I just used one in the example to gloss over which specific error(s) would need to be caught to handle the call to the invalid package. This would include ORA-06508, but I'm not sure what else.

My expectation was that when a call to an invalidated (but valid) package fails, an ORA-04068 error would be raised and then the call could then be repeated without getting the same error. That's based on what I've read on this page and elsewhere.

However as my example illustrated, if the error gets caught in a PL/SQL block (and not re-raised), simply re-attempting the call doesn't work. It doesn't matter if the re-attempt is from the client or directly from PL/SQL. The ORA-04068 error never happens (why not?), and package state is not automatically reset.

If the error handler explicitly resets package state (e.g. with DBMS_SESSION.RESET_PACKAGE) and then exits without re-raising, then re-attempting the call *from the client* does work.

Unfortunately that doesn't mean that the PL/SQL code can catch the error, reset package state, and try again. I've now tried it - it doesn't work, and I still get the ORA-06508 every time.

So in short, it seems invalidated package errors can't be handled in PL/SQL alone - a return to the client is necessary. And that means any 'when others' handlers need to result in a prompt exit from PL/SQL, at least if you're wanting to recompile code on a live system.

Tom Kyte
September 18, 2009 - 10:26 am UTC

... The 'when others' handler in the example isn't really the focus here ...

it is to me, it is an extremely poor practice, the worst of the worst practices if you ask me. I am making it the focus.

... My expectation was that when a call to an invalidated (but valid) package fails, an ORA-04068 error would be raised and then the call could then be repeated without getting the same error. That's based on what I've read on this page and elsewhere. ...

you have to get the error back to the client - when the session state is erased - it is UNSAFE to continue, you go back to the client - let them know "hey, someone wiped out the state of a package - now, if you are smart enough and know that that is 'OK', you can just retry the procedure that failed, else - you raise an error all of the up to that end user thing and tell them 'ouch, something I cannot deal with happened, I'm going away now"

... If the error handler explicitly resets package state (e.g. with DBMS_SESSION.RESET_PACKAGE) and then exits without re-raising, then re-attempting the call *from the client* does work. ...

and as I demonstrated - if you DO NOT reset the package state, if you DO NOT hide this error, then re-attempting the call *from the client* does work.

Notice how our paragraphs ended exactly the same? the re-attempting from the client DOES WORK.

And in your case, the client is clueless that a horrendous error happened, the database state is left unstable, unknown transactionally.

And in my case, the client is totally aware of the issue, the database state is left in a stable, known state transactionally.


... And that means any 'when others' handlers need to result in a prompt exit from PL/SQL, at least if you're wanting to recompile code on a live system. ...

I don't know why you would have a when others not followed by RAISE - if you have when others NOT FOLLOWED BY RAISE, YOU HAVE A BUG IN YOUR CODE - PERIOD. IF YOU PUT RAISE IN THE WHEN OTHERS - everything works normally.

The only reason for you to have a when others in your code would be to

a) log the error using an autonomous transaction to be followed by the word:
b) RAISE;

and if you do that

a) your code is correct (does not have the when others bug YOUR EXISTING code has)

b) database is left in stable known state

c) you have made a record of the error

d) the client knows there was an error and the client knows to retry the transaction



development, production - I don't really care, the only way to deal with this is to let the error propagate back to the client - period.

why is serverout set to "off" when getting ora-04068 in sqlplus ?

Sokrates, January 26, 2011 - 2:48 am UTC

one really annoying thing about sqlplus is that serverout is set to off when one receives a ora-04068.

See:

session 1 > set serverout on
session 1 > create package abc is x number; end abc;
  2  /

Package created.

session 1 > exec abc.x := 17 ; dbms_output.put_line(abc.x)
17

PL/SQL procedure successfully completed.

in another session

session 2 > create or replace package abc is x number; y number; end abc;
  2  /

Package created.


in the first session again

session 1 > exec abc.x := 16; dbms_output.put_line(abc.x)
BEGIN abc.x := 16; dbms_output.put_line(abc.x); END;

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


I receive ORA-04068, that's ok.
So now I do
session 1 > exec abc.x := 18; dbms_output.put_line(abc.x)

PL/SQL procedure successfully completed.

oops - why doesn't sqlplus display "18" ? I try it again:
session 1 > exec dbms_output.put_line(abc.x)

PL/SQL procedure successfully completed.


it doesn't want to (seems it doesn't like me anymore :-), i have to tell it
session 1 > set serverout on

once again, and then
session 1 >  exec dbms_output.put_line(abc.x)
18

PL/SQL procedure successfully completed.

we are friends again

How comes it that serverout is set to "off" when getting ora-04068 ? Is there a cause for this behaviour ?
It seems to be a bug in my eyes
(but one get used to be annoyed by it when working with this for many years ...)


Tom Kyte
February 01, 2011 - 12:42 pm UTC

it seems to be a bug in sqlplus

Interestingly - the author of doc id 418270.1 must have known this since their example shows them issuing the serveroutput twice...

there is a bug filed against it - 560143 - but I don't see any action on it (low priority one).

When the session state is reset - it blows away all affected packages.

Run this in session 1:


drop package abc;
drop package def;

create package abc is x number; end abc;
/
create package def is x number := 55; end def;
/

exec abc.x := 17 ; def.x := 42; dbms_output.put_line(abc.x)
pause
exec dbms_output.put_line(abc.x)
set serveroutput on
exec dbms_output.put_line(def.x)


and when it pauses, run this in session 2:


create or replace package abc is /* new one */ x number; end abc;
/
exec abc.x := 17 ; dbms_output.put_line(abc.x)



and then resume session 1


You'll see 55 as the output. DBMS_OUTPUT looses it's session state too.... SQLPlus would have to call dbms_output.enable "special" after it hits an ora-4068.


Sokrates, February 01, 2011 - 1:02 pm UTC


Sokrates, February 03, 2011 - 2:01 am UTC

created a new SR for this issue

David N, October 13, 2011 - 5:28 pm UTC

I had the same ORA-04068 problem. Then I found that in some cases when we do not need persistent package state beyond server call we can use serially reusable packages to avoid "ORA-04068: existing state of packages has been discarded" error.

For SERIALLY_REUSABLE Packages please see documentation http://download.oracle.com/docs/cd/E11882_01/appdev.112/e25519/packages.htm#CJABACHJ

First we demonstrate error:

SQL> set serveroutput on;
SQL> drop table t1
  2  /

Table dropped.

SQL> create table t1 (n number)
  2  /

Table created.

SQL> create or replace package p1 as
  2     function get_gl_n return number;
  3  end p1;
  4  /

Package created.

SQL> create or replace package body p1 as
  2   gl_n number;
  3  function get_gl_n return number is
  4  begin
  5     return gl_n;
  6  end get_gl_n;
  7  begin
  8     select count(*) into gl_n from t1;
  9  end p1;
 10  /

Package body created.

SQL> exec dbms_output.put_line(p1.get_gl_n)
0

PL/SQL procedure successfully completed.

SQL> drop table t1
  2  /

Table dropped.

SQL> create table t1 (n number)
  2  /

Table created.

SQL> select object_type,status
  2  from user_objects
  3  where object_name='P1'
  4  /

OBJECT_TYPE         STATUS
------------------- -------
PACKAGE             VALID
PACKAGE BODY        INVALID

SQL> exec dbms_output.put_line(p1.get_gl_n)
BEGIN dbms_output.put_line(p1.get_gl_n); END;

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


SQL>

----------------

Now we make package SERIALLY REUSABLE:

SQL> set serveroutput on;
SQL> create or replace package p1 as
  2  PRAGMA SERIALLY_REUSABLE;
  3     function get_gl_n return number;
  4  end p1;
  5  /

Package created.

SQL> create or replace package body p1 as
  2  PRAGMA SERIALLY_REUSABLE;
  3   gl_n number;
  4  function get_gl_n return number is
  5  begin
  6     return gl_n;
  7  end get_gl_n;
  8  begin
  9     select count(*) into gl_n from t1;
 10  end p1;
 11  /

Package body created.

SQL> exec dbms_output.put_line(p1.get_gl_n);
0

PL/SQL procedure successfully completed.

SQL>
SQL> drop table t1
  2  /

Table dropped.

SQL> create table t1 (n number)
  2  /

Table created.

SQL> select object_type,status
  2  from user_objects
  3  where object_name='P1'
  4  /

OBJECT_TYPE         STATUS
------------------- -------
PACKAGE             VALID
PACKAGE BODY        INVALID

SQL> exec dbms_output.put_line(p1.get_gl_n);
0

PL/SQL procedure successfully completed.

SQL>

So no more ORA-04068 error

Thank you Tom for this site. You are the best.
Respectfully,
David N

Tom Kyte
October 14, 2011 - 11:08 pm UTC

I don't really like this approach - if they didn't need a state - why the HECK did they program one???

It is a really bad programming practice to use globals in the first place without a really good reason (maintaining state is one of the few really good reasons), but to have them and NOT NEED them - there is no reason for that.


but yes, serially reusable would tend to work, at the expense of unloading/reloading the package in the session state each call.

Can you detect this in advance?

Neil, October 19, 2011 - 11:11 am UTC

So I've compiled a package and have existing session. They will the correctly get the ORA-04068.

Is there anyway I can see this in any of the Oracle tables/tools? So that I can manually intervene on the app server and manually maintain the connection pool. Or cycle the app when necessarily. As they haven't written there code to handle it.
Tom Kyte
October 19, 2011 - 6:33 pm UTC

There is not, you would however know from experience (you've encountered the 4068 apparently, you KNOW they rely on session state) that you need to cycle your application servers after a patch.


Unless you use edition based redefinition in 11g R2 - you can avoid the 4068 entirely with that approach.

Respectfully disagree

Hilarion, December 13, 2011 - 4:32 pm UTC

I must say that I respectfully disagree to some of your statements Tom.

Regarding the statement that the client should be the one that always gets and handles the ORA-4068 errors:
If the client is an application/server, than that means that the logic, that decides if we can safely retry or not after ORA-4068 has to be coded into the application. If we are able to code it on the client side, then why shouldn't we be able to code it in PL/SQL? Yes, there are cases when coding it client-side is better (or even the only way), but that's not always the case.

Regarding the statement that if the package state can be safely reset, then we apparently did not need the state in the package anyway:
Package state can be there for performance reasons. Having it may save us some recalculations, SQL reexecutions, etc. and in case the state is dropped, we know that it was there only for performance, so we can safely retry the operations. Unfortunately "SERIALLY_REUSABLE" pragma does not help in such cases, because it makes Oracle not hold package state between executions, which does save us from state dropping errors on recompilation, but also in most cases kills performance gains we coded in it. I'd really like to see Oracle introducing new package level pragma (eg. "CAN_SAFELY_REINITIALIZE"), that'd tell Oracle that the package can be safely and automatically reinitialized when it's state invalidates.
The other case comes from package state definition. As you know, unfortunately package level defined constants are treated as part of package state. This means that even if a package does not have a logical state (no package variables and/or cursors, etc.) it still can hit ORA-4068. This is where "SERIALLY_REUSABLE" pragma comes handy.

Regarding the statement that "when others then null" is never a good thing and that suppressing errors in "when others then <not null>" is also a bad thing:
We have one case when "when others then null" seems valid. We had to write a package set that would serve for logging/tracing purposes. Main requirement was that it's use should never cause errors for it's caller even in cases that logging/tracing was not working correctly. We had to use "when other then null" in that package set to hide any errors that happen in it (eg. when logging is configured to use DBMS_OUTPUT and so much text was logged that we hit DBMS_OUTPUT buffer limits).
We also use "when others then something", that does not raise back the original error in procedures that are used only as scheduled jobs. The error handler does rollback any done work and logs the error. This solution prevents scheduled jobs entering "broken" state, which would cause much more damage than we can accept. In most cases "when others" is not the only handler in our "exception" block - we always try to react appropriately to the error, but "when others" is the necessary fall-back we have to use.

Regarding the statement that one can avoid ORA-4068 errors by cycling application(s) after patch:
We have applications that are required to work continuously for months and having to cycle it for more than 1% on-line users (thousands of users on-line at any time of day) is usually not acceptable. We had to write heaps of code client-side to handle ORA-4068. If there was any way to handle it on DB side, then it'd be much easier, because this way we could have handlers close to the error origin, which makes deciding if reinitialization and retry is safe (or not) much easier. Now each client-side handler has to have list of packages which state drop errors it can safely disregard and only one operation has to be retried and which can not and whole process has to start from scratch or user has to be informed about "critical error". Package level pragma "CAN_SAFELY_REINITIALIZE" would save us a lot of work, but still having a way to handle ORA-4068 in stored PL/SQL would have much use. There's also one more Oracle change that would benefit us a lot: Now Oracle drops state of all packages if one of those initialized in current session gets recompiled. It would be nice if Oracle only dropped state for the only ones that really changed (got directly or indirectly recompiled). This would also solve the problem with DBMS_OUTPUT getting reset after ORA-4068.


PS.: English is not my native language and I'm far from being good at it so there may be translation errors in my text above. Please ask if anything looks suspicious.
Tom Kyte
December 14, 2011 - 7:18 am UTC

If the client is an application/server, than that means that the logic, that decides if we can safely retry or not after ORA-4068 has to be coded into the application. If we are able to code it on the client side, then why shouldn't we be able to code it in PL/SQL? Yes, there are cases when coding it client-side is better (or even the only way), but that's not always the case.

You see - I am also a fan of never using commit or rollback (I've actually written that I wish commit and rollback were not part of the plsql language) in PLSQL. I do not believe a stored procedure knows when the transaction is truly done - only the CLIENT does.

I have a stored procedure "change_address". I have a stored procedure "change_contact_info". I would like to have a transaction that changes the address and contact info as a discrete unit or work. now, if the person that coded these procedures said "I know when the transaction is complete" - where do you think the commits would be? They'd be in the procedures of course. Which means I have to now code a third procedure.

if the stored procedure writes understood that they do not have enough knowledge to know when the transaction is truly over - this would not be a problem. I'd just call the two API's and then commit - viola, done.

I hate procedures that commit (dbms_scheduler - that means you)



Regarding the statement that if the package state can be safely reset, then we apparently did not need the state in the package anyway:
Package state can be there for performance reasons. Having it may save us some recalculations, SQL reexecutions, etc. and in case the state is dropped, we know that it was there only for performance, so we can safely retry the operations.


No, you cannot just safely retry the operation. In this case you must first know enough to invoke the code to perform the calculations and so on - the stuff must be reinitialized.


The other case comes from package state definition. As you know, unfortunately package level defined constants are treated as part of package state. This means that even if a package does not have a logical state (no package variables and/or cursors, etc.) it still can hit ORA-4068. This is where "SERIALLY_REUSABLE" pragma comes handy.

put your constants in a constant package - separate and distinct from your code, from your logic.

If a constant changes - that affects *everything*, so I would say if you replace a package of constants - everything is affected to its core, that is "game over player one". You'll have code that maybe set some globals (state) based on the old constants - that has to be invalidated.

If you use modular approaches, you can minimize this 4068 approach - even with constants.



Regarding the statement that "when others then null" is never a good thing

I was saying to never use when others the way the person used it, in their context. They swallowed ALL EXCEPTIONS (when they only meant to catch ONE) and treated all exceptions as if they were a 4068. *that is plain wrong, you cannot argue with that, that is plain wrong*.

would you code:

begin
select x into y from t where ...;
exception
when others then y := 42;
end;


No, no you would not because that would be ignorantly wrong, it would be beyond "not smart", it would be downright dumb. What you would code would be:


begin
select x into y from t where ...;
exception
when NO_DATA_FOUND then y := 42;
end;

you would catch and deal with the SINGLE exception you are expecting. the ONLY use of when others is:

a) to release a resource - and then follow with a RAISE/RAISE_APPLICATION_ERROR, for example:

begin
file := utl_file.fopen(..);
..
exception
when others
the
if utl_file.isopen(file) then utl_file.fclose(file); end if;
RAISE;
end;


b) to log an error, before re-raising the exception;

begin
...
exception
when others then
log_error_using_autonomous_transaction( .... );
RAISE;
end;


We had to use "when other then null" in that package set to hide any errors that happen in it (eg. when logging is configured to use DBMS_OUTPUT and so much text was logged that we hit DBMS_OUTPUT buffer limits).

You should have, you could have just erased that package then. You obviously DID NOT CARE ONE WHIT if that code executed or not, in fact you couldn't even tell if it did. So why bother calling it???? What was the point? It would execute sometimes and not other times and you couldn't tell, you couldn't rely on it so why even bother???

If you knew dbms_output was going to blow up and you didn't care about that - then you should have caught the error dbms_output throws when it blows up, you should NOT have used others. That is wrong, that is a bug in your code. Seriously - there is no argument to counter that. You are swallowing any and all exceptions when you meant to catch ONE.



. This solution prevents scheduled jobs entering "broken" state, which would cause much more damage than we can accept.

hah, that solution allows the job to forever fail and no one notices. If you say "but we have our log table", I will just say "but you have the error screaming at you in the alert log, you have errors in the scheduler table, you have the broken flag in the dictionary. You have many places screaming 'i am failing', you have many places that tools actually look (enterprise manager and related tools will not be querying your table will they? No, they'll look in the alert, in the dictionary to alert DBAs to the fact that something is wrong".

Better to let the job 'break' so a big red blinking light goes off (it takes like 16 broken runs to break a job) and someone fixes it. How many 'broken' runs will result with your approach (if you say the jobs fix themselves - the errors are temporary - then you don't have a problem in the first place - we'll retry the job over and over)



we always try to react appropriately to the error, but "when others" is the necessary fall-back we have to use.

I disagree 100% (I wish I could disagree more than 100% :( )



We have applications that are required to work continuously for months and having to cycle it for more than 1% on-line users (thousands of users on-line at any time of day) is usually not acceptable.

before 11g - how the heck did you do patching at all? Say your patch contained three related packages. How did you install them consistently? or are you saying it is ok for some transactions to use version 2 of package A with version 1 of packages B and C? If you didn't take a small maintenance window - that is exactly what they did!



In 11g you have edition based redefinition, which if used to patch, can remove the 4068 from consideration.

https://www.google.com/search?q=site%3Awww.oracle.com+kyte+edition+based+redefinition

Disagree again

Hilarion, December 14, 2011 - 6:55 pm UTC

I still do not agree. Some of your arguments do not speak to me (not sure of the translation).

You see - I am also a fan of never using commit or rollback (I've actually written that I wish commit and rollback were not part of the plsql language) in PLSQL. I do not believe a stored procedure knows when the transaction is truly done - only the CLIENT does.
I was referring to PL/SQL code deciding if it's safe to retry actions that this specific code does in case of package state being dropped. Yes, it usually involves rollbacks. We do those in our code. In most cases it's "rollback to savepoint", where savepoints were placed by the same code that is rolling back to them. We also have PL/SQL procedures/packages which are called only from client (never by other PL/SQL) that do commit or rollback. This saves us a lot of trouble if we have a transaction that lasts longer an there's risk that the connection between client and DB can be interrupted after the procedure call but before the client receives response and issues commit/rollback. And yes, the client knows how to reconnect after connection failure and check if the operation was done successfully or not.
So summing up: Whether a procedure knows or does not know how to handle transaction depends only on how the procedure was written. Do not assume that all of us can't write decent code. :)

No, you cannot just safely retry the operation. In this case you must first know enough to invoke the code to perform the calculations and so on - the stuff must be reinitialized.
You are right. When I said "retry the operations" I was also referring to doing all required initializations. In many cases those would happen automatically because they reside in package initialization code, which should get rerun by Oracle when package state was dropped and I decided to use it again (handled the ORA-4068 in some specific way).

put your constants in a constant package - separate and distinct from your code, from your logic.
We do that for all "public" constants (in package specification) but doing the same for "internal" constants (specified in package body) is something we want to avoid because it makes code less readable and hermetic.
I still do not understand why Oracle decided to have constants as part of package state. If it was and option (some pragma perhaps)... I know if my constants are related to package state or not. Why does Oracle has to be smarter than me in regards to my applications?

You obviously DID NOT CARE ONE WHIT if that code executed or not, in fact you couldn't even tell if it did. So why bother calling it????
Because if it works, then it helps. In analysing how some problem/error happened. If logging procedure worked (and it does in 99% cases and when it does not, it at least logs how the process started), then we have logs to analyse. If it does not, then we analyse data and code. No harm done. If we did like you say, then in all cases we'd be left with only code and data and no logs.

that solution allows the job to forever fail and no one notices
The point always is: Do you check your log tables / scheduler error log / alert logs? If you don't, then there's no good solution. We do check our log tables (and they check us - we get auto-notifications, SMSes, e-mails). What we can't do is to guarantee that we will look into them the same minute the error appears and correct all errors instantly. Our scheduled jobs do execute every minute. If they fail to do one of their tasks because of some unexpected error, then they skip that task and try to do next one. In most cases this means that most of the tasks do get done even if there is a bug in code that makes some tasks fail (we fit in our error margins). And yes, sometimes situation changes and the next time the job runs, it's able to do the previously failed task properly (still the error cause has to be analysed and removed). If they were coded to break on error, then someone would loose lot of money and we would loose our jobs.

before 11g - how the heck did you do patching at all
We are before 11g. We do our patching very carefully. We coded something like middle tier in PL/SQL (I already mentioned packages/procedures that handle transactions) that is called only directly from the client. it consists only of stateless code that - when changed - does not invalidate anything. Before installing a patch we substitute some middle tier code (related to the part that has to be patched) with prepared temporary code (which has no calls to main code and replies to all client requests that this function is on maintenance), then we install the patch and restore the original middle tier. The client that receives "under short maintenance" exception will retry it's actions until it succeeds (or fails with different error) and when it gets "under long maintenance", it informs user about it, showing expected time of maintenance (from exception details). This way we keep our users satisfied and are able to avoid most hiccups. Still sometimes we do have to stop everything, but that's only for scheduled big updates (or patching critical errors that cannot be patched other way but have to be patched ASAP).

In 11g you have edition based redefinition, which if used to patch, can remove the 4068 from consideration.
We do not use 11g yet and unfortunately I'm not familiar with "edition based redefinition". Will have to do some reading apparently.

Thank you for your comments and remarks. I'm always glad to read more from you. "Ask Tom" was and is great source of help for us.

Why only after 3 recompile thar ORA-04068 appears?

Al Ricafort, February 08, 2012 - 10:20 pm UTC

Hi Tom,

I've created a test package below:
------------
create or replace
PACKAGE TEST_PKG AS
v_number        number;
PROCEDURE testMethod(
   i_par1       IN  NUMBER,
   o_par1       OUT NUMBER
); 
END TEST_PKG;

create or replace
PACKAGE BODY TEST_PKG AS
PROCEDURE testMethod(
   i_par1       IN  NUMBER,
   o_par1       OUT NUMBER
)
IS
BEGIN
   SELECT i_par1 
   INTO v_number
   FROM DUAL;
   o_par1 := i_par1;
END testMethod;
END TEST_PKG;


Then I created the following sql scripts:

---
SQL> !cat x.sql
SELECT SYSDATE FROM DUAL;
DECLARE
  I_PAR1 NUMBER;
  O_PAR1 NUMBER;
BEGIN
  I_PAR1 := 1234;

  TEST_PKG.TESTMETHOD(
    I_PAR1 => I_PAR1,
    O_PAR1 => O_PAR1
  );
DBMS_OUTPUT.PUT_LINE('O_PAR1 = ' || O_PAR1);
END;
/

SQL> !cat y.sql
SELECT SYSDATE FROM DUAL;
alter package test_pkg compile;


Now I opened 2 sessions one running y.sql and the other x.sql alternately and the result puzzles me.


============================

------------
SESSION 1
------------
SQL> @y.sql
SYSDATE
-----------------
20120209 12:08:03
Package altered.

SQL> @y.sql
SYSDATE
-----------------
20120209 12:08:09

Package altered.

SQL> @y.sql
SYSDATE
-----------------
20120209 12:08:16

Package altered.

------------
SESSION 2
------------
SQL> @x.sql
SYSDATE
-----------------
20120209 12:08:06

PL/SQL procedure successfully completed.

SQL> @x.sql
SYSDATE
-----------------
20120209 12:08:12

PL/SQL procedure successfully completed.

SQL> @x.sql
SYSDATE
-----------------
20120209 12:08:20

DECLARE
*
ERROR at line 1:
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "OPS$BOM.TEST_PKG" has been
invalidated
ORA-04065: not executed, altered or dropped package body "OPS$BOM.TEST_PKG"
ORA-06508: PL/SQL: could not find program unit being called
ORA-06512: at line 7
============================

My question is why only after 3 recompilation attempts that ORA-04068 showed up? And it always happened on the 3rd run.

I was expecting that I would have gotten this error on my first recompilation.


Tom Kyte
February 08, 2012 - 11:34 pm UTC

I did it your way (two sessions, persistently connected) and I did it my one (one easy script to interleave them)

connect /

prompt #1
!sqlplus / @y
@x
prompt =====================================

prompt #2
!sqlplus / @y
@x
prompt =====================================

prompt #3
!sqlplus / @y
@x
prompt =====================================



In either case, the second @x failed


ops$tkyte%ORA11GR2> @test
Connected.
#1

SQL*Plus: Release 11.2.0.2.0 Production on Thu Feb 9 00:32:52 2012

Copyright (c) 1982, 2010, Oracle.  All rights reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options


Session altered.


SYSDATE
--------------------
09-feb-2012 00:32:52


Package altered.

Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options


Session altered.


SYSDATE
--------------------
09-feb-2012 00:32:52

O_PAR1 = 1234

PL/SQL procedure successfully completed.

=====================================
#2

SQL*Plus: Release 11.2.0.2.0 Production on Thu Feb 9 00:32:52 2012

Copyright (c) 1982, 2010, Oracle.  All rights reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options


Session altered.


SYSDATE
--------------------
09-feb-2012 00:32:52


Package altered.

Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options


Session altered.


SYSDATE
--------------------
09-feb-2012 00:32:52

DECLARE
*
ERROR at line 1:
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package "OPS$TKYTE.TEST_PKG" has been invalidated
ORA-04065: not executed, altered or dropped package "OPS$TKYTE.TEST_PKG"
ORA-06508: PL/SQL: could not find program unit being called:
"OPS$TKYTE.TEST_PKG"
ORA-06512: at line 7


=====================================
#3

SQL*Plus: Release 11.2.0.2.0 Production on Thu Feb 9 00:32:52 2012

Copyright (c) 1982, 2010, Oracle.  All rights reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options


Session altered.


SYSDATE
--------------------
09-feb-2012 00:32:52


Package altered.

Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options


Session altered.


SYSDATE
--------------------
09-feb-2012 00:32:52


PL/SQL procedure successfully completed.

=====================================

Why only after 3 recompile thar ORA-04068 appears?

Al Ricafort, February 09, 2012 - 8:04 pm UTC

Hi Tom,

We are using this version:
---
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.6.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.6.0 - Production
---

Is this related to that version 9 bug? Because if I run the script under 1 session it does not raise any exception.

So to sum up, if you compile/recompile a package with state then the state will be lost. If a session that called it before try to call it again it will be notified with ORA-4068 exception. If there is no call before the package is compiled/recompiled then no exception is raised.

Is my understanding here correct?


Tom Kyte
February 10, 2012 - 5:03 pm UTC

I dug up an old 9ir2 image and I agree that it should have failed the second time in that version, but it did not.


More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library