是否可以在触发器中获取执行调用堆栈?

gar*_*rik 18 trigger sql-server-2008

我有 10 个存储过程,每个存储过程都将 INSERT 插入到一个 tableX 中。

是否可以在 tableX 的触发器主体中获取导致 tableX 修改的对象(存储的 proc1 或 sp2 或....)?

谢谢你。

Mar*_*ian 10

是的,可以通过使用@@procid 系统函数和更好的 OBJECT_NAME(@@PROCID) 来识别正在运行的代码,以获得完整的名称。

定义:“返回当前 Transact-SQL 模块的对象标识符 (ID)。Transact-SQL 模块可以是存储过程、用户定义函数或触发器。@@PROCID 不能在 CLR 模块中指定,也不能在过程数据访问提供程序。”

你可以在这里阅读它。

另一种选择是检查当前 spid 的 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
Run Code Online (Sandbox Code Playgroud)

也许那里有太多细节......但我相信你明白了。

第三种选择是context_info信息用于当前 SP 的会话。并将保存在那里的上下文信息与每个过程相关联。例如,在程序 1 中,您将 111 写入上下文,在程序 2 中,您将写入 222.. 等等。

您可以在此 SO question 中阅读有关 context_info 的更多信息。

  • 1) 触发器中的 OBJECT_NAME(@@PROCID) 返回触发器名称 :(. 2) 必须在触发器处获取信息。3) context_info 是一个解决方案。谢谢。 (2认同)
  • 是的,在触发器`OBJECT_NAME(@@PROCID)` 中返回触发器名称,而不是调用过程。 (2认同)
  • 这完全是错误的。它返回触发器的名称,而不是OP要求的调用过程的名称 (2认同)

Bas*_*sel 5

XEvents 提供了另一种了解 T-SQL 堆栈的方法,尽管 SQL Server 2008 可能不支持所使用的事件类型。该解决方案由触发器、错误和 XEvent 会话组成。我以吉姆·布朗的例子来展示它的工作原理。

\n\n

首先,我测试了SQL Server 2016 SP2CU2 Dev Edition的解决方案。SQL Server 2008支持一些EXevent,但我没有任何实例,因此无法测试它。

\n\n

这个想法是在虚拟的 try-catch 块中生成用户错误,然后通过操作捕获 XEvent 会话中的错误tsql_stackSQLSERVER.error_reportedXEvent 类型可以捕获所有错误,即使 try-catch 块捕获了这些错误。最后,sys.dm_exec_sql_text从操作给出的查询句柄中提取 T-SQL 查询tsql_stack

\n\n

我开发的吉姆·布朗答案中的一个例子如下所示。触发器会引发带有文本“catch me”的错误。XEvent 会话仅捕获诸如“catch me”之类的文本的错误。

\n\n
CREATE TABLE  Test ( TestID INT )\n\nGO\n\nCREATE TRIGGER TestTrigger ON Test\nFOR INSERT\nAS\nBEGIN TRY\n    SET XACT_ABORT OFF; -- REALLY IMPORTANT!\n    /* make an catching a great deal more interesting */\n    DECLARE @TestID NVARCHAR(MAX) ;\n    SELECT TOP (1) @TestID = CAST(ins.TestID AS NVARCHAR(MAX)) FROM inserted AS ins ;\n    RAISERROR (N\'catch_me TestID = "%s"\' , 11 , 0 , @TestID) ;\nEND TRY BEGIN CATCH /* NOTHING TO DO */ END CATCH\n\nGO\n\nCREATE PROCEDURE usp_ProcIDTest\nAS\nINSERT INTO Test ( TestID ) VALUES ( 1 ) \n\nGO\n\nCREATE PROCEDURE usp_RootProcIDTest\nAS\nEXEC usp_ProcIDTest\n\nGO\n\n-- This XEvent session definition was kindly provided by XEvent \'New Session\' wizard.\nCREATE EVENT SESSION [catch_insertion_into_Test] ON SERVER \nADD EVENT sqlserver.error_reported(\n    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)\n    WHERE ([message] like N\'catch_me%\'))\nADD TARGET package0.ring_buffer(SET max_memory=(10240))\nWITH (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)\n\nGO\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,如果您启动 XEvent 会话(SSMS、对象资源管理器、管理、扩展事件、会话、catch_insertion_into_Test),执行 usp_RootProcIDTest 并查看 XEvent 会话的环形缓冲区,您应该看到包含节点的 XML <action name="tsql_stack" package="sqlserver">。存在一系列框架节点。将a的属性值handle放入系统函数“sys.dm_exec_sql_text”中,然后查看\xc3\xa0:

\n\n
-- REPLACE MY HANDLES WITH YOURS\nSELECT * FROM sys.dm_exec_sql_text(0x03000800D153096910272C01A6AA000000000000000000000000000000000000000000000000000000000000);\nSELECT * FROM sys.dm_exec_sql_text(0x030008000A78FD6912272C01A6AA000001000000000000000000000000000000000000000000000000000000);\nSELECT * FROM sys.dm_exec_sql_text(0x03000800439CF16A13272C01A6AA000001000000000000000000000000000000000000000000000000000000);\n
Run Code Online (Sandbox Code Playgroud)\n\n

执行调用堆栈示例

\n\n

XEvent 让您做的远不止这些!不要错过学习它们的机会!

\n