fire_once
property of the trigger:- If the trigger
fire_once
isTRUE
, then the trigger is not executed by an apply process - If the trigger
fire_once
isFALSE
, then the trigger is suppose to be always executed, wether that's a regular DML/DDL command or an Streams apply process performing the change
To build the test case, we'll implement a simple Streams One-Way Replication. To do it in 10 minutes, assuming your database is in archivelog, follow Step 1 to Step 9 of the "Oracle Streams One Way Table Replication 101" post. Ready?
Test when fire_once
is TRUE
(i.e. Default)
To begin, we'll create a table and a trigger in the DESTINATION
schema; we'll check if the trigger is supposed to fire ONCE or ALWAYS:connect / as sysdbaSo that's really the default and that trigger is not supposed to be executed by an apply process. But before, we can test the trigger is working fine by inserting a value in the
create table destination.t1_x
(id number primary key,
text varchar2(80));
create or replace trigger destination.t1_x_trigger
after insert on destination.T1 for each row
begin
insert into T1_X(id, text)
values (:new.id, :new.text);
end;
/
set serveroutput on
begin
if (dbms_ddl.IS_TRIGGER_FIRE_ONCE('DESTINATION', 'T1_X_TRIGGER'))
then
dbms_output.put_line('Trigger FIRE_ONCE=TRUE');
else
dbms_output.put_line('Trigger FIRE_ONCE=FALSE');
end if;
end;
/
Trigger FIRE_ONCE=TRUE
DESTINATION.T1
table manually (That will make the 2 tables diverge but who cares?):insert into DESTINATION.T1Now that we are sure the tigger is working fine, we can test the trigger is not executed by the apply process. We'll change the
values (9999, 'Text 9999');
commit;
select *
from DESTINATION.T1_X;
ID TEXT
---- ---------
9999 Text 9999
SOURCE.T1
table this time and will check the values in changed on the DESTINATION.T1
but not in DESTINATION.T1_X
as expected:insert into SOURCE.T1Very good!
values (4, 'Text 4');
commit;
pause
select *
from DESTINATION.T1;
ID TEXT
---- ---------
1 Text 1
2 Text 2
3 Text 3
9999 Text 9999
4 Text 4
select *
from DESTINATION.T1_X;
ID TEXT
---- ---------
9999 Text 9999
Test when fire_once
is FALSE
Now we'll change the trigger's behavior and we'll perform another test to see if the trigger is executed when the change is applied to the DESTINATION.T1
table:beginBut wait a minute! Wasn't that trigger supposed to be executed? Let's restart all the processes to see if anything changes:
DBMS_DDL.SET_TRIGGER_FIRING_PROPERTY(
trig_owner => 'DESTINATION',
trig_name => 'T1_X_TRIGGER',
fire_once => false);
end;
/
set serveroutput on
begin
if (dbms_ddl.IS_TRIGGER_FIRE_ONCE('DESTINATION', 'T1_X_TRIGGER'))
then
dbms_output.put_line('Trigger FIRE_ONCE=TRUE');
else
dbms_output.put_line('Trigger FIRE_ONCE=FALSE');
end if;
end;
/
Trigger FIRE_ONCE=FALSE
insert into SOURCE.T1
values (5, 'Text 5');
commit;
pause
select *
from DESTINATION.T1;
ID TEXT
---- ---------
1 Text 1
2 Text 2
3 Text 3
9999 Text 9999
4 Text 4
5 Text 5
select *
from DESTINATION.T1_X;
ID TEXT
---- ---------
9999 Text 9999
exec dbms_capture_adm.stop_capture('STREAMS_CAPTURE');No, Same Story! Actually, I had to recreate the trigger to make it work:
exec dbms_apply_adm.stop_apply('STREAMS_APPLY');
exec dbms_capture_adm.start_capture('STREAMS_CAPTURE');
exec dbms_apply_adm.start_apply('STREAMS_APPLY');
set serveroutput on
begin
if (dbms_ddl.IS_TRIGGER_FIRE_ONCE('DESTINATION', 'T1_X_TRIGGER'))
then
dbms_output.put_line('Trigger FIRE_ONCE=TRUE');
else
dbms_output.put_line('Trigger FIRE_ONCE=FALSE');
end if;
end;
/
Trigger FIRE_ONCE=FALSE
insert into SOURCE.T1
values (6, 'Text 6');
commit;
select *
from DESTINATION.T1;
2
ID TEXT
---- ----------
1 Text 1
2 Text 2
3 Text 3
9999 Text 9999
4 Text 4
5 Text 5
6 Text 6
select *
from DESTINATION.T1_X;
ID TEXT
---- ----------
9999 Text 9999
exec dbms_apply_adm.stop_apply('STREAMS_APPLY');Expected Behavior? Bug? I'm still split! What do you think? btw, don't forget to clean up your Streams configuration.
drop trigger destination.t1_x_trigger;
create or replace trigger destination.t1_x_trigger
after insert on destination.T1 for each row
begin
insert into T1_X(id, text)
values (:new.id, :new.text);
end;
/
begin
DBMS_DDL.SET_TRIGGER_FIRING_PROPERTY(
trig_owner => 'DESTINATION',
trig_name => 'T1_X_TRIGGER',
fire_once => false);
end;
/
set serveroutput on
begin
if (dbms_ddl.IS_TRIGGER_FIRE_ONCE('DESTINATION', 'T1_X_TRIGGER'))
then
dbms_output.put_line('Trigger FIRE_ONCE=TRUE');
else
dbms_output.put_line('Trigger FIRE_ONCE=FALSE');
end if;
end;
/
Trigger FIRE_ONCE=FALSE
exec dbms_apply_adm.start_apply('STREAMS_APPLY');
insert into SOURCE.T1
values (7, 'Text 7');
commit;
select *
from DESTINATION.T1;
ID TEXT
---- ----------
1 Text 1
2 Text 2
3 Text 3
9999 Text 9999
4 Text 4
5 Text 5
6 Text 6
7 Text 7
select *
from DESTINATION.T1_X;
ID TEXT
---- ----------
9999 Text 9999
7 Text 7
Well, you got it working, right ? Then, in Oracle acception, this is not a bug anymore...
ReplyDeleteFiring trigger is one way to track the arrival of data at destination , empty column to be update only by trigger like heartbeat table.
ReplyDelete