Utilisation de SQL Server, existe-t-il un moyen d'audit de l'intérieur d'un déclencheur du SQL qui le tire?
J'ai besoin de connaître la requête SQL qui tire une gâchette sur une base de données sans profileur.
Merci
J'ai un certain nombre de déclencheurs qui font cela et je trouve que DBCC INPUTBUFFER
est généralement la meilleure façon de le faire. Attention: la sortie est limitée à 4000 caractères. Très longues requêtes seront tronquées.
DECLARE @sql nvarchar(max)
SET @sql = 'DBCC INPUTBUFFER(' + CAST(@@SPID AS nvarchar(100)) + ')'
CREATE TABLE #SQL (
EventType varchar(100),
Parameters int,
EventInfo nvarchar(max)
)
INSERT INTO #SQL
EXEC sp_executesql @sql
SELECT @sql = EventInfo FROM #SQL
DROP TABLE #SQL
À la fin de cela, @sql
contient la requête pour la demande actuelle. De plus, vous pouvez aussi facilement utiliser une variable de table au lieu d'une table Temp.
Voici l'échantillon de la gâchette DDL qui capture également la requête SQL:
CREATE TRIGGER Audit_DDL
ON DATABASE
FOR CREATE_TABLE, ALTER_TABLE, DROP_TABLE
AS
DECLARE
@event xml;
SET
@event = EVENTDATA();
INSERT INTO Audit_DDL_Events
VALUES
(
REPLACE(CONVERT(varchar(50),
@event.query('data(/EVENT_INSTANCE/PostTime)')), 'T', ' ')
,
CONVERT(varchar(150),
@event.query('data(/EVENT_INSTANCE/LoginName)'))
,
CONVERT(varchar(150),
@event.query('data(/EVENT_INSTANCE/UserName)'))
,
CONVERT(varchar(150),
@event.query('data(/EVENT_INSTANCE/DatabaseName)'))
,
CONVERT(varchar(150),
@event.query('data(/EVENT_INSTANCE/SchemaName)'))
,
CONVERT(varchar(150),
@event.query('data(/EVENT_INSTANCE/ObjectName)'))
,
CONVERT(varchar(150),
@event.query('data(/EVENT_INSTANCE/ObjectType)'))
,
CONVERT(varchar(max),
@event.query('data(/EVENT_INSTANCE/TSQLCommand/CommandText)'))
);
Les résultats du tableau approprié:
CREATE TABLE Audit_DDL_Events
(
DDL_Event_Time datetime
,
DDL_Login_Name varchar(150)
,
DDL_User_Name varchar(150)
,
DDL_Database_Name varchar(150)
,
DDL_Schema_Name varchar(150)
,
DDL_Object_Name varchar(150)
,
DDL_Object_Type varchar(150)
,
DDL_Command varchar(max)
);
ressemblerait à:
Ce qui suit semble faire l'affaire pour récupérer le lot/déclaration actuelle:
SELECT current_batch = dest.text
, current_statement = SUBSTRING(dest.text, dem.statement_start_offset/2, CASE WHEN dem.statement_end_offset=-1 THEN 8000 ELSE (dem.statement_end_offset-dem.statement_start_offset)/2 END)
FROM sys.dm_exec_requests dem CROSS APPLY sys.dm_exec_sql_text(dem.sql_handle) dest
WHERE session_id = @@SPID
bien que IIRC si l'appel soit à une procédure stockée, vous pouvez obtenir le code de la procédure renvoyé plutôt que le texte de l'appel en fonction de la manière dont la demande a été soumise (ad-hoc SQL, appel de procédure préparé, etc ...). Je ne sais pas si dans un déclencheur, vous finirez par obtenir le code de la gâchette au lieu de ce que vous recherchez, vous devez donc tester cela.
Pour voir la différence entre le lot et la déclaration, courez quelque chose comme:
DECLARE @current_batch NVARCHAR(MAX), @current_statement NVARCHAR(MAX)
-- start of statement that will be returned by itself
SELECT @current_batch = dest.text
, @current_statement = SUBSTRING(dest.text, dem.statement_start_offset/2, CASE WHEN dem.statement_end_offset=-1 THEN 8000 ELSE (dem.statement_end_offset-dem.statement_start_offset)/2 END)
FROM sys.dm_exec_requests dem CROSS APPLY sys.dm_exec_sql_text(dem.sql_handle) dest
WHERE session_id = @@SPID
-- end of statement that will be returned by itself
-- results:
PRINT '---- BATCH --------------------------------------------'
PRINT @current_batch
PRINT '---- STATEMENT ----------------------------------------'
PRINT @current_statement
via SQL Server Management Studio ou similaire.