How can I pass status back from a trigger code??
Ravi Kumar, March 11, 2004 - 10:49 am UTC
Hi Tom,
We have an application in which the user selects a text file from his local client machine from the client application and makes a procedure call to the Oracle Database for each line of the file. The procedure inserts those values to a staging table. There is a "after insert each row" trigger on the staging table where some validations are done and updates/inserts someother main tables. If the validations fails, then trigger code raises an exception. Based on the exception, the procedure retuns the status to the client.
The reason for coding the trigger on the staging table is, the end user wants to see the progress of the file read and processing of the data.
Now, when the validations fail and the exception is raised, the orginal insert to the staging table is also not finished. How to handle this situation, if we want to make the insert into staging table happen and return the fail validation status back to the procedure and hence to the client? Or any other better solution to this situation.
Thanks in advance,
Ravi
March 11, 2004 - 2:05 pm UTC
I don't see why this is a trigger. why is this a trigger? for the end user to see progress doesn't need a trigger here.
sounds like procedure wants to
a) insert row REGARDLESS
b) do the code you currently have in trigger to figure out what message to return to client.
the trigger would only be used to "protect" the table from getting bad data inserted.
What would be a possible solution?
Ajeet, January 26, 2005 - 5:11 am UTC
Tom,
I have 2 tables on a oracle instance evnodsd1
they are like this
create table t1 (id number(9) not null , name varchar2(1) not null) ;
alter table t1 add constraint t1_pk primary key(id)
using index ;
create table t2 (dtl_id number(9) not null,id number(9) not null,dtl_name varchar2(3) not null) ;
alter table t2 add constraint t2_fk1 foreign key(id)
references t1(id) ;
alter table t2 add constraint t2_pk primary key(dtl_id,id)
using index ;
so t1 is parent of t2.
table t2 is populated using a pro*c program.
then I have a table t2_qa on a different oracle instance evnrdwq2 -- and I have a db link from evnodsd1 to this instance.
I have a trigger at table t2 of instance evnodsd1 and this trigger will populate t2_qa --code is like this
create or replace trigger t2_trg
before insert
on t2
referencing new as new old as old
for each row
--
declare
l_module varchar2(1024) ;
l_where varchar2(1024) ;
l_cnt1 number ;
l_cnt2 number ;
tran_exception exception ;
pragma exception_init(tran_exception,-02055) ;
--
begin
--
l_module := who_am_i ;
--
/* select count(*) into l_cnt1 from t1 where nvl(id,-1) = nvl(:new.id,-1) ;
if l_cnt1 <> 0 then */
insert into ops$rdetl.t2_qa@evnrdwq2
(
dtl_id ,id,name)
values (:new.dtl_id,:new.id,:new.dtl_name) ;
--end if ;
exception
when others then
rdo_log_error(l_module) ;
raise ;
end ;
/
so this inserts a row into t2_qa as after it is inserted into t2.
when the source program (pro*C) inserts a bad row such a row for which there is no partent record..I get
ORA-02055 and ORA-02067..I read about this..I know it is coming because there was a FK voilation during the insert into t2.
I have a workaround like this...that I check that if parent record exist in t1 for t2 then only insert..into t2_qa (in the trigger code itself).
(please see the commented code --that is my workaround for now --it does not look too good).
My question is --is there any other way to handle or resolve this problem -- How can my trigger know that --execute or fire only if the transaction on t2 was commited successfuly -- any oracle supplied solution -- Any thing neat than this one.i saw a mention of this in oracle server manual but could not actually get it working..as I am confused conceptually -- the hang up is -- How to know that the insert on the source table was succesful or not and how would my trigger will know this.
As this trigger will be executed millions times in a day.(in worst case -- average is less than million times).
also I have 7-8 such triggres and I want to do it in a better way --if any.
Any help would be great.
below are the insert statement I tried and the error i got.
insert into t1 values (1,'A') ;
commit ;
then when I tried to insert a row in t2..I got this error..
SQL> SQL>
SQL> insert into t2 values (1,2,'BB') ;
insert into t2 values (1,2,'BB')
*
ERROR at line 1:
ORA-02055: distributed update operation failed; rollback required
ORA-02291: integrity constraint (OPS$RDETL.T2_FK1) violated - parent key not
found
January 26, 2005 - 8:59 am UTC
why does it matter? who cares -- just raise an error. the insert isn't going to happen, why does it matter who raises it??
(and why are you trying to do syncronous replication -- yuck, fairly horrible stuff making it so your systems are really never available)
could not be more agree with you but..
Ajeet, January 26, 2005 - 10:54 am UTC
Tom,
I knew you will ask it ..yes the insert will not happen but the source program was written in pro*c before 8 years and they handle exceptions in strange way -- like if they get -2291 they do insert the parent records..but now because this new trigger they first get ora-2055 and so there process gets aborted..exit.I do not have a say in it --as customer don't want to change it.so honestly i want to do as good as I can think of.
so blame is on me..so I have trying to find a better way.
Any ideas -- most appreciated.
Thanks again
Ajeet
January 26, 2005 - 11:20 am UTC
don't syncronously replicate then, use snapshots (materialized views). better uptime, better availability, easier to manage
Agreed But..
Ajeet, January 26, 2005 - 11:50 am UTC
Tom,
Yes..I Should use the MV's or Stream ..but they have so much of application code which is pointing to these existing tables -- so hard to change all such tables.
I know it does not sound logical and even I am not convineced..but I am just another memeber in the project team--so back to my question -- in the given problem --can I do anything else --that is can i avoid that problem because of the trigger..Code remains same as I have given above.sorry if i am trying to be persistent on taking a wrong approach..but I want to learn a way to resolve this problem if any.
Thanks alot
Ajeet
January 26, 2005 - 1:19 pm UTC
not following you.
You create mv logs on the tables in questions (instead of hand coding a trigger, one that is not actually working we might add)
You create materialized views on the other site (instead of create table)
and there you code.
what tables "have to change"?
The Source table and Target table in question..
Ajeet, January 27, 2005 - 7:43 am UTC
Tom.
Both the source table on which I have a trigger and the target table -- which is being populated from Trigger ..all of these are in the production ..and I am trying to fix the trigger error which I have described in my above post..so I was trying to say the replacing the target table will not be easy for me as there are too many stakeholders ..so I want to fix the trigger so that it can work as described above.
I was trying to use your very first response in this thread --that is use dbms_job ..it sounds very cool except that my users want the data in target table immedietly --that is right after it comes to t2.
I know there are several ways -- i could have used stream..i could have used MV with refresh group and autocommit..my constraint is - I am allowed to change just the tiny part-- the trigger.
I am still in search of an answer/help.
Thanks
Ajeet
January 27, 2005 - 9:51 am UTC
I don't think you'll "get there from here"
the production code is broke
the fix is rather simple
syncronous replication is really bad.
sorry, don't know what else to say.
OK
Kumar, May 07, 2007 - 2:46 am UTC
Hi Tom,
Please check the below trigger.
This is only a sample test case.
Requirement is simple and it is
whatever rows that are inserted into table t with value x = 3
must be inserted into t_copy and ** when clause is mandatory **.
I am getting errors with this trigger.How to correct this?
SQL> create table t(x number,y date)
2 /
Table created.
SQL> create table t_copy as select * from t
2 /
Table created.
SQL> create or replace trigger ins_t_copy
2 after insert on t
3 for each row
4 when ( x = 3 )
5 begin
6 insert into t_copy select * from t;
7* end;
SQL> /
when ( x = 3 )
*
ERROR at line 4:
ORA-04076: invalid NEW or OLD specification
May 08, 2007 - 10:44 am UTC
when new.x
I generally find the documentation to be of great help in cases like this :)
http://docs.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_7004.htm#sthref7994 ...
WHEN Clause
Specify the trigger condition, which is a SQL condition that must be satisfied for the database to fire the trigger. See the syntax description of condition in Chapter 7, "Conditions". This condition must contain correlation names and cannot contain a query.
The NEW and OLD keywords, when specified in the WHEN clause, are not considered bind variables, so are not preceded by a colon (:). However, you must precede NEW and OLD with a colon in all references other than the WHEN clause..........