在写一个AFTER SUSPEND触发器的时候碰到了一个很有趣的现象。
寻找导致问题的原因。
上一篇文章介绍了,如果当前用户下的触发器出现了编译错误,则会导致其他触发器也无法触发,即使当前触发器被删除。
是什么原因导致了这种情况的产生,怀疑可能与触发器的运行顺序有关,由于触发器的运行是根据触发器的建立顺序,下面将SYS用户下的触发器和当前用户下的触发器建立顺序倒置,看看是否出现同样的问题:
SQL> DROP TABLE T_TRIGGER PURGE;
表已删除。
SQL> CREATE TABLE T_TRIGGER (INFO VARCHAR2(20));
表已创建。
SQL> CONN / AS SYSDBA
已连接。
SQL> DROP TRIGGER TRI_SUSPEND;
触发器已删除。
SQL> CREATE OR REPLACE TRIGGER TRI_SUSPEND
2 AFTER SUSPEND ON DATABASE
3 DECLARE
4 PRAGMA AUTONOMOUS_TRANSACTION;
5 V_RESULT BOOLEAN;
6 V_ERROR_TYPE VARCHAR2(32767);
7 V_OBJECT_TYPE VARCHAR2(32767);
8 V_OBJECT_OWNER VARCHAR2(30);
9 V_TABLESPACE_NAME VARCHAR2(30);
10 V_OBJECT_NAME VARCHAR2(128);
11 V_SUB_OBJECT_NAME VARCHAR2(128);
12 BEGIN
13 V_RESULT := DBMS_RESUMABLE.SPACE_ERROR_INFO(
14 V_ERROR_TYPE,
15 V_OBJECT_TYPE,
16 V_OBJECT_OWNER,
17 V_TABLESPACE_NAME,
18 V_OBJECT_NAME,
19 V_SUB_OBJECT_NAME);
20 INSERT INTO YANGTK.T_TRIGGER VALUES ('SYS TRIGGER');
21 COMMIT;
22 END;
23 /
触发器已创建
SQL> CONN YANGTK/YANGTK
已连接。
SQL> DROP TRIGGER TRI_SUSPEND;
DROP TRIGGER TRI_SUSPEND
*
第1行出现错误:
ORA-04080:触发器'TRI_SUSPEND'不存在
SQL> CREATE OR REPLACE TRIGGER TRI_SUSPEND
2 AFTER SUSPEND ON DATABASE
3 DECLARE
4 PRAGMA AUTONOMOUS_TRANSACTION;
5 V_RESULT BOOLEAN;
6 V_ERROR_TYPE VARCHAR2(32767);
7 V_OBJECT_TYPE VARCHAR2(32767);
8 V_OBJECT_OWNER VARCHAR2(30);
9 V_TABLESPACE_NAME VARCHAR2(30);
10 V_OBJECT_NAME VARCHAR2(128);
11 V_SUB_OBJECT_NAME VARCHAR2(128);
12 BEGIN
13 V_RESULT := DBMS_RESUMABLE.SPACE_ERROR_INFO(
14 V_ERROR_TYPE,
15 V_OBJECT_TYPE,
16 V_OBJECT_OWNER,
17 V_TABLESPACE_NAME,
18 V_OBJECT_NAME,
19 V_SUB_OBJECT_NAME);
20 INSERT INTO T_TRIGGER VALUES ('YANGTK TRIGGER');
21 COMMIT;
22 END;
23 /
警告:创建的触发器带有编译错误。
SQL> ALTER SESSION ENABLE RESUMABLE TIMEOUT 300;
会话已更改。
SQL> CREATE TABLE T_BIG (ID NUMBER)
2 TABLESPACE YANGTK
3 STORAGE (INITIAL250M);
CREATE TABLE T_BIG (ID NUMBER)
*
第1行出现错误:
ORA-04098:触发器'YANGTK.TRI_SUSPEND'无效且未通过重新验证
ORA-01659:无法分配超出27的MINEXTENTS (在表空间YANGTK中)
SQL> SELECT * FROM T_TRIGGER;
INFO
--------------------
SYS TRIGGER
SQL> SELECT OBJECT_ID, OWNER
2 FROM DBA_OBJECTS
3 WHERE OBJECT_NAME = 'TRI_SUSPEND';
OBJECT_ID OWNER
---------- ------------------------------
92651 SYS
92652 YANGTK
虽然错误信息一样,但是可以看到,这次T_TRIGGER表中包含一条记录,说明SYS触发器已经执行成功了。是在尝试调用第二个触发器YANGTK用户下的触发器时出现的错误。
SQL> DROP TRIGGER TRI_SUSPEND;
触发器已删除。
SQL> CREATE TABLE T_BIG (ID NUMBER)
2 TABLESPACE YANGTK
3 STORAGE (INITIAL250M);
CREATE TABLE T_BIG (ID NUMBER)
*
第1行出现错误:
ORA-01659:无法分配超出27的MINEXTENTS (在表空间YANGTK中)
SQL> SELECT * FROM T_TRIGGER;
INFO
--------------------
SYS TRIGGER
可以看到,就是由于触发器状态的不正确,导致当前会话调用触发器出现了问题。即使删除了问题触发器,发生了SUSPEND事件后,SYS用户下的AFTER SYSPEND也没有再次被触发。
尝试在当前会话再次添加一个正确的触发器:
SQL> CREATE OR REPLACE TRIGGER TRI_SUSPEND
2 AFTER SUSPEND ON DATABASE
3 DECLARE
4 PRAGMA AUTONOMOUS_TRANSACTION;
5 BEGIN
6 INSERT INTO T_TRIGGER VALUES ('YANGTK TRIGGER');
7 COMMIT;
8 END;
9 /
触发器已创建
SQL> CREATE TABLE T_BIG (ID NUMBER)
2 TABLESPACE YANGTK
3 STORAGE (INITIAL250M);
CREATE TABLE T_BIG (ID NUMBER)
*
第1行出现错误:
ORA-01659:无法分配超出27的MINEXTENTS (在表空间YANGTK中)
SQL> SELECT * FROM T_TRIGGER;
INFO
--------------------
SYS TRIGGER
即使重建当前用户下的触发器,使其状态正确,在当前的会话中,Oracle也不会再次调用触发器了。
oracle视频教程请关注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html