Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, George.

Asked: August 02, 2000 - 11:32 am UTC

Last updated: July 23, 2003 - 10:02 am UTC

Version: Oracle 8i

Viewed 10K+ times! This question is

You Asked

Tom,
Are cascading triggers all subject to the commit/rollback of the initiating task? If a task updates a table that has a trigger associated with it that update a second table that has a trigger associated with ... are all updates subject to the initiating tasks commit/rollback.
What if the last trigger executes a PL/SQL procedure that writes a flat ascii file to disk, is this all part of the initiating tasks' response time?

and Tom said...

Historically and by default -- YES. Triggers are considered all part of the same exact transaction.


Not only are they part of the transaction but they are atomic with respect to the firing statment. What I mean by that is if you have tables T1, T2 and T3 and table T1 has a trigger to insert into T2 and T2 has one to insert into T3 and you execute:

insert into T1 values ( ... );

either:

o both triggers and all three INSERTS succeed or
o all fail and are undone.

the insert is atomic -- its sideeffects (the triggers) are part of it. Either all of the triggers fire and succeed or they are all undone. To take that further lets say you execute:


insert into some_table values ( ... ); /* this succeeds */
insert into t1 values ( .... ); /* this fails */


After executing these two statements -- the work done by the second insert is "undone" (including any side effects from the triggers) but the work done by the FIRST insert is still there -- you need to either commit it or roll it back.


Now, there are somethings you can do in plsql that are not transactional -- writing to a file for example, or changing the value of a global variable in a package. These operations are NOT undone -- only the inserts/updates/deletes you do are. Therefore, if the trigger writes to an ascii file -- then closes the file and then FAILS -- the file will still exist, we cannot roll that back. In cases like this where I want the file to exists IF and ONLY IF the transaction succeeds, I use DBMS_JOB to schedule the procedure to write the file right AFTER I commit. In that fashion -- that operation that cannot be rolled back will execute after I succeed (and if it fails, the job queues will report the error to me via enterprise manager or a simple query).

In the beginning, I said "historically". Starting with Oracle8i, release 8.1 -- it is possible to have an "autonomous" transaction. they break this rule. See

</code> http://asktom.oracle.com/~tkyte/autonomous/index.html <code>
for info on that feature.


Rating

  (3 ratings)

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

Comments

Triggers

Mahomed, April 12, 2002 - 7:57 am UTC

Is there any way of passing the 'new' and 'old' data structures that are available
in triggers directly to another stored procedure instead of the way I am doing
currently as follows :

create or replace trigger trg_pallet_adiufer
after delete or insert or update on pallet for each row
declare
o_pallet pallet%rowtype := null;
n_pallet pallet%rowtype := null;
l_retval number;
BEGIN
pkg_lib.lib_trace( 'TRPALLET', 2, ' old.intpal = ' || to_char(nvl(:old.intpal,-1)) ||
' new.intpal = ' || to_char(nvl(:new.intpal,-1)) );

