web-dev-qa-db-fra.com

Requête d'audit SQL Server qui tire une gâchette

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

5
jviladrich

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.

4
db2

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 à:

enter image description here

3
Ivan Stankovic

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.

3
David Spillett