有趣的觸發器事件
在查詢觸發器的檢視時碰到了一個有趣的問題。
透過一個SQL檢查DBA_TRIGGERS中存在哪個觸發事件:
SQL> SELECT DISTINCT TRIGGERING_EVENT FROM DBA_TRIGGERS;
TRIGGERING_EVENT
------------------------------
UPDATE OR DELETE
DROP
ALTER OR RENAME
INSERT OR UPDATE OR DELETE
INSERT OR UPDATE
DELETE
UPDATE
TRUNCATE
CREATE
ALTER
CREATE OR ALTER
INSERT
STARTUP
DROP OR TRUNCATE
SHUTDOWN
已選擇15行。
下面檢查資料庫中觸發事件為SHUTDOWN的觸發器有哪些:
SQL> SELECT OWNER, TRIGGER_NAME
2 FROM DBA_TRIGGERS
3 WHERE TRIGGERING_EVENT = 'SHUTDOWN';
未選定行
居然沒有找到,可是剛才的查詢明明看到有觸發事件為SHUTDOWN的觸發器。基本上只有兩種可能,一個是在我發出第二個查詢之前,有人刪除了這種型別的觸發器,不過由於這個資料庫是我本機的資料庫,因此不存在這個問題。那麼只剩下一種可能,就是查詢結果後面還跟了看不到的字元。
首先驗證這種觸發事件的觸發器仍然存在:
SQL> SELECT OWNER, TRIGGER_NAME
2 FROM DBA_TRIGGERS
3 WHERE TRIGGERING_EVENT LIKE 'SHUT%';
OWNER TRIGGER_NAME
------------------------------ ----------------------------
SYS AURORA$SERVER$SHUTDOWN
SYS OLAPISHUTDOWNTRIGGER
觸發器果然存在,莫非所有的觸發事件後面都新增了不可見字元:
SQL> SELECT DISTINCT TRIGGERING_EVENT || '.'
2 FROM DBA_TRIGGERS;
TRIGGERING_EVENT||'.'
------------------------------------------------------
TRUNCATE .
INSERT OR UPDATE.
DELETE.
CREATE .
INSERT OR UPDATE OR DELETE.
SHUTDOWN .
UPDATE.
ALTER .
UPDATE OR DELETE.
DROP OR TRUNCATE .
STARTUP .
DROP .
ALTER OR RENAME .
INSERT.
CREATE OR ALTER .
已選擇15行。
奇怪的現象出現了,並不是每種觸發事件後面都跟隨了空格,所有DML以及DML組合事件都不帶末尾的空格,而其他型別都是帶空格的,這又是什麼原因呢。
SQL> SELECT TEXT FROM DBA_VIEWS
2 WHERE VIEW_NAME = 'DBA_TRIGGERS';
TEXT
-------------------------------------------------------------------------------
select trigusr.name, trigobj.name,
decode(t.type#, 0, 'BEFORE STATEMENT',
1, 'BEFORE EACH ROW',
2, 'AFTER STATEMENT',
3, 'AFTER EACH ROW',
4, 'INSTEAD OF',
'UNDEFINED'),
decode(t.insert$*100 + t.update$*10 + t.delete$,
100, 'INSERT',
010, 'UPDATE',
001, 'DELETE',
110, 'INSERT OR UPDATE',
101, 'INSERT OR DELETE',
011, 'UPDATE OR DELETE',
111, 'INSERT OR UPDATE OR DELETE', 'ERROR'),
tabusr.name,
decode(bitand(t.property, 1), 1, 'VIEW',
0, 'TABLE',
'UNDEFINED'),
tabobj.name, NULL,
'REFERENCING NEW AS '||t.refnewname||' OLD AS '||t.refoldname,
t.whenclause,decode(t.enabled, 0, 'DISABLED', 1, 'ENABLED', 'ERROR'),
t.definition,
decode(bitand(t.property, 2), 2, 'CALL',
'PL/SQL '),
t.action#
from sys.obj$ trigobj, sys.obj$ tabobj, sys.trigger$ t,
sys.user$ tabusr, sys.user$ trigusr
where (trigobj.obj# = t.obj# and
tabobj.obj# = t.baseobject and
tabobj.owner# = tabusr.user# and
trigobj.owner# = trigusr.user# and
bitand(t.property, 63) < 8 )
union all
select trigusr.name, trigobj.name,
decode(t.type#, 0, 'BEFORE EVENT',
2, 'AFTER EVENT',
'UNDEFINED'),
decode(bitand(t.sys_evts, 1), 1, 'STARTUP ') ||
decode(bitand(t.sys_evts, 2), 2,
decode(sign(bitand(t.sys_evts, 1)), 1, 'OR SHUTDOWN ',
'SHUTDOWN ')) ||
decode(bitand(t.sys_evts, 4), 4,
decode(sign(bitand(t.sys_evts, 3)), 1, 'OR ERROR ',
'ERROR ')) ||
decode(bitand(t.sys_evts, 8), 8,
decode(sign(bitand(t.sys_evts, 7)), 1, 'OR LOGON ',
'LOGON ')) ||
decode(bitand(t.sys_evts, 16), 16,
decode(sign(bitand(t.sys_evts, 15)), 1, 'OR LOGOFF ',
'LOGOFF ')) ||
decode(bitand(t.sys_evts, 262176), 32,
decode(sign(bitand(t.sys_evts, 31)), 1, 'OR CREATE ',
'CREATE ')) ||
decode(bitand(t.sys_evts, 262208), 64,
decode(sign(bitand(t.sys_evts, 63)), 1, 'OR ALTER ',
'ALTER ')) ||
decode(bitand(t.sys_evts, 262272), 128,
decode(sign(bitand(t.sys_evts, 127)), 1, 'OR DROP ',
'DROP ')) ||
decode (bitand(t.sys_evts, 262400), 256,
decode(sign(bitand(t.sys_evts, 255)), 1, 'OR ANALYZE ',
'ANALYZE ')) ||
decode (bitand(t.sys_evts, 262656), 512,
decode(sign(bitand(t.sys_evts, 511)), 1, 'OR COMMENT ',
'COMMENT ')) ||
decode (bitand(t.sys_evts, 263168), 1024,
decode(sign(bitand(t.sys_evts, 1023)), 1, 'OR GRANT ',
'GRANT ')) ||
decode (bitand(t.sys_evts, 264192), 2048,
decode(sign(bitand(t.sys_evts, 2047)), 1, 'OR REVOKE ',
'REVOKE ')) ||
decode (bitand(t.sys_evts, 266240), 4096,
decode(sign(bitand(t.sys_evts, 4095)), 1, 'OR TRUNCATE ',
'TRUNCATE ')) ||
decode (bitand(t.sys_evts, 270336), 8192,
decode(sign(bitand(t.sys_evts, 8191)), 1, 'OR RENAME ',
'RENAME ')) ||
decode (bitand(t.sys_evts, 278528), 16384,
decode(sign(bitand(t.sys_evts, 16383)), 1, 'OR ASSOCIATE STATISTICS ',
'ASSOCIATE STATISTICS ')) ||
decode (bitand(t.sys_evts, 294912), 32768,
decode(sign(bitand(t.sys_evts, 32767)), 1, 'OR AUDIT ',
'AUDIT ')) ||
decode (bitand(t.sys_evts, 327680), 65536,
decode(sign(bitand(t.sys_evts, 65535)), 1,
'OR DISASSOCIATE STATISTICS ', 'DISASSOCIATE STATISTICS ')) ||
decode (bitand(t.sys_evts, 393216), 131072,
decode(sign(bitand(t.sys_evts, 131071)), 1, 'OR NOAUDIT ',
'NOAUDIT ')) ||
decode (bitand(t.sys_evts, 262144), 262144,
decode(sign(bitand(t.sys_evts, 31)), 1, 'OR DDL ',
'DDL ')) ||
decode (bitand(t.sys_evts, 8388608), 8388608,
decode(sign(bitand(t.sys_evts, 8388607)), 1, 'OR SUSPEND ',
'SUSPEND ')),
'SYS',
'DATABASE ',
NULL,
NULL,
'REFERENCING NEW AS '||t.refnewname||' OLD AS '||t.refoldname
|| decode(bitand(t.property,32),32,' PARENT AS ' || t.refprtname,NULL),
t.whenclause,decode(t.enabled, 0, 'DISABLED', 1, 'ENABLED', 'ERROR'),
t.definition,
decode(bitand(t.property, 2), 2, 'CALL',
'PL/SQL '),
t.action#
from sys.obj$ trigobj, sys.trigger$ t, sys.user$ trigusr
where (trigobj.obj# = t.obj# and
trigobj.owner# = trigusr.user# and
bitand(t.property, 63) >= 8 and bitand(t.property, 63) < 16)
union all
select trigusr.name, trigobj.name,
decode(t.type#, 0, 'BEFORE EVENT',
2, 'AFTER EVENT',
'UNDEFINED'),
decode(bitand(t.sys_evts, 1), 1, 'STARTUP ') ||
decode(bitand(t.sys_evts, 2), 2,
decode(sign(bitand(t.sys_evts, 1)), 1, 'OR SHUTDOWN ',
'SHUTDOWN ')) ||
decode(bitand(t.sys_evts, 4), 4,
decode(sign(bitand(t.sys_evts, 3)), 1, 'OR ERROR ',
'ERROR ')) ||
decode(bitand(t.sys_evts, 8), 8,
decode(sign(bitand(t.sys_evts, 7)), 1, 'OR LOGON ',
'LOGON ')) ||
decode(bitand(t.sys_evts, 16), 16,
decode(sign(bitand(t.sys_evts, 15)), 1, 'OR LOGOFF ',
'LOGOFF ')) ||
decode(bitand(t.sys_evts, 262176), 32,
decode(sign(bitand(t.sys_evts, 31)), 1, 'OR CREATE ',
'CREATE ')) ||
decode(bitand(t.sys_evts, 262208), 64,
decode(sign(bitand(t.sys_evts, 63)), 1, 'OR ALTER ',
'ALTER ')) ||
decode(bitand(t.sys_evts, 262272), 128,
decode(sign(bitand(t.sys_evts, 127)), 1, 'OR DROP ',
'DROP ')) ||
decode (bitand(t.sys_evts, 262400), 256,
decode(sign(bitand(t.sys_evts, 255)), 1, 'OR ANALYZE ',
'ANALYZE ')) ||
decode (bitand(t.sys_evts, 262656), 512,
decode(sign(bitand(t.sys_evts, 511)), 1, 'OR COMMENT ',
'COMMENT ')) ||
decode (bitand(t.sys_evts, 263168), 1024,
decode(sign(bitand(t.sys_evts, 1023)), 1, 'OR GRANT ',
'GRANT ')) ||
decode (bitand(t.sys_evts, 264192), 2048,
decode(sign(bitand(t.sys_evts, 2047)), 1, 'OR REVOKE ',
'REVOKE ')) ||
decode (bitand(t.sys_evts, 266240), 4096,
decode(sign(bitand(t.sys_evts, 4095)), 1, 'OR TRUNCATE ',
'TRUNCATE ')) ||
decode (bitand(t.sys_evts, 270336), 8192,
decode(sign(bitand(t.sys_evts, 8191)), 1, 'OR RENAME ',
'RENAME ')) ||
decode (bitand(t.sys_evts, 278528), 16384,
decode(sign(bitand(t.sys_evts, 16383)), 1, 'OR ASSOCIATE STATISTICS ',
'ASSOCIATE STATISTICS ')) ||
decode (bitand(t.sys_evts, 294912), 32768,
decode(sign(bitand(t.sys_evts, 32767)), 1, 'OR AUDIT ',
'AUDIT ')) ||
decode (bitand(t.sys_evts, 327680), 65536,
decode(sign(bitand(t.sys_evts, 65535)), 1,
'OR DISASSOCIATE STATISTICS ', 'DISASSOCIATE STATISTICS ')) ||
decode (bitand(t.sys_evts, 393216), 131072,
decode(sign(bitand(t.sys_evts, 131071)), 1, 'OR NOAUDIT ',
'NOAUDIT ')) ||
decode (bitand(t.sys_evts, 262144), 262144,
decode(sign(bitand(t.sys_evts, 31)), 1, 'OR DDL ',
'DDL ')) ||
decode (bitand(t.sys_evts, 8388608), 8388608,
decode(sign(bitand(t.sys_evts, 8388607)), 1, 'OR SUSPEND ',
'SUSPEND ')),
tabusr.name,
'SCHEMA',
NULL,
NULL,
'REFERENCING NEW AS '||t.refnewname||' OLD AS '||t.refoldname,
t.whenclause,decode(t.enabled, 0, 'DISABLED', 1, 'ENABLED', 'ERROR'),
t.definition,
decode(bitand(t.property, 2), 2, 'CALL',
'PL/SQL '),
t.action#
from sys.obj$ trigobj, sys.trigger$ t, sys.user$ tabusr, sys.user$ trigusr
where (trigobj.obj# = t.obj# and
trigobj.owner# = trigusr.user# and
bitand(t.property, 63) >= 16 and bitand(t.property, 63) < 32 and
tabusr.user# = t.baseobject)
union all
select trigusr.name, trigobj.name,
decode(t.type#, 0, 'BEFORE STATEMENT',
1, 'BEFORE EACH ROW',
2, 'AFTER STATEMENT',
3, 'AFTER EACH ROW',
4, 'INSTEAD OF',
'UNDEFINED'),
decode(t.insert$*100 + t.update$*10 + t.delete$,
100, 'INSERT',
010, 'UPDATE',
001, 'DELETE',
110, 'INSERT OR UPDATE',
101, 'INSERT OR DELETE',
011, 'UPDATE OR DELETE',
111, 'INSERT OR UPDATE OR DELETE', 'ERROR'),
tabusr.name,
decode(bitand(t.property, 1), 1, 'VIEW',
0, 'TABLE',
'UNDEFINED'),
tabobj.name, ntcol.name,
'REFERENCING NEW AS '||t.refnewname||' OLD AS '||t.refoldname ||
' PARENT AS ' || t.refprtname,
t.whenclause,decode(t.enabled, 0, 'DISABLED', 1, 'ENABLED', 'ERROR'),
t.definition,
decode(bitand(t.property, 2), 2, 'CALL',
'PL/SQL '),
t.action#
from sys.obj$ trigobj, sys.obj$ tabobj, sys.trigger$ t,
sys.user$ tabusr, sys.user$ trigusr, sys.viewtrcol$ ntcol
where (trigobj.obj# = t.obj# and
tabobj.obj# = t.baseobject and
tabobj.owner# = tabusr.user# and
trigobj.owner# = trigusr.user# and
t.nttrigcol = ntcol.intcol# and
t.nttrigatt = ntcol.attribute# and
t.baseobject = ntcol.obj# and
bitand(t.property, 63) >= 32)
其實只要看一下DBA_TRIGGERS檢視的SQL就清楚了。
觀察上面紅色部分,由於觸發器事件可以由多個事件組合,Oracle在存放的時候將不同事件轉化為不同的數位儲存,這樣透過一個欄位就可以表示多個事件的組合資訊。而在檢視顯示的時候,透過DECODE判斷數位,對於第一個事件顯示事件名稱和空格,以後出現的事件直接在後面追加OR和事件名稱及空格。Oracle這裡新增空格是為了方便處理多個事件組合的情況。
而對於DML的情況,由於一共可能產生的組合只有7種,Oracle將所有可能依次列出,因此就沒有新增空格,程式碼參考上面藍色部分。
看來不起眼的一個空格,Oracle在處理上也是經過思考的,不過個人認為,如果在紅色程式碼的外面巢狀一層RTRIM,那麼就真的完美了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-234425/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle觸發器6(建立系統事件觸發器)Oracle觸發器事件
- oracle 觸發器 client 事件Oracle觸發器client事件
- mvvm模式 事件觸發器[wpf]MVVM模式事件觸發器
- 取消事件觸發事件
- WebSocket的事件觸發機制Web事件
- Android觸控事件(下)——事件的分發Android事件
- touch事件和click事件多次觸發的問題事件
- 使用 jQuery 觸發 Vue 事件jQueryVue事件
- 取消事件觸發(妙啊)事件
- jQuery select 觸發事件jQuery事件
- JavaScript 模擬事件觸發JavaScript事件
- 技術分享:NodeJS中的Events(事件觸發器)講解NodeJS事件觸發器
- 通過程式碼控制View的觸控事件被觸發View事件
- Oracle觸發器觸發級別Oracle觸發器
- javascript如何獲取觸發事件的物件JavaScript事件物件
- HTML事件的控制元件觸發 (轉)HTML事件控制元件
- js 建立和觸發事件 和 自定義事件JS事件
- 如何觸發react input change事件React事件
- Yii中事件觸發機制事件
- 根據業務寫觸發器(oracle觸發器片)觸發器Oracle
- Vue事件獲取觸發事件物件和繫結事件物件Vue事件物件
- mysql——觸發器MySql觸發器
- mysql 觸發器MySql觸發器
- SQL觸發器SQL觸發器
- Mysql觸發器:MySql觸發器
- Oracle觸發器Oracle觸發器
- mysql觸發器MySql觸發器
- 原生javascript如何獲取觸發事件的物件JavaScript事件物件
- 瞭解SQL Server觸發器及觸發器中的事務AWSQLServer觸發器
- SQL Sever 2000中的前觸發器和後觸發器SQL觸發器
- storage事件中的坑,storage.setItem()無法觸發storage事件事件
- javascript避免dom事件重複觸發JavaScript事件
- js頁面載入觸發事件JS事件
- view.performClick()觸發點選事件ViewORM事件
- 【SQL Server】-- 一觸即發之觸發器SQLServer觸發器
- 瀏覽器的視窗大小被改變時觸發的事件window.onresize瀏覽器事件
- (interbase之九)intebase的儲存過程、觸發器以及事件、異常 (轉)儲存過程觸發器事件
- (15)mysql 中的觸發器MySql觸發器