ฉันมี 10 โพรซีเดอร์ที่เก็บไว้และแต่ละอันจะแทรกลงในหนึ่ง tableX
เป็นไปได้หรือไม่ที่ทริกเกอร์เนื้อความของ tableX จะได้รับวัตถุใดที่ทำให้เกิดการดัดแปลง tableX (เก็บไว้ proc1 หรือ sp2 หรือ .... )?
ขอขอบคุณ.
ฉันมี 10 โพรซีเดอร์ที่เก็บไว้และแต่ละอันจะแทรกลงในหนึ่ง tableX
เป็นไปได้หรือไม่ที่ทริกเกอร์เนื้อความของ tableX จะได้รับวัตถุใดที่ทำให้เกิดการดัดแปลง tableX (เก็บไว้ proc1 หรือ sp2 หรือ .... )?
ขอขอบคุณ.
คำตอบ:
ใช่เป็นไปได้ที่จะระบุรหัสที่ใช้งานโดยใช้ฟังก์ชั่นระบบ @@ procidและดีกว่า OBJECT_NAME (@@ PROCID) เพื่อให้มีชื่อสมบูรณ์
คำจำกัดความ: "ส่งคืน object identifier (ID) ของโมดูล Transact-SQL ปัจจุบันโมดูล Transact-SQL สามารถเป็นกระบวนงานที่เก็บไว้ฟังก์ชันที่ผู้ใช้กำหนดเองหรือทริกเกอร์ @@ PROCID ไม่สามารถระบุได้ในโมดูล CLR หรือ in- ผู้ให้บริการเข้าถึงข้อมูลในกระบวนการ "
คุณสามารถอ่านเกี่ยวกับเรื่องนี้ที่นี่
อีกตัวเลือกหนึ่งคือการตรวจสอบแผน sql ของ spid ปัจจุบันและบันทึกข้อมูลนั้นในตารางการบันทึก ตัวอย่างแบบสอบถามที่จะใช้ในแต่ละขั้นตอนเพื่อบันทึกข้อมูลการตรวจสอบจะเป็น:
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 ปัจจุบัน และเชื่อมโยงข้อมูลบริบทที่บันทึกไว้กับแต่ละกระบวนการ ตัวอย่างเช่นในโพรซีเดอร์ 1 คุณเขียน 111 ลงในบริบทในโพรซีเดอร์ 2 คุณเขียน 222 .. และอื่น ๆ
ข้อมูลเพิ่มเติมเกี่ยวกับ context_info คุณสามารถอ่านได้ในคำถาม SOนี้
OBJECT_NAME(@@PROCID)
ส่งคืนชื่อทริกเกอร์ไม่ใช่ proc ที่เรียก
ฉันต้องการทำสิ่งนี้เช่นกัน ขอบคุณสำหรับคำตอบ. ขณะที่ฉันยังอยู่ที่นี่ฉันจะโพสต์การทดสอบเพื่อประหยัดเวลาผู้อื่น :)
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 stack แม้ว่า SQL Server 2008 อาจไม่สนับสนุนประเภทเหตุการณ์ที่ใช้ โซลูชันประกอบด้วยทริกเกอร์ข้อผิดพลาดและเซสชัน XEvent ฉันใช้ตัวอย่างของ Jim Brown เพื่อแสดงวิธีการทำงาน
ก่อนอื่นผมทดสอบวิธีแก้ปัญหาสำหรับ SQL Server 2016 SP2CU2 Dev Edition SQL Server 2008 รองรับ EXEENT บางตัว แต่ฉันไม่มีอินสแตนซ์ใด ๆ ดังนั้นฉันจึงไม่สามารถทดสอบได้
แนวคิดคือการสร้างข้อผิดพลาดของผู้ใช้ในบล็อก try-catch จำลองจากนั้นจับข้อผิดพลาดภายในเซสชัน XEvent ด้วยtsql_stack
แอ็คชัน SQLSERVER.error_reported
ประเภท XEvent สามารถดักจับข้อผิดพลาดทั้งหมดได้แม้ว่าบล็อก try-catch จะดักจับพวกมัน ในท้ายที่สุดsys.dm_exec_sql_text
แยกแบบสอบถาม T-SQL จากแบบสอบถามจัดการtsql_stack
การกระทำที่ให้
ตัวอย่างจากคำตอบของจิมบราวน์ที่ฉันพัฒนาแสดงไว้ด้านล่าง ทริกเกอร์ทำให้เกิดข้อผิดพลาดกับข้อความ 'จับฉัน' เซสชั่น 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, วัตถุ Explorer, การบริหารจัดการ, กิจกรรมขยายบำบัด catch_insertion_into_Test) ดำเนินการ usp_RootProcIDTest และมองบัฟเฟอร์แหวนเซสชั่น XEvent ของคุณควรจะเห็น XML <action name="tsql_stack" package="sqlserver">
ซึ่งประกอบด้วยโหนด มีลำดับของโหนดเฟรม ใส่ค่าของhandle
แอตทริบิวต์ของลงในฟังก์ชั่นระบบ 'sys.dm_exec_sql_text' และ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);
XEvent ให้คุณทำมากกว่านี้! อย่าพลาดโอกาสที่จะเรียนรู้พวกเขา!