Можно ли получить стек вызовов выполнения в триггере?
-
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);
Xevent позволяет вам сделать гораздо больше, чем это! Не упустите возможности их выучить!