第十七章 使用觸發(fā)器
本章介紹如何在Intersystems SQL中定義觸發(fā)器。觸發(fā)器是響應(yīng)某些SQL事件執(zhí)行的代碼行。本章包括以下主題:
定義觸發(fā)器
有幾種方法可以為特定表定義觸發(fā)器:
- 在將投影到SQL表的持久性類定義中包含觸發(fā)定義。例如,
MyApp.person類的此定義包括Loggevent觸發(fā)器的定義,在每個(gè)成功的數(shù)據(jù)插入到MyApp.person表之后,將在每個(gè)成功的數(shù)據(jù)插入后調(diào)用:
Class MyApp.Person Extends %Persistent [DdlAllowed]
{
// ... Class Property Definitions
Trigger LogEvent [ Event = INSERT, Time = AFTER ]
{
// Trigger code to log an event
}
}
- 使用SQL創(chuàng)建觸發(fā)命令創(chuàng)建觸發(fā)器。這在相應(yīng)的持久性類中生成觸發(fā)對(duì)象定義。 SQL觸發(fā)器名稱按照標(biāo)識(shí)符命名約定進(jìn)行操作。 IntersystemsIris?數(shù)據(jù)平臺(tái)使用SQL觸發(fā)名稱生成相應(yīng)的觸發(fā)類實(shí)體名稱。
必須擁有%create_trigger管理級(jí)別權(quán)限來(lái)創(chuàng)建觸發(fā)器。必須具有刪除觸發(fā)器的%drop_trigger管理級(jí)別權(quán)限。
類的最大用戶定義觸發(fā)器數(shù)為200。
注意:Intersystems Iris不支持收集投影的表上的觸發(fā)。用戶無(wú)法定義這樣的觸發(fā)器,并且作為子表的集合的投影不認(rèn)為涉及該基本集合的觸發(fā)。
Intersystems Iris不支持修改Security.Roles和Security.Users表的觸發(fā)器。
觸發(fā)器的類型
觸發(fā)器由以下內(nèi)容定義:
- 導(dǎo)致它執(zhí)行的事件類型。觸發(fā)器可以是單個(gè)事件觸發(fā)器或多事件觸發(fā)。定義單個(gè)事件觸發(fā)器以在指定表上發(fā)生插入,更新或刪除事件時(shí)執(zhí)行。定義多事件觸發(fā)器以執(zhí)行當(dāng)在指定的表中發(fā)生多個(gè)指定的事件中的任何一個(gè)時(shí)執(zhí)行??梢允褂妙惗x或創(chuàng)建觸發(fā)命令定義插入/更新,更新/刪除或插入/更新/刪除多事件觸發(fā)器。事件類型在Class定義中指定了所需的事件觸發(fā)器關(guān)鍵字。
- 觸發(fā)器執(zhí)行的時(shí)間:在事件發(fā)生之前或之后。
這是由可選的Time trigger關(guān)鍵字在類定義中指定的。
默認(rèn)為Before。 - 可以將多個(gè)觸發(fā)器與同一事件和時(shí)間相關(guān)聯(lián);在這種情況下,可以使用
order trigger關(guān)鍵字來(lái)控制觸發(fā)多個(gè)觸發(fā)器的順序。先觸發(fā)順序較低的觸發(fā)器。
如果多個(gè)觸發(fā)器具有相同的Order值,則不指定它們的觸發(fā)順序。 - 可選的
Foreach trigger關(guān)鍵字提供了額外的粒度。
該關(guān)鍵字控制觸發(fā)器是每一行觸發(fā)一次(Foreach = row),還是每一行或?qū)ο笤L問(wèn)觸發(fā)一次(Foreach = row/object),還是每語(yǔ)句觸發(fā)一次(Foreach = statement)。
沒有Foreach trigger關(guān)鍵字定義的觸發(fā)器每一行觸發(fā)一次。
如果觸發(fā)器是用Foreach = row/object定義的,那么觸發(fā)器也會(huì)在對(duì)象訪問(wèn)期間的特定點(diǎn)被調(diào)用,如本章后面所述。
可以使用INFORMATION.SCHEMA.TRIGGERS的ACTIONORIENTATION屬性列出每個(gè)觸發(fā)器的Foreach值
下面是可用的觸發(fā)器及其等價(jià)的回調(diào)方法:
BEFORE INSERT(等價(jià)于%OnBeforeSave())AFTER INSERT(等價(jià)于%OnAfterSave())BEFORE UPDATE(等價(jià)于%OnBeforeSave())AFTER UPDATE(等價(jià)于%OnAfterSave())BEFORE UPDATE OF specified column(s)AFTER UPDATE OF specified column(s)BEFORE DELETE(等價(jià)于%OnDelete())AFTER DELETE(等價(jià)于%OnAfterDelete())
注意:當(dāng)觸發(fā)器執(zhí)行時(shí),它不能直接修改正在處理的表中的屬性值。
這是因?yàn)镮nterSystems IRIS在字段(屬性)值驗(yàn)證代碼之后執(zhí)行觸發(fā)代碼。
例如,觸發(fā)器不能將LastModified字段設(shè)置為正在處理的行中的當(dāng)前時(shí)間戳。
但是,觸發(fā)器代碼可以對(duì)表中的字段值發(fā)出更新。
更新執(zhí)行自己的字段值驗(yàn)證。
AFTER Triggers
在INSERT、UPDATE或DELETE事件發(fā)生后執(zhí)行AFTER觸發(fā)器:
- 如果
SQLCODE=0(事件成功完成),InterSystems IRIS將執(zhí)行AFTER觸發(fā)器。 - 如果
SQLCODE是負(fù)數(shù)(事件失敗),系統(tǒng)間IRIS就不會(huì)執(zhí)行AFTER觸發(fā)器。 - 如果
SQLCODE=100(沒有發(fā)現(xiàn)要插入、更新或刪除的行),則系統(tǒng)間IRIS執(zhí)行AFTER觸發(fā)器。
遞歸觸發(fā)器
觸發(fā)器執(zhí)行可以是遞歸的。
例如,如果表T1有一個(gè)對(duì)表T2執(zhí)行插入操作的觸發(fā)器,表T2也有一個(gè)對(duì)表T1執(zhí)行插入操作的觸發(fā)器。
當(dāng)表T1有一個(gè)調(diào)用例程/過(guò)程的觸發(fā)器,并且該例程/過(guò)程執(zhí)行對(duì)T1的插入操作時(shí),也可以發(fā)生遞歸。
觸發(fā)器遞歸的處理取決于觸發(fā)器的類型:
- 行和行/對(duì)象觸發(fā)器:InterSystems IRIS不阻止行觸發(fā)器和行/對(duì)象觸發(fā)器遞歸地執(zhí)行。
處理觸發(fā)器遞歸是程序員的責(zé)任。
如果觸發(fā)代碼不處理遞歸執(zhí)行,則可能發(fā)生runtime<FRAMESTACK>錯(cuò)誤。 - 語(yǔ)句觸發(fā)器:InterSystems IRIS阻止
AFTER語(yǔ)句觸發(fā)器遞歸執(zhí)行。
如果InterSystems IRIS檢測(cè)到該觸發(fā)器在執(zhí)行堆棧中已經(jīng)被調(diào)用,它將不會(huì)發(fā)出AFTER觸發(fā)器。
沒有錯(cuò)誤發(fā)出;
觸發(fā)器不會(huì)被第二次執(zhí)行。
InterSystems IRIS不會(huì)阻止BEFORE語(yǔ)句觸發(fā)器遞歸地執(zhí)行。
在觸發(fā)遞歸之前處理是程序員的責(zé)任。
如果BEFORE觸發(fā)器代碼不處理遞歸執(zhí)行,可能會(huì)發(fā)生runtime <FRAMESTACK>錯(cuò)誤。
Trigger Code
每個(gè)觸發(fā)器包含執(zhí)行觸發(fā)操作的一行或多行代碼。
每當(dāng)與觸發(fā)器關(guān)聯(lián)的事件發(fā)生時(shí),SQL引擎就會(huì)調(diào)用這段代碼。
如果觸發(fā)器是使用CREATE觸發(fā)器定義的,則可以用ObjectScript或SQL編寫此操作代碼。
(InterSystems IRIS將SQL編寫的代碼轉(zhuǎn)換為類定義中的ObjectScript。)
如果觸發(fā)器是使用Studio定義的,那么這個(gè)操作代碼必須用ObjectScript編寫。
因?yàn)橛|發(fā)器的代碼不是作為過(guò)程生成的,所以觸發(fā)器中的所有局部變量都是公共變量。
這意味著觸發(fā)器中的所有變量都應(yīng)該用一個(gè)新語(yǔ)句顯式聲明;
這可以防止它們與調(diào)用觸發(fā)器的代碼中的變量發(fā)生沖突。
%ok, %msg, and %oper 系統(tǒng)變量
-
%ok:僅在觸發(fā)器代碼中使用的變量。
如果觸發(fā)代碼成功,它設(shè)置%ok=1。
如果觸發(fā)代碼失敗,它設(shè)置%ok=0。
如果在觸發(fā)器執(zhí)行期間發(fā)出SQLCODE錯(cuò)誤,InterSystems IRIS將設(shè)置%ok=0。
當(dāng)%ok=0時(shí),觸發(fā)器代碼中止,觸發(fā)器操作和調(diào)用觸發(fā)器的操作被回滾。
如果插入或更新觸發(fā)器代碼失敗,并且表中定義了一個(gè)外鍵約束,InterSystems IRIS將釋放外鍵表中相應(yīng)行上的鎖。
觸發(fā)代碼可以顯式設(shè)置%ok=0。
這會(huì)創(chuàng)建一個(gè)運(yùn)行時(shí)錯(cuò)誤,中止觸發(fā)器的執(zhí)行并回滾操作。
通常,在設(shè)置%ok=0之前,觸發(fā)器代碼顯式地將%msg變量設(shè)置為用戶指定的字符串,用于描述這個(gè)用戶定義的觸發(fā)器代碼錯(cuò)誤。
%ok變量是一個(gè)必須顯式更新的公共變量。
在完成非觸發(fā)代碼SELECT、INSERT、UPDATE或DELETE語(yǔ)句后,%ok的值與之前的值沒有變化。
%ok僅在執(zhí)行觸發(fā)器代碼時(shí)定義。
%msg:觸發(fā)代碼可以顯式地將%msg變量設(shè)置為描述運(yùn)行時(shí)錯(cuò)誤原因的字符串。
設(shè)置變量%msg。
%oper:僅在觸發(fā)器代碼中使用的變量。
觸發(fā)器代碼可以引用變量%oper,該變量包含觸發(fā)觸發(fā)器的事件(插入、更新或刪除)的名稱。
{fieldname}語(yǔ)法
在觸發(fā)器代碼中,可以使用特殊的{fieldname}語(yǔ)法引用字段值(對(duì)于屬于觸發(fā)器關(guān)聯(lián)的表的字段)。
例如,下面是MyApp中LogEvent觸發(fā)器的定義。
Person類包含一個(gè)對(duì)ID字段的引用,如{ID}:
Class MyApp.Person Extends %Persistent [DdlAllowed]
{
// ... Definitions of other class members
/// This trigger updates the LogTable after every insert
Trigger LogEvent [ Event = INSERT, Time = AFTER ]
{
// get row id of inserted row
NEW id,SQLCODE,%msg,%ok,%oper
SET id = {ID}
// INSERT value into Log table
&sql(INSERT INTO LogTable
(TableName, IDValue)
VALUES ('MyApp.Person', :id))
IF SQLCODE<0 {SET baderr="SQLCODE ERROR:"_SQLCODE_" "_%msg
SET %ok=0
RETURN baderr }
}
// ... Definitions of other class members
}
這個(gè){fieldname}語(yǔ)法支持統(tǒng)一字段。
它不支持%SerialObject集合屬性。
例如,如果表引用了嵌入的串行對(duì)象類Address(其中包含屬性City),那么觸發(fā)器語(yǔ)法{Address_City}就是對(duì)字段的有效引用。
觸發(fā)器語(yǔ)法{Address}是對(duì)集合屬性的引用,不能使用。
觸發(fā)器代碼中的宏
觸發(fā)器代碼可以包含一個(gè)引用字段名的宏定義(使用{fieldname}語(yǔ)法)。
但是,如果你的觸發(fā)代碼包含一個(gè)#Include預(yù)處理器指令,用于一個(gè)引用字段名的宏(使用{fieldname}語(yǔ)法),那么這個(gè)字段名就不能被訪問(wèn)。
這是因?yàn)镮nterSystems IRIS在代碼被傳遞給宏預(yù)處理器之前,翻譯觸發(fā)器代碼中的{fieldname}引用。
如果一個(gè){fieldname}引用在#Include文件中,它不會(huì)在觸發(fā)器代碼中“看到”,因此不會(huì)被轉(zhuǎn)換。
這種情況的解決方法是定義一個(gè)帶參數(shù)的宏,然后將{fieldname}傳遞給觸發(fā)器中的宏。
例如,#Include文件可以包含如下一行:
#Define dtThrowTrigger(%val) SET x=$GET(%val,"?")
然后在觸發(fā)器中調(diào)用提供{fieldname}語(yǔ)法作為參數(shù)的宏:
$$$dtThrowTrigger({%%ID})
{name*O}, {name*N}和{name*C}觸發(fā)代碼語(yǔ)法
在更新觸發(fā)器代碼中有三種語(yǔ)法快捷方式可用。
可以使用下面的語(yǔ)法引用舊的(預(yù)更新的)值:
{fieldname*O}
其中fieldname是字段的名稱,星號(hào)后面的字符是字母“O”(表示舊)。
對(duì)于插入觸發(fā)器,{fieldname*O}總是空字符串("")。
你可以使用下面的語(yǔ)法來(lái)引用新的(更新后的)值:
{fieldname*N}
其中fieldname是字段的名稱,星號(hào)后面的字符是字母“N”(表示新字段)。
{fieldname*N}語(yǔ)法只能用于引用要存儲(chǔ)的值;
它不能用來(lái)更改值。
不能在觸發(fā)器代碼中設(shè)置{fieldname*N}。
在插入或更新時(shí)計(jì)算字段的值應(yīng)該通過(guò)其他方法實(shí)現(xiàn),比如SqlComputeOnChange。
可以使用以下語(yǔ)法測(cè)試字段值是否被更改(更新):
{fieldname*C}
其中,fieldname是字段的名稱,星號(hào)后面的字符是字母“C”(表示已更改)。
{fieldname*C}的計(jì)算結(jié)果是1,如果字段已經(jīng)被修改,0,如果它沒有被修改。
對(duì)于插入觸發(fā)器,InterSystems IRIS將{fieldname*C}設(shè)置為1。
對(duì)于具有流屬性的類,如果SQL語(yǔ)句(INSERT或UPDATE)沒有插入/更新流屬性本身,則對(duì)流屬性{stream *N}和{stream *O}的SQL觸發(fā)器引用將返回流的OID。
然而,如果SQL語(yǔ)句確實(shí)插入/更新了stream屬性,{stream *O}仍然是OID,但{stream *N}的值被設(shè)置為以下之一:
- 在觸發(fā)器之前,將流字段的值以傳遞給更新或插入的任何格式返回。
這可以是輸入到stream屬性中的文字?jǐn)?shù)據(jù)值,也可以是臨時(shí)stream對(duì)象的OREF或OID。 -
AFTER trigger將流的Id作為{stream *N}的值返回。
這是InterSystems IRIS的Id值,存儲(chǔ)在流字段名為global的^classnameD中。
該值根據(jù)流屬性的CLASSNAME類型參數(shù)使用適當(dāng)?shù)?code>Id格式。
如果一個(gè)流屬性使用InterSystems IRIS對(duì)象更新,{stream *N}的值總是一個(gè)OID。
注意:對(duì)于由串行對(duì)象的數(shù)組集合創(chuàng)建的子表觸發(fā)器,觸發(fā)器邏輯與對(duì)象訪問(wèn)/保存一起工作,但與SQL訪問(wèn)(插入或更新)不工作。
附加觸發(fā)器代碼語(yǔ)法
在ObjectScript中編寫的觸發(fā)器代碼可以包含偽域引用變量{%%CLASSNAME}、{%%CLASSNAMEQ}、{%%OPERATION}、{%%TABLENAME}和{%%ID}。
這些偽字段在類編譯時(shí)被轉(zhuǎn)換成特定的值。
可以從觸發(fā)器代碼、SQL計(jì)算代碼和SQL映射定義中使用類方法,因?yàn)轭惙椒ú灰蕾囉趽碛虚_放對(duì)象。
必須使用##class(classname). methodname()語(yǔ)法從觸發(fā)器代碼中調(diào)用方法。
你不能使用..Methodname()語(yǔ)法,因?yàn)檫@個(gè)語(yǔ)法需要一個(gè)當(dāng)前打開的對(duì)象。
可以將當(dāng)前行字段的值作為類方法的參數(shù)傳遞,但是類方法本身不能使用字段語(yǔ)法。
Pulling Triggers
如果調(diào)用對(duì)應(yīng)于該表的DML命令,則“拉出”(執(zhí)行)已定義的觸發(fā)器。
對(duì)于DML命令成功插入、更新或刪除的每一行,都會(huì)拉取一行或行/對(duì)象觸發(fā)器。
對(duì)于每個(gè)成功執(zhí)行的INSERT、UPDATE或DELETE語(yǔ)句,都會(huì)拉出一次語(yǔ)句觸發(fā)器,而不管該語(yǔ)句是否實(shí)際更改了表數(shù)據(jù)中的任何行。
-
INSERT語(yǔ)句拉動(dòng)相應(yīng)的插入觸發(fā)器。
插入可以通過(guò)指定%NOTRIGGER關(guān)鍵字來(lái)阻止觸發(fā)相應(yīng)的觸發(fā)器。
指定%NOJOURN關(guān)鍵字的插入不會(huì)記錄該插入或相應(yīng)的插入觸發(fā)器。
這意味著插入事件或觸發(fā)事件都不可能回滾。
快速插入不能用于具有插入觸發(fā)器的表。
UPDATE語(yǔ)句拉動(dòng)相應(yīng)的更新觸發(fā)器。
更新可以通過(guò)指定%NOTRIGGER關(guān)鍵字來(lái)阻止觸發(fā)相應(yīng)的觸發(fā)器。
指定%NOJOURN關(guān)鍵字的更新不會(huì)記錄該更新或相應(yīng)的更新觸發(fā)器。
這意味著更新事件或觸發(fā)事件都不可能回滾。根據(jù)執(zhí)行的DDL操作的類型,
INSERT或UPDATE語(yǔ)句拉動(dòng)相應(yīng)的INSERT觸發(fā)器或UPDATE觸發(fā)器。
要防止觸發(fā)任何類型的觸發(fā)器,請(qǐng)指定%NOTRIGGER關(guān)鍵字。DELETE語(yǔ)句拉動(dòng)相應(yīng)的DELETE觸發(fā)器。
DELETE可以通過(guò)指定%NOTRIGGER關(guān)鍵字來(lái)阻止觸發(fā)相應(yīng)的觸發(fā)器。
指定%NOJOURN關(guān)鍵字的刪除不會(huì)記錄刪除或相應(yīng)的刪除觸發(fā)器。
這意味著刪除事件或觸發(fā)事件都不可能回滾。TRUNCATE TABLE語(yǔ)句不會(huì)觸發(fā)刪除觸發(fā)器。
默認(rèn)情況下,DDL語(yǔ)句和相應(yīng)的觸發(fā)操作被記錄在日志中。
%NOJOURN關(guān)鍵字阻止DDL命令和觸發(fā)動(dòng)作的日志記錄。
觸發(fā)器和對(duì)象訪問(wèn)
如果觸發(fā)器是用Foreach = row/object定義的,那么觸發(fā)器也會(huì)在對(duì)象訪問(wèn)期間的特定點(diǎn)被調(diào)用,這取決于觸發(fā)器定義的Event和Time關(guān)鍵字,如下所示:
Event |
Time |
此時(shí)也調(diào)用Trigger
|
|---|---|---|
| INSERT | BEFORE | 在新對(duì)象的%Save()之前 |
| INSERT | AFTER | 在新對(duì)象的%Save()后 |
| UPDATE | BEFORE | 在已存在對(duì)象的%Save()之前 |
| UPDATE | AFTER | 在已存在對(duì)象的%Save()后 |
| DELETE | BEFORE | 在現(xiàn)有對(duì)象的%DeleteId()之前 |
| DELETE | AFTER | 在現(xiàn)有對(duì)象的%DeleteId()后 |
因此,也沒有必要為了保持SQL和對(duì)象行為同步而實(shí)現(xiàn)回調(diào)方法,
在對(duì)象訪問(wèn)期間沒有拔出觸發(fā)器
默認(rèn)情況下,SQL對(duì)象使用%Storage.Persistent存儲(chǔ)。
InterSystems IRIS也支持 %Storage.SQL storage。
SQL存儲(chǔ)。
在使用 %Storage.SQL storage的類中保存或刪除對(duì)象時(shí)。
SQL存儲(chǔ),所有語(yǔ)句(Foreach = statement)、行(Foreach = row)和行/對(duì)象(Foreach = row/object)觸發(fā)器被拉出。
沒有定義Foreach trigger關(guān)鍵字的觸發(fā)器是行觸發(fā)器。
提取所有觸發(fā)器是默認(rèn)行為。
但是,在使用%Storage.SQL storage保存或刪除類中的對(duì)象時(shí)。
SQL,可以指定只有定義為Foreach = row/object的觸發(fā)器應(yīng)該被拉出。
定義為Foreach = statement或Foreach = row的觸發(fā)器不會(huì)被拉取。
這是通過(guò)指定類參數(shù)OBJECTSPULLTRIGGERS = 0來(lái)實(shí)現(xiàn)的。
默認(rèn)值是OBJECTSPULLTRIGGERS = 1。
此參數(shù)僅應(yīng)用于使用%Storage.SQL定義的類。
觸發(fā)器與事務(wù)
觸發(fā)器在事務(wù)中執(zhí)行觸發(fā)器碼。它設(shè)置事務(wù)級(jí)別,然后執(zhí)行觸發(fā)器代碼。成功完成觸發(fā)器代碼后,觸發(fā)器提交事務(wù)。
注意:使用事務(wù)的觸發(fā)器的結(jié)果是,如果觸發(fā)器調(diào)用提交事務(wù)的代碼,則觸發(fā)器的完成失敗,因?yàn)槭聞?wù)級(jí)別已經(jīng)遞減為0.調(diào)用生產(chǎn)的業(yè)務(wù)服務(wù)時(shí)可能發(fā)生這種情況。
使用INSERT語(yǔ)句級(jí)別對(duì)象觸發(fā)器后,如果觸發(fā)器集%OK = 0,則使用SQLCODE -131錯(cuò)誤失敗行的插入失敗。如下所示,可能會(huì)發(fā)生交易回滾:
- 如果
auto_commit = on,則插入的事務(wù)將被回滾。 - 如果
auto_commit =off,則應(yīng)用于回滾或提交輸入的事務(wù)。 - 如果使用
no_auto_commit模式,則不啟動(dòng)事務(wù),因此插入件不能回滾。
Auto_Commit模式是使用 SET TRANSACTION %COMMITMODE option或 SetOption()方法建立的,如下所示 SET status=$SYSTEM.SQL.Util.SetOption("AutoCommit",intval,.oldval). 可用方法INTVAL值為0(無(wú)),1(隱式)和2(顯式)。
觸發(fā)器可以在觸發(fā)器中的%MSG變量中設(shè)置錯(cuò)誤消息。此消息將返回給呼叫者,給出觸發(fā)器失敗的信息。
列出觸發(fā)器
在管理門戶SQL接口目錄詳細(xì)信息中列出了為指定表定義的觸發(fā)器。這列出了每個(gè)觸發(fā)器的基本信息。
Information.schema.triggers類列出了當(dāng)前命名空間中的定義觸發(fā)器。對(duì)于每個(gè)觸發(fā)信息.Schema.triggers列出了各種屬性,包括觸發(fā)器的名稱,關(guān)聯(lián)的架構(gòu)和表名稱,EventManipulation屬性(插入,更新,刪除,插入/更新,ActionTiming屬性(之前,之后),創(chuàng)建的屬性(觸發(fā)創(chuàng)建時(shí)間戳)和ActionStatement屬性,它是生成的SQL觸發(fā)器代碼。
創(chuàng)建的屬性從上次修改課程定義時(shí)派生觸發(fā)創(chuàng)建時(shí)間戳。因此,隨后使用此類(例如,定義其他觸發(fā)器)可能導(dǎo)致創(chuàng)建屬性值的意外更新。
可以從SQL查詢中訪問(wèn)此信息.Schema.triggers信息,如下例所示:
SELECT TABLE_NAME,TRIGGER_NAME,CREATED,EVENT_MANIPULATION,ACTION_TIMING,ACTION_ORIENTATION,ACTION_STATEMENT
FROM INFORMATION_SCHEMA.TRIGGERS WHERE TABLE_SCHEMA='SQLUser'
