Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ORACLE "before update" trigger does not fire when column is changed within another trigger

I am using ORACLE 12c.

On a table I have 2 triggers, both "before update". One of the triggers fires while updating a column and within this trigger another column gets a new value. The second trigger should fire while updating this second column. But he did not.

create table TRIGGER_TEST
(
    col1 varchar2(64),
    col2 varchar2(64),
    col3 varchar2(64)
);

create or replace trigger TR_TRIGGER_TEST_1 
before update of COL1 on TRIGGER_TEST
for each row
begin
    dbms_output.put_line('here we are in TR_TRIGGER_TEST_1');
    :new.col2 := 'only testing';
end;
/

create or replace trigger TR_TRIGGER_TEST_2
before update of COL2 on TRIGGER_TEST
for each row
begin
    dbms_output.put_line('here we are in TR_TRIGGER_TEST_2');
    :new.col3 := 'trigger_test_2 has fired';
end;
/


insert into TRIGGER_TEST values ('1_col1','1_col2','1_col3');
select * from TRIGGER_TEST;

COL1                 COL2              COL3                                                    
----------------------------------------------------------------
1_col1               1_col2            1_col3                                                          

After I have inserted the row I perform an UPDATE. And I expect COL1= "now we will see", COL2="only testing" and COL3 = "trigger_test_2 has fired".

update TRIGGER_TEST set COL1 = 'now we will see';

But what I get is this:

select * from TRIGGER_TEST;


COL1                 COL2              COL3                                                    
----------------------------------------------------------------
now we will see      only testing      1_col3                                                          

Can anybody explain this to me? I am really sure, that with former ORACLE versions this szenario has worked. But now it does not.

like image 788
virtualbee Avatar asked Jun 07 '17 12:06

virtualbee


People also ask

Does an on update trigger have access to old and new variables?

UPDATE. An UPDATE trigger can refer to both OLD and NEW transition variables. INSERT. An INSERT trigger can only refer to a NEW transition variable because before the activation of the INSERT operation, the affected row does not exist in the database.

Is it possible to create the following trigger before or after update trigger for each row?

Old and new values are available in both BEFORE and AFTER row triggers. A new column value can be assigned in a BEFORE row trigger, but not in an AFTER row trigger (because the triggering statement takes effect before an AFTER row trigger is fired).

Is it possible to create the following trigger before or after update trigger for each row a yes b no?

you can have many before triggers -- each modifying the :new values. That entire referenced thread was the proof that you cannot be sure the trigger is fired only once for each row!

How do I know which column is updated in a trigger?

Using a SQL Server trigger to check if a column is updated, there are two ways this can be done; one is to use the function update(<col name>) and the other is to use columns_updated().


1 Answers

I am really sure, that with former ORACLE versions this szenario has worked.

It has not. I ran your code in 11gR2 and got the same result:

set serveroutput on

update TRIGGER_TEST set COL1 = 'now we will see';

here we are in TR_TRIGGER_TEST_1


1 row updated.

select * from TRIGGER_TEST;

COL1                           COL2                           COL3                          
------------------------------ ------------------------------ ------------------------------
now we will see                only testing                   1_col3                        

The before update of COL2 on TRIGGER_TEST is a DML event clause. You are creating simple DML triggers:

A DML trigger is created on either a table or view, and its triggering event is composed of the DML statements DELETE, INSERT, and UPDATE. ...

When you issue your update that DML causes the first trigger to fire. But when you assign a new value inside that trigger:

    :new.col2 := 'only testing';

.. that is not a DML statement - it is not a separate update.

If assigning a value in that way did cause a trigger to fire, then if you instead did:

    :new.col1 := 'something';

... then that first trigger would fire again, recursively, until you hit the error ORA-00036: maximum number of recursive SQL levels (50) exceeded. That would obviously be bad.

You will have to repeat the assignment of col3 in the first trigger if that is what you need to happen. For more complicated side-effects that you want to happen whether you hit either trigger, you could have a procedure that does any necessary actions (that don't affect this table), and then call that from both triggers. Although then you'd need a mechanism to make sure the procedure isn't called twice if a DML update touches both columns - which would cause both triggers to fire.

like image 75
Alex Poole Avatar answered Oct 23 '22 05:10

Alex Poole