Trigger Type | Example |
BEFORE ROW / STATEMENT | BEFORE INSERT [FOR EACH ROW]) |
AFTER ROW / STATEMENT | AFTER UPDATE [FOR EACH ROW]) |
INSTEAD OF (* - applies to views only) | INSTEAD OF UPDATE |
System Event | BEFORE SHUTDOWN, AFTER STARTUP, SERVERERROR |
Client Event | AFTER LOGON, BEFORE CREATE |
SQL> CREATE TABLE t ( a VARCHAR2(10) ); Table created. SQL> CREATE TRIGGER t_trig 2 BEFORE INSERT ON t 3 FOR EACH ROW 4 BEGIN 5 NULL; 6 END t_trig; 7 / Trigger created. |
SQL> CREATE OR REPLACE TRIGGER t_trig 2 BEFORE INSERT OR UPDATE OR DELETE ON t 3 FOR EACH ROW 4 BEGIN 5 IF DELETING 6 THEN 7 NULL; 8 ELSIF UPDATING 9 THEN 10 NULL; 11 ELSIF INSERTING 12 THEN 13 NULL; 14 END IF; 15 END t_trig; 16 / Trigger created. |
SQL> CREATE OR REPLACE TRIGGER t_trig 2 AFTER INSERT ON t 3 FOR EACH ROW 4 BEGIN 5 IF :old.a <> :new.a 6 THEN 7 NULL; 8 END IF; 9 END t_trig; 10 / Trigger created. |
SQL> CREATE OR REPLACE TRIGGER t_trig 2 AFTER INSERT ON t 3 BEGIN 4 debug('OLD A : ' || :old.a); 5 debug('NEW A : ' || :new.a); 6 END t_trig; 7 / CREATE OR REPLACE TRIGGER t_trig * ERROR at line 1: ORA-04082: NEW or OLD references not allowed in table level triggers |
Trigger Type | :OLD | :NEW |
BEFORE INSERT | NULL | INSERTed value |
AFTER INSERT | NULL | INSERTed value |
BEFORE UPDATE | Value before UPDATE | Value after UPDATE |
AFTER UPDATE | Value before UPDATE | Value after UPDATE |
BEFORE DELETE | Value before DELETE | NULL |
AFTER DELETE | Value before DELETE | NULL |
insert into T1 values ( ... );either:
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.
ORA-04091: table XXXX is mutating, trigger/function may not see itThe reasons behind this are quite complex, and can be found in the Oracle Documentation. The main reason, however, is attempting to read from a table which is currently being acted upon by a statement, i.e.
SQL> INSERT INTO t 2 SELECT 3 user 4 FROM dba_objects 5 WHERE rownum < 10000; 9999 rows created. Elapsed: 00:00:00.05 |
SQL> CREATE TRIGGER t_trig 2 BEFORE INSERT ON t 3 FOR EACH ROW 4 BEGIN 5 :new.a := user; 6 END t_trig; 7 / Trigger created. SQL> INSERT INTO t 2 SELECT 3 NULL 4 FROM dba_objects 5 WHERE rownum < 10000; 9999 rows created. Elapsed: 00:00:05.04 |
SQL> CREATE TABLE t ( a VARCHAR2(10) ); Table created. SQL> CREATE OR REPLACE PROCEDURE p 2 AS 3 l_count NUMBER; 4 BEGIN 5 SELECT count(*) INTO l_count FROM dual IN_PROCEDURE; 6 END p; 7 / Procedure created. SQL> CREATE OR REPLACE TRIGGER t_trig 2 BEFORE INSERT ON t 3 FOR EACH ROW 4 DECLARE 5 l_count NUMBER; 6 BEGIN 7 SELECT COUNT(*) INTO l_count FROM dual IN_TRIGGER; 8 p; 9 END t_trig; 10 / Trigger created. |
SQL> ALTER SESSION SET SQL_TRACE=TRUE; Session altered. SQL> INSERT INTO t VALUES ('X'); 1 row created. SQL> / 1 row created. SQL> / 1 row created. SQL> / 1 row created. SQL> / 1 row created. SQL> ALTER SESSION SET SQL_TRACE=FALSE; Session altered. |
SELECT COUNT(*) FROM dual IN_TRIGGER call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 5 0.00 0.00 0 0 0 0 Execute 5 0.00 0.00 0 0 0 0 Fetch 5 0.00 0.00 0 15 0 5 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 15 0.00 0.00 0 15 0 5 SELECT count(*) FROM dual IN_PROCEDURE call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.01 0.00 0 0 0 0 Execute 5 0.00 0.00 0 0 0 0 Fetch 5 0.00 0.00 0 15 0 5 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 11 0.01 0.00 0 15 0 5 |
SQL> CREATE OR REPLACE TRIGGER t_trig 2 BEFORE INSERT ON t 3 FOR EACH ROW 4 CALL p 5 / Trigger created. |
SQL> CREATE OR REPLACE PROCEDURE p ( user_name OUT VARCHAR2 ) 2 AS 3 BEGIN 4 user_name := user; 5 END p; 6 / Procedure created. SQL> CREATE OR REPLACE TRIGGER t_trig 2 BEFORE INSERT ON t 3 FOR EACH ROW 4 CALL p(:new.a) 5 / Trigger created. SQL> INSERT INTO t 2 SELECT 3 NULL 4 FROM dba_objects 5 WHERE rownum < 10000; 9999 rows created. Elapsed: 00:00:05.04 |
CREATE OR REPLACE TRIGGER <trigger_name> AFTER LOGON ON DATABASE [ WHEN <condition> ] BEGIN <code_block>; END;An example to switch on SQL tracing for a particular user, would therefore be,
CREATE OR REPLACE TRIGGER sadmin_logon_trg AFTER LOGON ON DATABASE WHEN (user="SCOTT") -- remove this line to turn it on for all users. BEGIN EXECUTE IMMEDIATE 'ALTER SESSION SET SQL_TRACE = TRUE'; END; |
/* Create a table and autonomous transaction procedure to audit logons */ SQL> CREATE TABLE temp ( a VARCHAR2(10) ); Table created. SQL> CREATE PROCEDURE temp_proc 2 AS 3 PRAGMA AUTONOMOUS_TRANSACTION; 4 BEGIN 5 INSERT INTO temp VALUES ('LOGGED ON'); 6 COMMIT; 7 END temp_proc; 8 / Procedure created. /* Create the trigger */ SQL> CREATE OR REPLACE TRIGGER logon_trig 2 AFTER LOGON ON DATABASE 3 WHEN (user='ORAUSER') 4 BEGIN 5 temp_proc; 6 RAISE_APPLICATION_ERROR(-20000, 'Sorry, you cannot login'); 7 END logon_trig; 8 / Trigger created. SQL> TRUNCATE TABLE temp; Table truncated. SQL> REVOKE dba FROM orauser; Revoke succeeded. SQL> conn Enter user-name: orauser Enter password: *********** ERROR: ORA-00604: error occurred at recursive SQL level 1 ORA-20000: Sorry, you cannot login ORA-06512: at line 3 Warning: You are no longer connected to ORACLE. SQL> conn Enter user-name: sys Enter password: ************************ Connected. SQL> GRANT DBA TO ORAUSER; Grant succeeded. SQL> conn Enter user-name: orauser Enter password: *********** Connected. SQL> SELECT * FROM temp; A ---------- LOGGED ON LOGGED ON -- Second row proves that the trigger fires for the DBA login, even though the RAISE_APPLICATION_ERROR does not affect the logon process. 2 rows selected. |
SQL> CREATE OR REPLACE TRIGGER logon_trig 2 AFTER LOGON ON DATABASE 3 BEGIN 4 RAISE_APPLICATION_ERROR(-20000, 'Sorry, you cannot login'); 5 END logon_trig; 6 / Trigger created. SQL> CONN Enter user-name: orauser Enter password: *********** ERROR: ORA-00604: error occurred at recursive SQL level 1 ORA-20000: Sorry, you cannot login ORA-06512: at line 2 Warning: You are no longer connected to ORACLE. SQL> CONN Enter user-name: sys Enter password: ************************ Connected. |
CREATE OR REPLACE TRIGGER ddl_trigger AFTER CREATE OR ALTER OR DROP ON SCHEMA BEGIN INSERT INTO log SELECT ora_sysevent, ora_dict_obj_owner, ora_dict_obj_name, ora_dict_obj_type, TO_CHAR(sysdate,'FM DD/MON/YYYY HH:MI:SS AM'), machine, terminal, program, osuser FROM v$session WHERE audsid = TO_NUMBER(sys_context('userenv', 'sessionid')); END; |