트리거에서 실행 호출 스택을 얻을 수 있습니까?


16

나는 10 개의 저장 프로 시저를 가지고 있으며 각각은 하나의 tableX에 INSERT를 수행합니다.

tableX의 트리거 본문에서 tableX (저장된 proc1 또는 sp2 또는 ....)를 수정하는 오브젝트를 얻을 수 있습니까?

감사합니다.

답변:


9

예, @@ 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

세부 정보가 너무 많을 수 있습니다.하지만 아이디어가 있다고 생각합니다.

세 번째 옵션은하는 것 사용 CONTEXT_INFO의 정보 는 현재 SP의 세션을. 거기에 저장된 컨텍스트 정보를 각 프로 시저와 어딘가에 연관 시키십시오. 예를 들어, procedure1에서는 컨텍스트에 111을 쓰고, procedure2에는 222 .. 등을 씁니다.

이 SO 질문 에서 읽을 수있는 context_info에 관한 훨씬 더 많은 정보 .


1
1) 트리거의 OBJECT_NAME (@@ PROCID)은 트리거 이름을 반환합니다. (. 2) 트리거에 대한 정보 만 있으면됩니다. 3) context_info는 해결책입니다. 감사.
garik

1
예, 트리거 내부 OBJECT_NAME(@@PROCID)에서는 호출하는 proc이 아닌 트리거 이름을 반환합니다.
ProfK

이것은 명백한 잘못입니다. OP가 요청한대로 호출 절차가 아닌 트리거 이름을 반환합니다.
리버스 엔지니어

동의합니다. 답변이 잘못되었습니다. 업스트림 프로 시저를 수정할 수 있으면 CONTEXT_INFO가 작동합니다.
Tom Warfield

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

SQL Server 2008은 사용 된 이벤트 유형을 지원하지 않을 수 있지만 XEvents는 T-SQL 스택을 알 수있는 또 다른 방법을 제공합니다. 솔루션은 트리거, 오류 및 XEvent 세션으로 구성됩니다. Jim Brown의 사례를 통해 작동 방식을 보여주었습니다.

우선, SQL Server 2016 SP2CU2 Dev Edition 용 솔루션을 테스트했습니다. SQL Server 2008은 일부 EXevent를 지원하지만 테스트 할 수없는 인스턴스가 없습니다.

아이디어는 더미 try-catch 블록에서 사용자 오류를 생성 한 다음 tsql_stack조치를 통해 XEvent 세션 내에서 오류를 포착하는 것 입니다. SQLSERVER.error_reportedtry-catch 블록이 오류를 포착하더라도 XEvent 유형은 모든 오류를 포착 할 수 있습니다. 결국, sys.dm_exec_sql_text어떤 tsql_stack조치가 제공 하는 쿼리 핸들에서 T-SQL 쿼리를 추출하십시오 .

내가 개발 한 Jim Brown의 답변의 예가 아래에 나와 있습니다. 트리거는 '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.