if ( not deleting )
then
n_pallet.agvtrk := :new.agvtrk;
n_pallet.bastyp := :new.bastyp;
n_pallet.batref := :new.batref;
n_pallet.bbfdat := :new.bbfdat;
n_pallet.calwgt := :new.calwgt;
n_pallet.cltcde := :new.cltcde;
n_pallet.cltpon := :new.cltpon;
n_pallet.copdat := :new.copdat;
n_pallet.datrcv := :new.datrcv;
n_pallet.dstasl := :new.dstasl;
n_pallet.dstblk := :new.dstblk;
n_pallet.dstcol := :new.dstcol;
n_pallet.dstdep := :new.dstdep;
n_pallet.dstlvl := :new.dstlvl;
n_pallet.dstsid := :new.dstsid;
n_pallet.imvnum := :new.imvnum;
n_pallet.intpal := :new.intpal;
n_pallet.intrct := :new.intrct;
n_pallet.itmcde := :new.itmcde;
n_pallet.labsid := :new.labsid;
n_pallet.mhetrk := :new.mhetrk;
n_pallet.numcas := :new.numcas;
n_pallet.numinc := :new.numinc;
n_pallet.palbas := :new.palbas;
n_pallet.palhgt := :new.palhgt;
n_pallet.palnum := :new.palnum;
n_pallet.paltyp := :new.paltyp;
n_pallet.palwgt := :new.palwgt;
n_pallet.pcktyp := :new.pcktyp;
n_pallet.piklin := :new.piklin;
n_pallet.pikref := :new.pikref;
n_pallet.prddat := :new.prddat;
n_pallet.qtyuom := :new.qtyuom;
n_pallet.rakasl := :new.rakasl;
n_pallet.rakblk := :new.rakblk;
n_pallet.rakcol := :new.rakcol;
n_pallet.rakdep := :new.rakdep;
n_pallet.raklvl := :new.raklvl;
n_pallet.raksid := :new.raksid;
n_pallet.rctlin := :new.rctlin;
n_pallet.rejtxt := :new.rejtxt;
n_pallet.rotdat := :new.rotdat;
n_pallet.rotsec := :new.rotsec;
n_pallet.rsvcde := :new.rsvcde;
n_pallet.sscode := :new.sscode;
n_pallet.stdpal := :new.stdpal;
n_pallet.stscde := :new.stscde;
n_pallet.stsrea := :new.stsrea;
n_pallet.trndat := :new.trndat;
n_pallet.trnsts := :new.trnsts;
n_pallet.usedat := :new.usedat;
n_pallet.whscde := :new.whscde;
end if;
if ( not inserting )
then
o_pallet.agvtrk := :old.agvtrk;
o_pallet.bastyp := :old.bastyp;
o_pallet.batref := :old.batref;
o_pallet.bbfdat := :old.bbfdat;
o_pallet.calwgt := :old.calwgt;
o_pallet.cltcde := :old.cltcde;
o_pallet.cltpon := :old.cltpon;
o_pallet.copdat := :old.copdat;
o_pallet.datrcv := :old.datrcv;
o_pallet.dstasl := :old.dstasl;
o_pallet.dstblk := :old.dstblk;
o_pallet.dstcol := :old.dstcol;
o_pallet.dstdep := :old.dstdep;
o_pallet.dstlvl := :old.dstlvl;
o_pallet.dstsid := :old.dstsid;
o_pallet.imvnum := :old.imvnum;
o_pallet.intpal := :old.intpal;
o_pallet.intrct := :old.intrct;
o_pallet.itmcde := :old.itmcde;
o_pallet.labsid := :old.labsid;
o_pallet.mhetrk := :old.mhetrk;
o_pallet.numcas := :old.numcas;
o_pallet.numinc := :old.numinc;
o_pallet.palbas := :old.palbas;
o_pallet.palhgt := :old.palhgt;
o_pallet.palnum := :old.palnum;
o_pallet.paltyp := :old.paltyp;
o_pallet.palwgt := :old.palwgt;
o_pallet.pcktyp := :old.pcktyp;
o_pallet.piklin := :old.piklin;
o_pallet.pikref := :old.pikref;
o_pallet.prddat := :old.prddat;
o_pallet.qtyuom := :old.qtyuom;
o_pallet.rakasl := :old.rakasl;
o_pallet.rakblk := :old.rakblk;
o_pallet.rakcol := :old.rakcol;
o_pallet.rakdep := :old.rakdep;
o_pallet.raklvl := :old.raklvl;
o_pallet.raksid := :old.raksid;
o_pallet.rctlin := :old.rctlin;
o_pallet.rejtxt := :old.rejtxt;
o_pallet.rotdat := :old.rotdat;
o_pallet.rotsec := :old.rotsec;
o_pallet.rsvcde := :old.rsvcde;
o_pallet.sscode := :old.sscode;
o_pallet.stdpal := :old.stdpal;
o_pallet.stscde := :old.stscde;
o_pallet.stsrea := :old.stsrea;
o_pallet.trndat := :old.trndat;
o_pallet.trnsts := :old.trnsts;
o_pallet.usedat := :old.usedat;
o_pallet.whscde := :old.whscde;
end if;

l_retval := pkg_libpal.pallet_change('TRPALLET',1,o_pallet,n_pallet);

END;
/



Tom Kyte
April 12, 2002 - 8:47 am UTC

nope, i use sql to write sql to automate the generation of the above trigger.

Cascading Triggers

Bhupinder, July 18, 2003 - 11:12 am UTC

Dear Tom,
That was really very informative.
But,if Oracle can do cascade trigger firing? (I believe so,
but is there max level?)
Example:
Table A has an insert trigger
Table B has an update trigger

in Table A's insert trigger has SQL to update table
B.
If table B's update trigger will fire?

Put more complicate if there is table C with insert
trigger and in TableB's update trigger insert table
C....etc..etc.

How far the level can be cascaded?


Tom Kyte
July 19, 2003 - 11:17 am UTC

the level will go as deep as you have the ability to open cursors for -- so open-cursors will ultimately determine the depth.

A reader, July 23, 2003 - 10:02 am UTC


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