เป็นไปได้หรือไม่ที่จะได้รับ call call สำหรับการเรียกใช้งานในทริกเกอร์?


16

ฉันมี 10 โพรซีเดอร์ที่เก็บไว้และแต่ละอันจะแทรกลงในหนึ่ง tableX

เป็นไปได้หรือไม่ที่ทริกเกอร์เนื้อความของ tableX จะได้รับวัตถุใดที่ทำให้เกิดการดัดแปลง tableX (เก็บไว้ proc1 หรือ sp2 หรือ .... )?

ขอขอบคุณ.

คำตอบ:


9

ใช่เป็นไปได้ที่จะระบุรหัสที่ใช้งานโดยใช้ฟังก์ชั่นระบบ @@ 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นี้


1
1) OBJECT_NAME (@@ PROCID) ในทริกเกอร์ส่งคืนชื่อทริกเกอร์ :(. 2) จำเป็นต้องมีข้อมูลที่ไก 3) context_info เป็นวิธีแก้ปัญหา ขอบคุณ
garik

1
ใช่ภายในทริกเกอร์OBJECT_NAME(@@PROCID)ส่งคืนชื่อทริกเกอร์ไม่ใช่ proc ที่เรียก
ProfK

นี่เป็นเพียงความผิดธรรมดา มันส่งคืนชื่อของทริกเกอร์ไม่ใช่ขั้นตอนการโทรตามที่ OP ถาม
วิศวกรที่กลับรายการเมื่อ

เห็นด้วยคำตอบนั้นผิด CONTEXT_INFO ใช้งานได้หากคุณสามารถแก้ไขโพรซีเดอร์อัพสตรีม
Tom Warfield

3

ฉันต้องการทำสิ่งนี้เช่นกัน ขอบคุณสำหรับคำตอบ. ขณะที่ฉันยังอยู่ที่นี่ฉันจะโพสต์การทดสอบเพื่อประหยัดเวลาผู้อื่น :)

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

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 ให้คุณทำมากกว่านี้! อย่าพลาดโอกาสที่จะเรียนรู้พวกเขา!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.