Можно ли получить стек вызовов выполнения в триггере?

dba.stackexchange https://dba.stackexchange.com/questions/3815

  •  16-10-2019
  •  | 
  •  

Вопрос

У меня есть 10 сохраненных процедур, и каждый из них делает вставки в один TableX.

Возможно ли в тележек -теле TableX, чтобы получить, какой объект вызывает модификацию TableX (сохраненный Proc1 или Sp2 или ....)?

Спасибо.

Это было полезно?

Решение

Да, можно определить запущенный код, по Использование функции системы @@ procid, и лучший object_name (@@ procid), чтобы иметь полное имя.

Определение: «Возвращает идентификатор объекта (ID) текущего модуля Transact-SQL. Модуль Transact-SQL может быть хранимой процедурой, определенной пользователем функцией или триггером. @@ Procid не может быть указан в модулях CLR или в Процесс доступа к данным. "

Вы можете прочитать об этом здесь.

Другой вариант - это было бы Проверьте план 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

Может быть, там слишком много деталей ... но я считаю, что вы поняли идею.

Третий вариант - это использовать контекст_инфо Информация к текущей сессии SP. И ассоциируйте где -нибудь контекстная информация, сохраняемая там с каждой процедурой. Например, в процедуре1 вы пишете 111 в контексте, в процедуре 2 вы пишете 222 .. и так далее.

Намного больше информации о контексте_инфо, в котором вы можете прочитать это так вопрос.

Другие советы

Я тоже хотел это сделать. Спасибо за ответ. Как я все еще здесь, я опубликую свой тест, чтобы сэкономить время другим :)

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

Xevents предоставляет еще один способ получить известность стека T-SQL, хотя SQL Server 2008 может не поддерживать тип использованного события. Решение состоит из триггера, ошибки и сеанса Xevent. Я взял пример Джима Брауна, чтобы показать, как это работает.

Прежде всего, я протестировал решение для SQL Server 2016 SP2CU2 DevEd. SQL Server 2008 поддерживает некоторое преувеличение, но у меня нет никакого экземпляра, поэтому я не мог его проверить.

Идея состоит в том, чтобы сгенерировать ошибку пользователя в фиктивном блоке Try-Catch, затем поймайте ошибку в сеансе Xevent с tsql_stack действие. SQLSERVER.error_reported Тип Xevent может поймать все ошибки, даже несмотря на то, что блок-блок Try-Catch их ловит. В конце, sys.dm_exec_sql_text Извлеките запросы t-sql из ручек запроса, которые tsql_stack Действие дает.

Пример из ответа Джима Брауна, который я разработал, показан ниже. Триггер поднимает ошибку с текстом «Поймай меня». Сеанс 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 (SSMS, Explorer, Management, расширенные события, сеансы, 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);

An execution call stack example

Xevent позволяет вам сделать гораздо больше, чем это! Не упустите возможности их выучить!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с dba.stackexchange
scroll top