是否可以在触发器中获取执行呼叫堆栈?
-
16-10-2019 - |
题
我有10个存储过程,每个过程都会插入一个tablex。
在Tablex的触发器主体中是否有可能导致TableX的修改(存储的Proc1或Sp2或....)?
谢谢你。
解决方案
是的,可以通过 使用@@ procid系统功能, ,以及更好的object_name(@@ procid)具有完整的名称。
定义:“返回当前Transact-SQL模块的对象标识符(ID)。transact-SQL模块可以是存储过程,用户定义的函数或触发器。处理数据访问提供商。”
你可以阅读 这里.
另一个选择是 检查当前蜘蛛的SQL计划 并将该信息保存在记录表中。每个过程中要使用以保存审核数据的示例查询将是:
select sp.hostname, sp.program_name, sp.loginame,
st.text as query_text
from sysprocesses sp
cross apply sys.dm_exec_sql_text(sp.sql_handle) as st
where sp.spid = @@spid
也许那里有太多细节..但是我相信您明白了。
第三种选择是 使用 context_info 信息 到当前SP的会话。并将保存在此处的上下文信息与每个过程相关联。例如,在过程1中,您将111写入上下文,在过程2中,您编写222 ..等等。
您可以阅读有关Context_info的更多信息 这个问题.
其他提示
我也想这样做。感谢你的回答。当我仍然在这里时,我会发布测试以节省其他时间:)
CREATE TABLE Test ( TestID INT )
GO
CREATE TRIGGER TestTrigger ON Test
FOR INSERT
AS
SELECT CAST(CONTEXT_INFO() AS NVARCHAR(128));
GO
CREATE PROCEDURE usp_ProcIDTest
AS
DECLARE @ProcedureName VARBINARY(MAX) = CAST(OBJECT_NAME(@@PROCID) AS VARBINARY(MAX))
SET CONTEXT_INFO @ProcedureName
INSERT INTO Test ( TestID ) VALUES ( 1 )
GO
EXEC usp_ProcIDTest
GO
DROP TABLE Test
GO
尽管SQL Server 2008可能不支持二手事件类型,但XEVENT提供了一种获取T-SQL堆栈的另一种方法。该解决方案由触发器,错误和XEVENT会话组成。我以吉姆·布朗(Jim Brown)的榜样来展示它的工作方式。
首先,我测试了SQL Server 2016 SP2CU2 DEV版本的解决方案。 SQL Server 2008支持一些exevent,但我没有任何实例,因此我无法测试它。
这个想法是在虚拟try-catch块中生成用户错误,然后在xevent会话中捕获错误 tsql_stack
行动。 SQLSERVER.error_reported
即使try-Catch块陷入困境,Xevent类型也可以捕获所有错误。到底, sys.dm_exec_sql_text
从查询手柄中提取T-SQL查询 tsql_stack
行动给出。
我开发的吉姆·布朗(Jim Brown)答案的一个例子如下所示。触发器通过文字“抓住我”提出了错误。 Xevent会话只有在“抓住我”之类的文本中捕获错误。
CREATE TABLE Test ( TestID INT )
GO
CREATE TRIGGER TestTrigger ON Test
FOR INSERT
AS
BEGIN TRY
SET XACT_ABORT OFF; -- REALLY IMPORTANT!
/* make an catching a great deal more interesting */
DECLARE @TestID NVARCHAR(MAX) ;
SELECT TOP (1) @TestID = CAST(ins.TestID AS NVARCHAR(MAX)) FROM inserted AS ins ;
RAISERROR (N'catch_me TestID = "%s"' , 11 , 0 , @TestID) ;
END TRY BEGIN CATCH /* NOTHING TO DO */ END CATCH
GO
CREATE PROCEDURE usp_ProcIDTest
AS
INSERT INTO Test ( TestID ) VALUES ( 1 )
GO
CREATE PROCEDURE usp_RootProcIDTest
AS
EXEC usp_ProcIDTest
GO
-- This XEvent session definition was kindly provided by XEvent 'New Session' wizard.
CREATE EVENT SESSION [catch_insertion_into_Test] ON SERVER
ADD EVENT sqlserver.error_reported(
ACTION(package0.callstack,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.client_pid,sqlserver.database_id,sqlserver.query_hash,sqlserver.query_plan_hash,sqlserver.server_principal_name,sqlserver.session_id,sqlserver.session_nt_username,sqlserver.sql_text,sqlserver.tsql_frame,sqlserver.tsql_stack,sqlserver.username,sqlserver.context_info,sqlserver.plan_handle)
WHERE ([message] like N'catch_me%'))
ADD TARGET package0.ring_buffer(SET max_memory=(10240))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=ON)
GO
现在,如果您启动XEvent会话(SSM,Object Explorer,管理,扩展事件,会话,Catch_insertion_into_test),执行USP_ROOTPROCIDTEST并查看XEVENT会话的戒指缓冲区,则应看到XML,该XML组成节点 <action name="tsql_stack" package="sqlserver">
. 。有一系列帧节点。放置一个值 handle
的属性到系统函数'sys.dm_exec_sql_text'和voilà:
-- REPLACE MY HANDLES WITH YOURS
SELECT * FROM sys.dm_exec_sql_text(0x03000800D153096910272C01A6AA000000000000000000000000000000000000000000000000000000000000);
SELECT * FROM sys.dm_exec_sql_text(0x030008000A78FD6912272C01A6AA000001000000000000000000000000000000000000000000000000000000);
SELECT * FROM sys.dm_exec_sql_text(0x03000800439CF16A13272C01A6AA000001000000000000000000000000000000000000000000000000000000);
XEvent让您做的不仅仅是这样!不要错过学习它们的机会!