A very good example for doing so is regular extraction of data for processing in a data warehouse. That's also the case which led to this post.
The setting is just slightly more complex: both, primary and standby site are RACs - of course when you plan to switchover/failover, they should be somehow similar. (And in case of a disaster, it's planned to failover an disable all not-so-important activities; warehouse extract would be one of those).
Also the offloaded activities are slightly more complex than a simple query. In this case PL/SQL code is included. According to the documentation, that's not an issue at all - it's still read only. But in this DB (11.2.0.4), it was an issue: Sometimes the result was not as expected.
Now I first need to define the expectation: in this special case, the ERROR is the expectation, and no error the wrong result. Whenever a package (with global variables) is changed in a session, all other sessions which initialized the package before the change, but called it afterwards, must get
04068, 00000, "existing state of packages%s%s%s has been discarded" // *Cause: One of errors 4060 - 4067 when attempt to execute a stored // procedure. // *Action: Try again after proper re-initialization of any application's // state.
Then the application can catch this error, re-initiate the package and continue.
that's how it should be.
But we sometimes had strange results in the test environment. After some investigation, we found it and I simplified it to this Testcase:
Testcase: (results are only shown when of any interest) INST1_ ... Instance1 INST2_ ... Instance2 PRI ... Primary DB ADG ... Active DataGuardit's important the sessions are not closed within the test!
prepare user:
SYS@INST1_PRI:
=============
-- create the user create user SR_TEST1 identified by "xxx" default tablespace users temporary tablespace temp; grant connect, create session, create procedure, create table to SR_TEST1; alter user SR_TEST1 quota unlimited on users;
SESSION1@INST1_PRI:
==================
-- connect & create objects connect SR_TEST1/"xxx" set serveroutput on create table tab1 (id number, ver varchar2(30)); insert into tab1 values (1, '_'); commit; create or replace PACKAGE PACK AS first_load date := to_date('3333-01-01 01:01:01', 'YYYY-MM-DD HH24:MI:SS'); PROCEDURE proc; END PACK; / CREATE OR REPLACE PACKAGE BODY PACK AS PROCEDURE proc AS BEGIN if first_load > sysdate then first_load := sysdate; end if; DBMS_OUTPUT.PUT_LINE('1: loaded first on ' || to_char(first_load,'YYYY-MM-DD HH24:MI:SS') ); NULL; END proc; END PACK; / update tab1 set ver='1' where id=1; commit; create or replace procedure proc1 is begin SR_TEST1.pack.proc; end; / -- test & initiate set serveroutput on exec SR_TEST1.proc1 select * from tab1; > 1: loaded first on 2017-03-15 09:52:00 > > PL/SQL procedure successfully completed. > select * from tab1; > > ID VER >---------- ------------------------------ > 1 1
SESSION2@INST2_PRI:
==================
-- connect & create objects connect SR_TEST1/"xxx" set serveroutput on -- test & initiate set serveroutput on exec SR_TEST1.proc1 select * from tab1; > 1: loaded first on 2017-03-15 09:53:00 > > PL/SQL procedure successfully completed. > select * from tab1; > > ID VER >---------- ------------------------------ > 1 1
SESSION3@INST1_ADG:
==================
-- connect & create objects connect SR_TEST1/"xxx" set serveroutput on -- here the redo apply is running select sid from v$session where program like '%MRP0%'; > SID >---------- > 2 -- test & initiate set serveroutput on exec SR_TEST1.proc1 > 1: loaded first on 2017-03-15 09:53:21 > > PL/SQL procedure successfully completed. > > select * from tab1; > > ID VER > ---------- ------------------------------ > 1 1
SESSION4@INST1_ADG:
==================
-- connect & create objects connect SR_TEST1/"xxx" set serveroutput on -- NO redo apply is running hereselect inst_id, sid from gv$session where program like '%MRP0%'; > no rows selected -- test & initiate set serveroutput on exec SR_TEST1.proc1 > 1: loaded first on 2017-03-15 09:54:00 > > PL/SQL procedure successfully completed. > > select * from tab1; > > ID VER > ---------- ------------------------------ > 1 1
SESSION1@INST1_PRI:
==================
-- change package body CREATE OR REPLACE PACKAGE BODY PACK AS PROCEDURE proc AS BEGIN if first_load > sysdate then first_load := sysdate; end if; DBMS_OUTPUT.PUT_LINE('2: loaded first on ' || to_char(first_load,'YYYY-MM-DD HH24:MI:SS') ); NULL; END proc; END PACK; / update tab1 set ver='2' where id=1; commit; -- test set serveroutput on exec SR_TEST1.proc1 select * from tab1; > 2: loaded first on 2017-03-15 09:55:51 > > PL/SQL procedure successfully completed. > > > ID VER > ---------- ------------------------------ > 1 2
SESSION2@INST2_PRI:
==================
-- test set serveroutput on exec SR_TEST1.proc1 SR_TEST1@EBSSID051 > BEGIN SR_TEST1.proc1; END; * ERROR at line 1: ORA-04068: existing state of packages has been discarded ORA-04061: existing state of package body "SR_TEST1.PACK" has been invalidated ORA-04065: not executed, altered or dropped package body "SR_TEST1.PACK" ORA-06508: PL/SQL: could not find program unit being called: "SR_TEST1.PACK" ORA-06512: at "SR_TEST1.PROC1", line 4 ORA-06512: at line 1 > select * from tab1; ID VER ---------- ------------------------------ 1 2 -- THIS Is the expected result
SESSION3@INST1_ADG:
==================
-- test & initiate set serveroutput on exec SR_TEST1.proc1 * ERROR at line 1: ORA-04068: existing state of packages has been discarded ORA-04061: existing state of package body "SR_TEST1.PACK" has been invalidated ORA-04065: not executed, altered or dropped package body "SR_TEST1.PACK" ORA-06508: PL/SQL: could not find program unit being called: "SR_TEST1.PACK" ORA-06512: at "SR_TEST1.PROC1", line 4 ORA-06512: at line 1 select * from tab1; ID VER ---------- ------------------------------ 1 2
SESSION4@INST1_ADG:
==================
-- test & initiate set serveroutput on exec SR_TEST1.proc1 1: loaded first on 2017-03-15 09:54:00 PL/SQL procedure successfully completed. select * from tab1; ID VER ---------- ------------------------------ 1 2-- HERE you see the update on the table is applied on ADG already, but the procedure output is still prefixed with 1: - not 2: as it should be.
SESSION4@INST2_ADG:
==================
-- to check: the package is there!
set pages 99
select text from all_source where name = 'PACK'
and type = 'PACKAGE BODY'
3 order by line;
TEXT
------------------------
PACKAGE BODY PACK AS
PROCEDURE proc AS
BEGIN
if first_load > sysdate then
first_load := sysdate;
end if;
DBMS_OUTPUT.PUT_LINE('2: loaded first on ' || to_char(first_load,'YYYY-MM-DD HH24:MI:SS') );
NULL;
END proc;
END PACK;
12 rows selected.
Even the testcase is clear and simple, it was not that easy to identify the root cause in a more complex life environment. Special thanks to Andy Sayer who helped me to sort and refine my ideas over twitter.
With this testcase I was able to open a SR at Oracle, and after some some Support-ping-pong I got a useful information:
It is known as Bug: 18357555: ADD SUPPORT FOR KGLIV_BRNULPALL TO KGLCLUSTERMESSAGE() / KQLMBIVG()
I'm only aware of one Patch:25808607 (for PSU:11.2.0.4.160419 - together with some other patches) which is available right now. But you can ask for your own, if you have an Active Dataguard and RAC, and Packages with global variables.
Keine Kommentare:
Kommentar veröffentlichen