Apakah mungkin untuk mendapatkan tumpukan panggilan eksekusi di pemicu?

16

Saya memiliki 10 prosedur tersimpan dan masing-masing melakukan INSERT menjadi satu tableX.

Apakah mungkin dalam tubuh pemicu tableX untuk mendapatkan objek apa yang menyebabkan modifikasi tableX (disimpan proc1 atau sp2 atau ....)?

Terima kasih.

garik
sumber

Jawaban:

9

Ya, adalah mungkin untuk mengidentifikasi kode yang sedang berjalan, dengan menggunakan fungsi sistem @@ procid , dan OBJECT_NAME (@@ PROCID) yang lebih baik untuk memiliki nama lengkap.

Definisi: "Mengembalikan objek pengidentifikasi (ID) dari modul Transact-SQL saat ini. Modul Transact-SQL dapat berupa prosedur tersimpan, fungsi yang ditentukan pengguna, atau pemicu. @@ PROCID tidak dapat ditentukan dalam modul CLR atau modul memproses penyedia akses data. "

Anda dapat membacanya di sini .

Opsi lain adalah memeriksa paket sql dari spid saat ini dan menyimpan info itu di tabel logging. Kueri sampel yang akan digunakan dalam setiap prosedur untuk menyimpan data audit adalah:

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

Mungkin ada terlalu banyak detail di sana..tapi saya percaya Anda mendapatkan idenya.

Opsi ketiga adalah menggunakan informasi context_info untuk sesi SP saat ini. Dan kaitkan suatu tempat informasi konteks disimpan di sana dengan setiap prosedur. Misalnya dalam procedure1 Anda menulis 111 ke konteks, di procedure2 Anda menulis 222 .. dan seterusnya

Lebih banyak info mengenai context_info yang dapat Anda baca dalam pertanyaan SO ini .

Marian
sumber
1
1) OBJECT_NAME (@@ PROCID) di trigger memicu return name :(. 2) perlu memiliki informasi hanya di trigger. 3) context_info adalah solusi. Terima kasih.
garik
1
Ya, di dalam pemicu OBJECT_NAME(@@PROCID)mengembalikan nama pemicu, bukan proc panggilan.
ProfK
Ini benar-benar salah. Ini mengembalikan nama pemicu, bukan prosedur panggilan saat OP bertanya
Reversed Engineer
Setuju, jawabannya salah. CONTEXT_INFO berfungsi jika Anda dapat mengubah prosedur hulu.
Tom Warfield
3

Saya ingin melakukan ini juga. Terima kasih atas jawabannya. Karena saya masih di sini, saya akan memposting tes saya untuk menghemat waktu orang lain :)

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
Jim Brown
sumber
2

XEvents menyediakan cara lain untuk mengenal tumpukan T-SQL meskipun SQL Server 2008 mungkin tidak mendukung jenis peristiwa yang digunakan. Solusi terdiri dari pemicu, kesalahan, dan sesi XEvent. Saya mengambil contoh Jim Brown untuk menunjukkan cara kerjanya.

Pertama-tama, saya menguji solusi untuk SQL Server 2016 SP2CU2 Dev Edition. SQL Server 2008 mendukung beberapa EXevent, tapi saya tidak punya contoh sehingga saya tidak bisa mengujinya.

Idenya adalah untuk menghasilkan kesalahan pengguna di blok try-catch dummy, kemudian menangkap kesalahan di dalam sesi XEvent dengan tsql_stacktindakan. SQLSERVER.error_reportedTipe XEvent dapat menangkap semua kesalahan meskipun blok try-catch menjebaknya. Pada akhirnya, sys.dm_exec_sql_textekstrak kueri T-SQL dari kueri menangani tsql_stacktindakan yang diberikan.

Contoh dari jawaban Jim Brown, yang saya kembangkan, ditunjukkan di bawah ini. Pemicu memunculkan kesalahan dengan teks 'tangkap aku'. Sesi XEvent menangkap kesalahan hanya dengan teks seperti 'tangkap saya'.

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

Sekarang, jika Anda meluncurkan sesi XEvent (SSMS, Object Explorer, Manajemen, Acara yang Diperpanjang, Sesi, catch_insertion_into_Test), jalankan usp_RootProcIDTest dan lihat buffer cincin sesi XEvent, Anda akan melihat XML yang terdiri dari node <action name="tsql_stack" package="sqlserver">. Ada urutan frame node. Masukkan nilai handleatribut 's ke fungsi sistem' sys.dm_exec_sql_text ', dan 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);

Contoh tumpukan panggilan eksekusi

XEvent membiarkan Anda melakukan lebih dari ini! Jangan lewatkan kesempatan untuk mempelajarinya!

Basil Kisel
sumber