トリガーで実行呼び出しスタックを取得することは可能ですか?


16

10個のストアドプロシージャがあり、それぞれが1つのtableXにINSERTします。

tableXのトリガー本体で、tableXの変更を引き起こすオブジェクトを取得することは可能ですか(proc1またはsp2または...を格納)?

ありがとうございました。

回答:


9

はい、@@ procidシステム関数を使用して実行中のコードを識別し、完全な名前を付けるためにOBJECT_NAME(@@ PROCID)を使用できます。

定義:「現在のTransact-SQLモジュールのオブジェクト識別子(ID)を返します。Transact-SQLモジュールは、ストアドプロシージャ、ユーザー定義関数、またはトリガーになります。@@ PROCIDはCLRモジュールまたはin-プロセスデータアクセスプロバイダー。」

あなたはここでそれについて読むことができます

別のオプションは、現在の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

そこには詳細が多すぎるかもしれません。しかし、私はあなたがアイデアを得ると信じています。

3番目のオプションはcontext_info情報を現在のSPのセッションに使用することです。そして、そこに保存されたコンテキスト情報を各手順に関連付けます。たとえば、procedure1では111をコンテキストに書き込み、procedure2では222 ..を書き込みます。

context_infoに関する詳細情報は、このSOの質問で読むことができます。


1
1)トリガー内のOBJECT_NAME(@@ PROCID)はトリガー名を返します:(。2)トリガーの位置に情報が必要です。3)context_infoは解決策です。ありがとう。
ガリック

1
トリガー内OBJECT_NAME(@@PROCID)では、呼び出し側のプロシージャではなくトリガー名が返されます。
-ProfK

これは明らかに間違っています。OPが要求した呼び出し元のプロシージャの名前ではなく、トリガーの名前を返します
リバースエンジニア

同意し、答えは間違っています。アップストリームプロシージャを変更できる場合、CONTEXT_INFOは機能します。
トムウォーフィールド

3

私もこれをやりたかった。答えてくれてありがとう。私はまだここにいるので、他の人の時間を節約するためにテストを投稿します:)

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

2

XEventsは、SQL Server 2008が使用されたイベントタイプをサポートしていない場合でも、T-SQLスタックを知るための別の方法を提供します。ソリューションは、トリガー、エラー、およびXEventセッションで構成されます。私はジム・ブラウンの例を取り上げて、その仕組みを示しました。

まず、SQL Server 2016 SP2CU2 Dev Editionのソリューションをテストしました。SQL Server 2008はいくつかのEXeventをサポートしますが、テストできないようにインスタンスがありません。

アイデアは、ダミーのtry-catchブロックでユーザーエラーを生成し、tsql_stackアクションを使用してXEventセッション内でエラーをキャッチすることです。SQLSERVER.error_reportedXEventタイプは、try-catchブロックがエラーをトラップしても、すべてのエラーをキャッチできます。最後に、アクションが与えるsys.dm_exec_sql_textクエリハンドルからT-SQLクエリを抽出しますtsql_stack

私が開発したジムブラウンの回答の例を以下に示します。トリガーは、テキスト「catch me」でエラーを発生させます。XEventセッションは、「catch me」などのテキストでのみエラーをキャッチします。

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セッション(SSMS、オブジェクトエクスプローラー、管理、拡張イベント、セッション、catch_insertion_into_Test)を起動し、usp_RootProcIDTestを実行してXEventセッションのリングバッファーを調べると、ノードを構成するXMLが表示されます<action name="tsql_stack" package="sqlserver">。一連のフレームノードがあります。handleの属性の値をシステム関数「sys.dm_exec_sql_text」に入れてください。

-- 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を使用すると、これ以上のことができます。それらを学ぶ機会をお見逃しなく!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.