I am working on a mutation test framework for SQL Server, for this I need to be able to calculate what lines of a stored procedure, function or trigger are executed when I execute a certain stored procedure.
The difficult part is that I want to know the exact lines or statements being executed from the stored procedure I call.
With a query like this I can see what stored procedures/triggers/functions are being executed, since I know when I call the stored procedure I can use the time to see if it was executed.
SELECT d.object_id, d.database_id,
OBJECT_NAME(object_id, database_id) AS proc_name,
MAX( d.last_execution_time) as last_execution_time,
OBJECT_DEFINITION(object_id) as definition
FROM sys.dm_exec_procedure_stats AS d
WHERE d.database_id = DB_ID()
GROUP BY d.object_id, d.database_id,
OBJECT_NAME(object_id, database_id)
How would I find the lines/statements that have been executed, I also have to know inside what stored procedure/trigger/function the lines/statements exists and in which shema this is. I have to take into account that a IF/ELSE statement may be used.
With this data I can do 2 important things:
- generate a code coverage report
- optimize what lines to mutate, since I dont have to mutate uncovered lines.
A possible, but not a very nice, solution would be to automaticly change stored procedures to add a line that inserts the previous line into a table, but this will require splitting up the procedure into statements, which I don't know how to do.
Please note that I cannot change the code users want to test with my framework. I can search for patterns and replace but manually changing procedures is NOT a option.
EDIT: Lets redifine this question: How to split a stored procedure definition into its different statements in a way that does not depend on code style? and How to add a new statement in between found statements?
EDIT: in the SO post SQL Server: How to parse code into its different statements I have found a way to trace statement execution, but I can't filter it yet.
So the extended events are the solution, this is how I have done it:
This creates an event that can be fired after every statement completion, this is done dynamicly to filter on the database
Then I have 3 procedures that make controlling this event easy
These procedures respectivly start and stop the trace and the last one stores the result in a table where it filters on the nest level so my own code is not traced.
Finally I use it a bit like this:
Special thanks to @Jeroen Mosterd for originally coming up with a proposal for this solution in this SQL Server: How to parse code into its different statements SO post
You can either:
With the @Debug parameter, you can default it to OFF, then call it with ON when you want to trace your statements, with the following code:
If you want to log everything, create a log table and insert a row into it wherever you need to know which statement was executed, such as:
and
Or you can combine them:
Of course these will affect performance even when you don't output/log.