I want to create trigger which should capture all error whatever it happens inside the trigger.
And it should store in some log table.
Here my challange is how to capture the error occur in DML statments.
THat DML statments error captured in log with respective table name along with column name and error message.
It should also caputre all other errors like no_data_found with exact line number.
Please look at my code below.
If any changes need tell us.
create or replace TRIGGER user_name.sample_trg
AFTER UPDATE ON user_name.transaction_tb
FOR EACH ROW
DECLARE
variable_ln number;
l_err varcha2(4000);
BEGIN
select column_value
into variable_ln
from tb1
where colum_1 = :NEW.colum_1
IF UPDATING THEN
INSERT
INTO hisotry_tb
(
column1,
column2,
column3,
column4,
)
VALUES
(
:NEW.column1,
:NEW.column2,
:NEW.column3,
:NEW.column4,
);
END IF;
IF INSERTING THEN
INSERT
INTO hisotry_tb
(
column5,
column6,
column7,
column8,
)
VALUES
(
:NEW.column5,
:NEW.column6,
:NEW.column7,
:NEW.column8,
);
END IF;
EXCEPTION
WHEN OTHERS THEN
l_err := DBMS_UTILITY.FORMAT_ERROR_STACK || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
INSERT INTO log (erro_msg, trigger_name, column_name)
VALUES (l_err, 'sample_trg', '?');
DBMS_OUTPUT.put_line (l_err);
END;
Related
I have an oracle trigger to insert data to another table. If i use single update query than it works however if i user multiple commands like update and insert it fails with error following error.
ORA-04091: table ADMIN_SMS_HANDLER is mutating, trigger/function may not see it
ORA-06512: at "ADMIN_SMS_TRIG", line 16
ORA-04088: error during execution of trigger 'ADMIN_SMS_TRIG'
This works.
CREATE OR REPLACE TRIGGER ADMIN_SMS_TRIG AFTER
INSERT ON ADMIN_SMS_HANDLER
FOR EACH ROW
DECLARE BEGIN
INSERT INTO SMS (
SMSID,
ANUMBER,
BNUMBER,
MSG,
APP
) VALUES (
SMSSEQ.NEXTVAL,
:NEW.SMS_FROM,
:NEW.SMS_TO,
:NEW.SMS_TEXT,
'APP'
);
END;
But this is not working
CREATE OR REPLACE TRIGGER ADMIN_SMS_TRIG AFTER
INSERT ON ADMIN_SMS_HANDLER
FOR EACH ROW
DECLARE BEGIN
INSERT INTO SMS (
SMSID,
ANUMBER,
BNUMBER,
MSG,
APP
) VALUES (
SMSSEQ.NEXTVAL,
:NEW.SMS_FROM,
:NEW.SMS_TO,
:NEW.SMS_TEXT,
'app'
);
UPDATE ADMIN_SMS_HANDLER
SET
SENT_DATE = SYSDATE,
SENT_STATUS = 1,
UPDATED_BY = 'trigger',
UPDATED_DATE = SYSDATE
WHERE
ID = :NEW.ID;
END;
The issue has nothing to do with multiple statements. The issue is that a row-level trigger (generally) cannot reference the table on which it is defined.
Assuming that the intention is to have the trigger automatically populate some columns, you would do that by directly setting values in the :new pseudo-record, i.e.
:new.sent_date := sysdate;
:new.sent_status := 1;
But since you want to modify data in the current row, you'd need to use a before insert trigger rather than an after insert trigger. Something like
CREATE OR REPLACE TRIGGER ADMIN_SMS_TRIG
BEFORE INSERT ON ADMIN_SMS_HANDLER
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO SMS (
SMSID,
ANUMBER,
BNUMBER,
MSG,
APP
) VALUES (
SMSSEQ.NEXTVAL,
:NEW.SMS_FROM,
:NEW.SMS_TO,
:NEW.SMS_TEXT,
'app'
);
:new.SENT_DATE := SYSDATE;
:new.SENT_STATUS := 1;
:new.UPDATED_BY := 'trigger';
:new.UPDATED_DATE := SYSDATE;
END;
I want to add exception handling within trigger.
I created Trigger as below.
I want to add exception handling within that. So that my trigger never failed if there are any invalid condition.
CREATE OR REPLACE TRIGGER system_notification_audit
AFTER
INSERT OR
UPDATE
on system_notification
FOR EACH ROW
begin
insert into system_notification_log
select :NEW.ID , :NEW.NAME, :NEW.Description, :NEW.PREFERENCE, :NEW.FREQUENCY,
:NEW.IS_HIGH, :NEW.IS_REQUIRED, :NEW.UPDATED_BY, :NEW.UPDATED_DATE
from dual
where :OLD.PREFERENCE <> :NEW.PREFERENCE
OR :OLD.FREQUENCY <> :NEW.FREQUENCY OR :NEW.IS_HIGH <> :OLD.IS_HIGH OR :NEW.IS_REQUIRED <> :OLD.IS_REQUIRED;
END;
Simply Ignoring an Exception isn't always a good way to design your program. At least log the errors somewhere for later observation.
Note that your INSERT statement can be rewritten using a simple insert ( without a select ) and an IF condition.
CREATE OR REPLACE TRIGGER system_notification_audit AFTER
INSERT OR UPDATE ON system_notification
FOR EACH ROW
BEGIN
IF
:old.preference <>:new.preference OR :old.frequency <>:new.frequency
OR :new.is_high <>:old.is_high OR :new.is_required <>:old.is_required
THEN
INSERT INTO system_notification_log (
id,
name,
description,
preference,
frequency,
is_high,
is_required,
updated_by,
updated_date
) VALUES (
:new.id,
:new.name,
:new.description,
:new.preference,
:new.frequency,
:new.is_high,
:new.is_required,
:new.updated_by,
:new.updated_date
);
END IF;
EXCEPTION WHEN OTHERS THEN
pr_trigger_logs(trig_name => 'system_notification_audit',
err_msg => DBMS_UTILITY.FORMAT_ERROR_BACKTRACE());
-- calling an error logging procedure.
END;
/
I won't give you the definition of procedure pr_trigger_logs. As an exercise, I'll let you come up with it!.
I have a table that i'm trying to populate via a plsql script (runs on plsql developer). The actual DML statement
is contained in a procedure inside a package. The procedure only inserts if the record doesn't exist yet.
It doesn't work. The part that checks for existence returns true after the first iteration of the script loop even if it doesn't actually exist in the table.
If i put the commit outside of the loop, nothing gets inserted at all and the existence checks return true for all iteration even if the table it empty.
When i try to simplify the insert with existence check to be in just one statement without the exception handling, i get the same outcome.
Please tell me what I'm doing wrong here.
CREATE OR REPLACE PACKAGE BODY some_package
IS
PROCEDURE add_to_queue(id IN NUMBER)
IS
pending_record VARCHAR2(1);
BEGIN
-- this part succeeds even if nothing matches the criteria
-- during the loop in the outside script
SELECT 'Y'
INTO pending_record
FROM dual
WHERE EXISTS (SELECT 'x' FROM some_queue smq
WHERE smq.id = id AND smq.status IS NULL);
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO some_queue (seqno, id, activity_date)
VALUES (some_sequence.nextval, id, SYSDATE);
WHEN OTHERS THEN
NULL;
END;
END some_package;
CREATE TABLE some_queue
(
seqno VARCHAR2(500) NOT NULL,
id NUMBER NOT NULL,
activity_date DATE NOT NULL,
status VARCHAR2(25),
CONSTRAINT some_queue_pk PRIMARY KEY (seqno)
);
-- script to randomly fill in the table with ids from another table
declare
type ids_coll_tt is table of number index by pls_integer;
ids_coll_table ids_coll_tt;
cursor ids_coll_cur is
select tab.id
from (select *
from ids_source_table
order by dbms_random.value ) tab
where rownum < 10;
begin
open ids_coll_cur;
fetch ids_coll_cur bulk collect into ids_coll_table;
close ids_coll_cur;
for x in 1..ids_coll_table.count
loop
some_package.add_to_queue(ids_coll_table(x));
commit; -- if this is here, the first iteration gets inserted
end loop;
-- commit; -- if the commit is done here, nothing gets inserted
end;
Note: I translated this code to be more generic for posting. Forgive me if there are any typos.
Update: even if i put everything inside the script and not use the package, i'm not able to properly check for existence and I get the same results.
I figured out the solution:
CREATE OR REPLACE PACKAGE BODY some_package
IS
PROCEDURE add_to_queue(p_id IN NUMBER)
IS
pending_record VARCHAR2(1);
BEGIN
-- this part succeeds even if nothing matches the criteria
-- during the loop in the outside script
SELECT 'Y'
INTO pending_record
FROM dual
WHERE EXISTS (SELECT 'x' FROM some_queue smq
WHERE smq.id = p_id AND smq.status IS NULL);
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO some_queue (seqno, id, activity_date)
VALUES (some_sequence.nextval, p_id, SYSDATE);
WHEN OTHERS THEN
NULL;
END;
END some_package;
changing the parameter name fixed it. I guess the compiler gets confused if it's the same name as the table field.
Don't name the parameter the same as the column (use a prefix like p_ or in_) and you can do it in a single statement if you use a MERGE statement self-joining on the ROWID pseudo-column:
CREATE OR REPLACE PACKAGE BODY some_package
IS
PROCEDURE add_to_queue(
in_id IN NUMBER
)
IS
BEGIN
MERGE INTO some_queue dst
USING ( SELECT ROWID AS rid
FROM some_queue
WHERE id = in_id
AND status IS NULL ) src
ON ( src.rid = dst.ROWID )
WHEN NOT MATCHED THEN
INSERT (seqno, id, activity_date)
VALUES (some_sequence.nextval, in_id, SYSDATE);
END;
END some_package;
I want include condition in my trigger, based on data from a table. As oracle to do allow subquery in trigger, how it can be achived. Please find my code below. Trans_code_master holds the list of valid code, which can be changed.
Thanks in advance for all your help.
CREATE OR REPLACE TRIGGER CUST_TRG
BEFORE INSERT OR UPDATE ON CUST_ALL_TRANS
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
WHEN (NEW.TRANSACTION_CODE IN(SELECT TRANS_CODE FROM TRANS_CODE_MASTER))
BEGIN
INSERT INTO CUST_DEPO_TRANS
(
CUST_ID
,AC_ID
,TRANSACTION_CODE
)
VALUES(
:NEW.CUST_ID
,:NEW.AC_ID
,:NEW.TRANSACTION_CODE
)
EXCEPTION
WHEN OTHERS THEN
-- Consider logging the error and then re-raise
RAISE;
END;
/
Its not possible in write query in when clause. Try the below way
CREATE OR REPLACE TRIGGER CUST_TRG
BEFORE INSERT OR UPDATE ON CUST_ALL_TRANS
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
V_CNT NUMBER;
BEGIN
SELECT COUNT(1) INTO V_CNT
FROM TRANS_CODE_MASTER
WHERE TRANS_CODE = NEW.TRANSACTION_CODE;
IF V_CNT > 0 THEN
INSERT INTO CUST_DEPO_TRANS
(
CUST_ID
,AC_ID
,TRANSACTION_CODE
)
VALUES(
:NEW.CUST_ID
,:NEW.AC_ID
,:NEW.TRANSACTION_CODE
)
END IF;
EXCEPTION
WHEN OTHERS THEN
-- Consider logging the error and then re-raise
RAISE;
END;
/
How can i correctly write a trigger for this task:
create or replace trigger M_t2
after insert on emp
begin
if ( to_char(sysdate,'DY' ) = 'TUE' ) then
dbms_output.put_line('cannot insert into emp on tuesday');
end if;
end;
/
This does not work as i am still able to insert like this:
insert into emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values('7935','BOLT','ANALYST',7698,sysdate,900,100,10);
dbms_output doesn't stop you doing anything, and you won't even see that message if your client isn't set up to show the output.
To prevent an action you'd need to raise an exception:
if ( to_char(sysdate,'DY' ) = 'TUE' ) then
raise_application_error(-20001, 'cannot insert into emp on tuesday');
end if;
The DY value is NLS-dependent so this could be circumvented by having a session with a different language, so you should take that into account using the optional third parameter to to_char(). It might as well be a before-insert trigger too:
create or replace trigger M_t2
before insert on emp
begin
if ( to_char(sysdate, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH' ) = 'TUE' ) then
raise_application_error(-20001, 'cannot insert into emp on tuesday');
end if;
end;
/
insert into emp ...
ERROR at line 1:
ORA-20001: cannot insert into emp on tuesday
ORA-06512: at "<schema>.N_T2", line 3
ORA-04088: error during execution of trigger '<schema>.M_T2'
Please look at this: http://www.techonthenet.com/oracle/triggers/after_insert.php
I think you must use :new clause and use variable