Bir tetikleyicide yürütme çağrısı yığını almak mümkün mü?


16

10 saklı yordam var ve her biri bir tableX ekler.

TableX'in bir tetikleme gövdesinde hangi nesnenin tableX (depolanmış proc1 veya sp2 veya ....) değişikliğine neden olduğunu elde etmek mümkün müdür?

Teşekkür ederim.

Yanıtlar:


9

Evet, @@ procid sistem işlevini ve tam adı almak için daha iyi OBJECT_NAME (@@ PROCID) kullanarak çalışan kodu tanımlamak mümkündür .

Tanım: "Geçerli Transact-SQL modülünün nesne tanımlayıcısını (ID) döndürür. Transact-SQL modülü saklı yordam, kullanıcı tanımlı işlev veya tetikleyici olabilir. @@ PROCID CLR modüllerinde veya in- işlem veri erişim sağlayıcısı. "

Burada okuyabilirsiniz .

Başka bir seçenek , geçerli örgünün sql planını kontrol etmek ve bu bilgileri bir kayıt tablosuna kaydetmek olacaktır. Denetim verilerini kaydetmek için her prosedürde kullanılacak örnek bir sorgu şöyle olacaktır:

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

Belki orada çok fazla detay var ... ama bu fikri anladığınıza inanıyorum.

Üçüncü seçenek , geçerli SP oturumu için context_info bilgisini kullanmak olacaktır . Ve orada kaydedilen bağlam bilgisini her prosedürle bir yerde ilişkilendirin. Örneğin, yordam1'de bağlama 111 yazılır, yordam2'de 222 yazarsınız vb.

Context_info ile ilgili daha fazla bilgiyi bu SO sorusunda okuyabilirsiniz .


1
1) Tetikleyicideki OBJECT_NAME (@@ PROCID) tetikleyici adını döndürür :(. 2) sadece tetikleyicide bilgi olması gerekir. 3) context_info bir çözümdür. Teşekkürler.
garik

1
Evet, bir tetikleyicinin içinde OBJECT_NAME(@@PROCID)tetikleyici adı döner, çağıran proc değil.
ProfK

Bu sadece yanlış. OP'nin istediği gibi çağıran prosedürün değil, tetikleyicinin adını döndürür
Ters Mühendis

Kabul ediyorum, cevap yanlış. Akış yukarı yordamı değiştirebiliyorsanız CONTEXT_INFO çalışır.
Tom Warfield

3

Bunu ben de yapmak istedim. Cevap için teşekkürler. Hala burada olduğum için testimi başkalarına zaman kazandırmak için göndereceğim :)

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 kullanılan bir olay türünü desteklemese de, XEvents bir T-SQL yığını bilinmesi için başka bir yol sağlar. Çözüm bir tetikleyici, bir hata ve bir XEvent oturumundan oluşur. Jim Brown'un nasıl çalıştığını göstermek için örnek aldım.

Her şeyden önce, çözümü SQL Server 2016 SP2CU2 Dev Edition için test ettim. SQL Server 2008 bazı EXevent'i destekler, ancak test edemediğim için herhangi bir örneğim yok.

Fikir, sahte bir try-catch bloğunda bir kullanıcı hatası oluşturmak, ardından eylemle bir XEvent oturumu içinde hatayı yakalamaktır tsql_stack. SQLSERVER.error_reportedXEvent türü, bir try-catch bloğu yakalasa bile tüm hataları yakalayabilir. Sonunda, sys.dm_exec_sql_texthangi tsql_stackeylem verir sorgu tanıtıcılarından T-SQL sorguları ayıklayın .

Geliştirdiğim Jim Brown cevabından bir örnek aşağıda gösterilmiştir. Bir tetikleyici 'beni yakala' metniyle hatayı yükseltir. XEvent oturumu yalnızca 'beni yakala' gibi metinlerle hataları yakalar.

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

Şimdi, XEvent oturumunu (SSMS, Nesne Gezgini, Yönetim, Genişletilmiş Olaylar, Oturumlar, catch_insertion_into_Test) başlatırsanız, usp_RootProcIDTest'i çalıştırır ve XEvent oturumunun halka arabelleğine bakarsanız, düğümü içeren XML'yi görmelisiniz <action name="tsql_stack" package="sqlserver">. Bir dizi kare düğüm vardır. Bir handle'özniteliğinin değerlerini ' sys.dm_exec_sql_text 'sistem işlevine koyun ve voilà:

-- 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);

Bir yürütme çağrısı yığını örneği

XEvent bundan daha fazlasını yapmanıza izin verir! Onları öğrenme fırsatlarını kaçırmayın!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.