SQL服务器:如何将代码解析成不同的语句
SQL Server: How to parse code into its different statements
作为 的可能解决方案,我建议我可以在每个语句之后添加插入语句。
有什么有效的方法可以将存储过程的代码拆分成不同的语句,以便在每个语句之后可以添加一个带有前一行的额外插入语句?如果完全相同的行在 procedure/function/trigger 中出现了不止一次,它们也需要用一些数字来唯一化。
不必考虑评论和样式。但重要的是可以遵循准确的执行流程
示例输入 1:
/*******************************************************************************************
description
@param wioho
*******************************************************************************************/
CREATE PROC usp_Example1
(
@param VARCHAR(MAX),
@param2 INT
)
AS
BEGIN
BEGIN TRY
-- random comment
INSERT INTO dept VALUES (@param, @param2)
IF EXISTS (
SELECT 1
FROM dept
WHERE deptno = 10
)
THROW 50001, 'Dept 10 exists', 1
ELSE
INSERT INTO dept VALUES (@param, @param2)
END TRY
BEGIN CATCH
THROW
END CATCH
END
预期输出 1(或功能等效):
/*******************************************************************************************
description
@param wioho
*******************************************************************************************/
CREATE PROC usp_Example1
(
@param VARCHAR(MAX),
@param2 INT
)
AS
BEGIN
BEGIN TRY
INSERT INTO coverageTrace VALUES ('usp_Example1', 'BEGIN TRY', 1)
-- random comment
INSERT INTO dept VALUES (@param, @param2)
INSERT INTO coverageTrace VALUES ('usp_Example1', 'INSERT INTO dept VALUES (@param, @param2)', 1)
IF EXISTS (
SELECT 1
FROM dept
WHERE deptno = 10
)
BEGIN
INSERT INTO coverageTrace VALUES ('usp_Example1', 'IF EXISTS (SELECT 1 FROM dept WHERE deptno = 10)', 1)
THROW 50001, 'Dept 10 exists', 1
END
ELSE IF 1 = 1
BEGIN
INSERT INTO dept VALUES (@param, @param2)
INSERT INTO coverageTrace VALUES ('usp_Example1', 'INSERT INTO dept VALUES (@param, @param2)', 2)
END
END TRY
BEGIN CATCH
INSERT INTO coverageTrace VALUES ('usp_Example1', 'BEGIN CATCH', 1)
THROW
END CATCH
END
现在,如果有人没有正确设计他们的代码,这应该仍然有效。
输入示例 2:
/*******************************************************************************************
description @param wioho
*******************************************************************************************/
CREATE PROC usp_Example1(@param VARCHAR(MAX),@param2 INT) AS BEGIN
BEGIN TRY-- random comment
INSERT INTO dept VALUES (@param, @param2) IF EXISTS (
SELECT 1
FROM dept
WHERE deptno = 10
)
THROW 50001, 'Dept 10 exists', 1 ELSE
INSERT INTO dept VALUES (@param, @param2) END TRY BEGIN CATCH
THROW
END CATCH
END
这应该给出预期输出 1 的(功能上的)等效代码
请注意,此代码在块语句的情况下需要能够知道是否明确使用了 BEGIN 和 END。因此如果需要,代码可以显式添加它。
是否有任何可以重复使用的可用代码或者我可以使用的正则表达式。如果可能的话,我想在 SQL 内执行此操作,这样我的突变测试框架就可以成为任何 MS SQL 服务器上的一个文件。
请注意:这是一个测试框架,手动更改代码不是一个选项,这个有 自动完成。
进度更新:
在@Jeroen Mostert 发表评论后,我开始尝试扩展事件系统。我还有几个问题要解决,如何正确过滤生成的 XML 以及如何只在数据库中跟踪而不在数据库名称中进行硬编码?(已修复通过代码生成(没有发布我需要在生成中使用宽字符集))
当前代码:
USE master
GO
DROP DATABASE IF EXISTS testMSSQLDB
GO
CREATE DATABASE testMSSQLDB
GO
USE testMSSQLDB
GO
CREATE TYPE ID FROM INT
GO
CREATE TABLE dept (
deptno ID PRIMARY KEY
)
GO
IF EXISTS(SELECT * FROM sys.server_event_sessions WHERE name='testMSSQLTrace')
DROP EVENT SESSION testMSSQLTrace ON SERVER;
DECLARE @cmd VARCHAR(MAX) = '';
SELECT @cmd = 'CREATE EVENT SESSION testMSSQLTrace
ON SERVER
ADD EVENT sqlserver.module_end
(SET collect_statement = (1)
WHERE (sqlserver.database_name = N''' + DB_NAME() + ''')),
--ADD EVENT sqlserver.rpc_completed
--(WHERE (sqlserver.database_name = N''' + DB_NAME() + ''')),
ADD EVENT sqlserver.sp_statement_completed
(WHERE (sqlserver.database_name = N''' + DB_NAME() + ''')),
--ADD EVENT sqlserver.sql_batch_completed
--(WHERE (sqlserver.database_name = N''' + DB_NAME() + ''')),
ADD EVENT sqlserver.sql_statement_completed
(WHERE (sqlserver.database_name = N''' + DB_NAME() + '''))
ADD TARGET package0.ring_buffer
WITH (
MAX_MEMORY = 2048 KB,
-- EVENT_RETENTION_MODE = NO_EVENT_LOSS,
MAX_DISPATCH_LATENCY = 3 SECONDS,
MAX_EVENT_SIZE = 0 KB,
MEMORY_PARTITION_MODE = NONE,
TRACK_CAUSALITY = OFF,
STARTUP_STATE = OFF
);'
EXEC (@cmd)
ALTER EVENT SESSION testMSSQLTrace
ON SERVER
STATE = STOP;
ALTER EVENT SESSION testMSSQLTrace
ON SERVER
STATE = START;
GO
CREATE OR ALTER PROC usp_temp
(
@param INT = 10
)
AS
BEGIN
IF @param = 10
BEGIN
DELETE dept
INSERT INTO dept VALUES (@param)
SELECT * FROM dept
END
ELSE
DELETE dept
END
GO
EXEC usp_temp
EXEC usp_temp 20
SELECT name, target_name, CAST(xet.target_data AS xml)
FROM sys.dm_xe_session_targets AS xet
JOIN sys.dm_xe_sessions AS xe
ON (xe.address = xet.event_session_address)
WHERE xe.name = 'testMSSQLTrace'
这生成(切掉一些部分):
<RingBufferTarget truncated="0" processingTime="0" totalEventsProcessed="12" eventCount="12" droppedCount="0" memoryUsed="2012">
<event name="sp_statement_completed" package="sqlserver" timestamp="2019-07-04T09:22:30.472Z">
<data name="source_database_id">
<type name="uint32" package="package0" />
<value>22</value>
</data>
<data name="object_id">
<type name="int32" package="package0" />
<value>1916742081</value>
</data>
<data name="object_type">
<type name="object_type" package="sqlserver" />
<value>8272</value>
<text>PROC</text>
</data>
<data name="duration">
<type name="int64" package="package0" />
<value>22</value>
</data>
<data name="cpu_time">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="physical_reads">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="logical_reads">
<type name="uint64" package="package0" />
<value>3</value>
</data>
<data name="writes">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="row_count">
<type name="uint64" package="package0" />
<value>1</value>
</data>
<data name="last_row_count">
<type name="uint64" package="package0" />
<value>1</value>
</data>
<data name="nest_level">
<type name="uint16" package="package0" />
<value>1</value>
</data>
<data name="line_number">
<type name="int32" package="package0" />
<value>11</value>
</data>
<data name="offset">
<type name="int32" package="package0" />
<value>214</value>
</data>
<data name="offset_end">
<type name="int32" package="package0" />
<value>276</value>
</data>
<data name="object_name">
<type name="unicode_string" package="package0" />
<value />
</data>
<data name="statement">
<type name="unicode_string" package="package0" />
<value>INSERT INTO dept VALUES (@param)</value>
</data>
</event>
<event name="sp_statement_completed" package="sqlserver" timestamp="2019-07-04T09:22:30.476Z">
<data name="source_database_id">
<type name="uint32" package="package0" />
<value>22</value>
</data>
<data name="object_id">
<type name="int32" package="package0" />
<value>1916742081</value>
</data>
<data name="object_type">
<type name="object_type" package="sqlserver" />
<value>8272</value>
<text>PROC</text>
</data>
<data name="duration">
<type name="int64" package="package0" />
<value>32</value>
</data>
<data name="cpu_time">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="physical_reads">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="logical_reads">
<type name="uint64" package="package0" />
<value>2</value>
</data>
<data name="writes">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="row_count">
<type name="uint64" package="package0" />
<value>1</value>
</data>
<data name="last_row_count">
<type name="uint64" package="package0" />
<value>1</value>
</data>
<data name="nest_level">
<type name="uint16" package="package0" />
<value>1</value>
</data>
<data name="line_number">
<type name="int32" package="package0" />
<value>12</value>
</data>
<data name="offset">
<type name="int32" package="package0" />
<value>286</value>
</data>
<data name="offset_end">
<type name="int32" package="package0" />
<value>320</value>
</data>
<data name="object_name">
<type name="unicode_string" package="package0" />
<value />
</data>
<data name="statement">
<type name="unicode_string" package="package0" />
<value>SELECT * FROM dept</value>
</data>
</event>
</RingBufferTarget>
我如何过滤此 XML 以便仅保留执行语句、对象类型和执行位置的对象 ID?具体需要的信息是,我需要知道一个存储过程在哪几行执行,一个存储过程可以调用其他存储过程,在这种情况下我还需要知道这个过程执行了哪些语句,它嵌套在第一个存储过程中程序。如果同一语句多次出现,我现在需要它的(相对)行号
或者在谓词中:
顶层存储过程 Y 中的过程 X 执行行 Z,行号为 J
顶层存储过程Y中的过程X执行行W行号我
编辑:我做了更多研究并得出结论,我需要所有具有 <data name="nest_level"><value>2</value></data>
字段的事件。其中 2 是大于 1 的任何值。
这个https://www.scarydba.com/2018/09/24/extended-events-and-stored-procedure-parameter-values/link证明对我获取所有数据很有帮助。
所以扩展事件是解决方案,我是这样做的:
IF EXISTS(SELECT * FROM sys.server_event_sessions WHERE name='testMSSQLTrace')
DROP EVENT SESSION testMSSQLTrace ON SERVER;
DECLARE @cmd VARCHAR(MAX) = '';
SELECT @cmd = 'CREATE EVENT SESSION testMSSQLTrace
ON SERVER
ADD EVENT sqlserver.sp_statement_completed
(WHERE (sqlserver.database_name = N''' + DB_NAME() + '''))
ADD TARGET package0.ring_buffer
WITH (
MAX_MEMORY = 2048 KB,
EVENT_RETENTION_MODE = NO_EVENT_LOSS,
MAX_DISPATCH_LATENCY = 3 SECONDS,
MAX_EVENT_SIZE = 0 KB,
MEMORY_PARTITION_MODE = NONE,
TRACK_CAUSALITY = OFF,
STARTUP_STATE = OFF
);'
EXEC (@cmd)
这会创建一个可以在每个语句完成后触发的事件,这是动态完成的以在数据库上进行过滤
然后我有 3 个程序可以轻松控制此事件
/*******************************************************************************************
Starts the statement trace
*******************************************************************************************/
CREATE OR ALTER PROC testMSSQL.Private_StartTrace
AS
BEGIN
ALTER EVENT SESSION testMSSQLTrace
ON SERVER
STATE = START;
END
GO
/*******************************************************************************************
Ends the statement trace, this also clears the trace
*******************************************************************************************/
CREATE OR ALTER PROC testMSSQL.Private_StopTrace
AS
BEGIN
ALTER EVENT SESSION testMSSQLTrace
ON SERVER
STATE = STOP;
END
GO
/*******************************************************************************************
Saves the statements trace
*******************************************************************************************/
CREATE OR ALTER PROC testMSSQL.Private_SaveTrace
AS
BEGIN
DECLARE @xml XML;
SELECT @xml = CAST(xet.target_data AS xml)
FROM sys.dm_xe_session_targets AS xet INNER JOIN sys.dm_xe_sessions AS xe ON (xe.address = xet.event_session_address)
WHERE xe.name = 'testMSSQLTrace'
INSERT INTO testMSSQL.StatementInvocations (testProcedure, procedureName, lineNumber, statement)
SELECT testMSSQL.GetCurrentTest(),
OBJECT_NAME(T.c.value('(data[@name="object_id"]/value)[1]', 'int')),
T.c.value('(data[@name="line_number"]/value)[1]', 'int'),
T.c.value('(data[@name="statement"]/value)[1]', 'VARCHAR(900)')
FROM @xml.nodes('RingBufferTarget/event') T(c)
WHERE T.c.value('(data[@name="nest_level"]/value)[1]', 'int') > 3
END
GO
这些程序分别启动和停止跟踪,最后一个程序将结果存储在 table 中,它在嵌套级别进行过滤,因此不会跟踪我自己的代码。
最后我有点像这样使用它:
start trace
start tran/savepoint
run SetUp (users code)
run test (users code)
save trace
save trace to variable
rollback tran (also catch errors and stuff like that)
save variable back to table so the trace is not rolled back
作为
有什么有效的方法可以将存储过程的代码拆分成不同的语句,以便在每个语句之后可以添加一个带有前一行的额外插入语句?如果完全相同的行在 procedure/function/trigger 中出现了不止一次,它们也需要用一些数字来唯一化。
不必考虑评论和样式。但重要的是可以遵循准确的执行流程
示例输入 1:
/*******************************************************************************************
description
@param wioho
*******************************************************************************************/
CREATE PROC usp_Example1
(
@param VARCHAR(MAX),
@param2 INT
)
AS
BEGIN
BEGIN TRY
-- random comment
INSERT INTO dept VALUES (@param, @param2)
IF EXISTS (
SELECT 1
FROM dept
WHERE deptno = 10
)
THROW 50001, 'Dept 10 exists', 1
ELSE
INSERT INTO dept VALUES (@param, @param2)
END TRY
BEGIN CATCH
THROW
END CATCH
END
预期输出 1(或功能等效):
/*******************************************************************************************
description
@param wioho
*******************************************************************************************/
CREATE PROC usp_Example1
(
@param VARCHAR(MAX),
@param2 INT
)
AS
BEGIN
BEGIN TRY
INSERT INTO coverageTrace VALUES ('usp_Example1', 'BEGIN TRY', 1)
-- random comment
INSERT INTO dept VALUES (@param, @param2)
INSERT INTO coverageTrace VALUES ('usp_Example1', 'INSERT INTO dept VALUES (@param, @param2)', 1)
IF EXISTS (
SELECT 1
FROM dept
WHERE deptno = 10
)
BEGIN
INSERT INTO coverageTrace VALUES ('usp_Example1', 'IF EXISTS (SELECT 1 FROM dept WHERE deptno = 10)', 1)
THROW 50001, 'Dept 10 exists', 1
END
ELSE IF 1 = 1
BEGIN
INSERT INTO dept VALUES (@param, @param2)
INSERT INTO coverageTrace VALUES ('usp_Example1', 'INSERT INTO dept VALUES (@param, @param2)', 2)
END
END TRY
BEGIN CATCH
INSERT INTO coverageTrace VALUES ('usp_Example1', 'BEGIN CATCH', 1)
THROW
END CATCH
END
现在,如果有人没有正确设计他们的代码,这应该仍然有效。 输入示例 2:
/*******************************************************************************************
description @param wioho
*******************************************************************************************/
CREATE PROC usp_Example1(@param VARCHAR(MAX),@param2 INT) AS BEGIN
BEGIN TRY-- random comment
INSERT INTO dept VALUES (@param, @param2) IF EXISTS (
SELECT 1
FROM dept
WHERE deptno = 10
)
THROW 50001, 'Dept 10 exists', 1 ELSE
INSERT INTO dept VALUES (@param, @param2) END TRY BEGIN CATCH
THROW
END CATCH
END
这应该给出预期输出 1 的(功能上的)等效代码
请注意,此代码在块语句的情况下需要能够知道是否明确使用了 BEGIN 和 END。因此如果需要,代码可以显式添加它。
是否有任何可以重复使用的可用代码或者我可以使用的正则表达式。如果可能的话,我想在 SQL 内执行此操作,这样我的突变测试框架就可以成为任何 MS SQL 服务器上的一个文件。
请注意:这是一个测试框架,手动更改代码不是一个选项,这个有 自动完成。
进度更新:
在@Jeroen Mostert 发表评论后,我开始尝试扩展事件系统。我还有几个问题要解决,如何正确过滤生成的 XML 以及如何只在数据库中跟踪而不在数据库名称中进行硬编码?(已修复通过代码生成(没有发布我需要在生成中使用宽字符集))
当前代码:
USE master
GO
DROP DATABASE IF EXISTS testMSSQLDB
GO
CREATE DATABASE testMSSQLDB
GO
USE testMSSQLDB
GO
CREATE TYPE ID FROM INT
GO
CREATE TABLE dept (
deptno ID PRIMARY KEY
)
GO
IF EXISTS(SELECT * FROM sys.server_event_sessions WHERE name='testMSSQLTrace')
DROP EVENT SESSION testMSSQLTrace ON SERVER;
DECLARE @cmd VARCHAR(MAX) = '';
SELECT @cmd = 'CREATE EVENT SESSION testMSSQLTrace
ON SERVER
ADD EVENT sqlserver.module_end
(SET collect_statement = (1)
WHERE (sqlserver.database_name = N''' + DB_NAME() + ''')),
--ADD EVENT sqlserver.rpc_completed
--(WHERE (sqlserver.database_name = N''' + DB_NAME() + ''')),
ADD EVENT sqlserver.sp_statement_completed
(WHERE (sqlserver.database_name = N''' + DB_NAME() + ''')),
--ADD EVENT sqlserver.sql_batch_completed
--(WHERE (sqlserver.database_name = N''' + DB_NAME() + ''')),
ADD EVENT sqlserver.sql_statement_completed
(WHERE (sqlserver.database_name = N''' + DB_NAME() + '''))
ADD TARGET package0.ring_buffer
WITH (
MAX_MEMORY = 2048 KB,
-- EVENT_RETENTION_MODE = NO_EVENT_LOSS,
MAX_DISPATCH_LATENCY = 3 SECONDS,
MAX_EVENT_SIZE = 0 KB,
MEMORY_PARTITION_MODE = NONE,
TRACK_CAUSALITY = OFF,
STARTUP_STATE = OFF
);'
EXEC (@cmd)
ALTER EVENT SESSION testMSSQLTrace
ON SERVER
STATE = STOP;
ALTER EVENT SESSION testMSSQLTrace
ON SERVER
STATE = START;
GO
CREATE OR ALTER PROC usp_temp
(
@param INT = 10
)
AS
BEGIN
IF @param = 10
BEGIN
DELETE dept
INSERT INTO dept VALUES (@param)
SELECT * FROM dept
END
ELSE
DELETE dept
END
GO
EXEC usp_temp
EXEC usp_temp 20
SELECT name, target_name, CAST(xet.target_data AS xml)
FROM sys.dm_xe_session_targets AS xet
JOIN sys.dm_xe_sessions AS xe
ON (xe.address = xet.event_session_address)
WHERE xe.name = 'testMSSQLTrace'
这生成(切掉一些部分):
<RingBufferTarget truncated="0" processingTime="0" totalEventsProcessed="12" eventCount="12" droppedCount="0" memoryUsed="2012">
<event name="sp_statement_completed" package="sqlserver" timestamp="2019-07-04T09:22:30.472Z">
<data name="source_database_id">
<type name="uint32" package="package0" />
<value>22</value>
</data>
<data name="object_id">
<type name="int32" package="package0" />
<value>1916742081</value>
</data>
<data name="object_type">
<type name="object_type" package="sqlserver" />
<value>8272</value>
<text>PROC</text>
</data>
<data name="duration">
<type name="int64" package="package0" />
<value>22</value>
</data>
<data name="cpu_time">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="physical_reads">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="logical_reads">
<type name="uint64" package="package0" />
<value>3</value>
</data>
<data name="writes">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="row_count">
<type name="uint64" package="package0" />
<value>1</value>
</data>
<data name="last_row_count">
<type name="uint64" package="package0" />
<value>1</value>
</data>
<data name="nest_level">
<type name="uint16" package="package0" />
<value>1</value>
</data>
<data name="line_number">
<type name="int32" package="package0" />
<value>11</value>
</data>
<data name="offset">
<type name="int32" package="package0" />
<value>214</value>
</data>
<data name="offset_end">
<type name="int32" package="package0" />
<value>276</value>
</data>
<data name="object_name">
<type name="unicode_string" package="package0" />
<value />
</data>
<data name="statement">
<type name="unicode_string" package="package0" />
<value>INSERT INTO dept VALUES (@param)</value>
</data>
</event>
<event name="sp_statement_completed" package="sqlserver" timestamp="2019-07-04T09:22:30.476Z">
<data name="source_database_id">
<type name="uint32" package="package0" />
<value>22</value>
</data>
<data name="object_id">
<type name="int32" package="package0" />
<value>1916742081</value>
</data>
<data name="object_type">
<type name="object_type" package="sqlserver" />
<value>8272</value>
<text>PROC</text>
</data>
<data name="duration">
<type name="int64" package="package0" />
<value>32</value>
</data>
<data name="cpu_time">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="physical_reads">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="logical_reads">
<type name="uint64" package="package0" />
<value>2</value>
</data>
<data name="writes">
<type name="uint64" package="package0" />
<value>0</value>
</data>
<data name="row_count">
<type name="uint64" package="package0" />
<value>1</value>
</data>
<data name="last_row_count">
<type name="uint64" package="package0" />
<value>1</value>
</data>
<data name="nest_level">
<type name="uint16" package="package0" />
<value>1</value>
</data>
<data name="line_number">
<type name="int32" package="package0" />
<value>12</value>
</data>
<data name="offset">
<type name="int32" package="package0" />
<value>286</value>
</data>
<data name="offset_end">
<type name="int32" package="package0" />
<value>320</value>
</data>
<data name="object_name">
<type name="unicode_string" package="package0" />
<value />
</data>
<data name="statement">
<type name="unicode_string" package="package0" />
<value>SELECT * FROM dept</value>
</data>
</event>
</RingBufferTarget>
我如何过滤此 XML 以便仅保留执行语句、对象类型和执行位置的对象 ID?具体需要的信息是,我需要知道一个存储过程在哪几行执行,一个存储过程可以调用其他存储过程,在这种情况下我还需要知道这个过程执行了哪些语句,它嵌套在第一个存储过程中程序。如果同一语句多次出现,我现在需要它的(相对)行号
或者在谓词中: 顶层存储过程 Y 中的过程 X 执行行 Z,行号为 J
顶层存储过程Y中的过程X执行行W行号我
编辑:我做了更多研究并得出结论,我需要所有具有 <data name="nest_level"><value>2</value></data>
字段的事件。其中 2 是大于 1 的任何值。
这个https://www.scarydba.com/2018/09/24/extended-events-and-stored-procedure-parameter-values/link证明对我获取所有数据很有帮助。
所以扩展事件是解决方案,我是这样做的:
IF EXISTS(SELECT * FROM sys.server_event_sessions WHERE name='testMSSQLTrace')
DROP EVENT SESSION testMSSQLTrace ON SERVER;
DECLARE @cmd VARCHAR(MAX) = '';
SELECT @cmd = 'CREATE EVENT SESSION testMSSQLTrace
ON SERVER
ADD EVENT sqlserver.sp_statement_completed
(WHERE (sqlserver.database_name = N''' + DB_NAME() + '''))
ADD TARGET package0.ring_buffer
WITH (
MAX_MEMORY = 2048 KB,
EVENT_RETENTION_MODE = NO_EVENT_LOSS,
MAX_DISPATCH_LATENCY = 3 SECONDS,
MAX_EVENT_SIZE = 0 KB,
MEMORY_PARTITION_MODE = NONE,
TRACK_CAUSALITY = OFF,
STARTUP_STATE = OFF
);'
EXEC (@cmd)
这会创建一个可以在每个语句完成后触发的事件,这是动态完成的以在数据库上进行过滤
然后我有 3 个程序可以轻松控制此事件
/*******************************************************************************************
Starts the statement trace
*******************************************************************************************/
CREATE OR ALTER PROC testMSSQL.Private_StartTrace
AS
BEGIN
ALTER EVENT SESSION testMSSQLTrace
ON SERVER
STATE = START;
END
GO
/*******************************************************************************************
Ends the statement trace, this also clears the trace
*******************************************************************************************/
CREATE OR ALTER PROC testMSSQL.Private_StopTrace
AS
BEGIN
ALTER EVENT SESSION testMSSQLTrace
ON SERVER
STATE = STOP;
END
GO
/*******************************************************************************************
Saves the statements trace
*******************************************************************************************/
CREATE OR ALTER PROC testMSSQL.Private_SaveTrace
AS
BEGIN
DECLARE @xml XML;
SELECT @xml = CAST(xet.target_data AS xml)
FROM sys.dm_xe_session_targets AS xet INNER JOIN sys.dm_xe_sessions AS xe ON (xe.address = xet.event_session_address)
WHERE xe.name = 'testMSSQLTrace'
INSERT INTO testMSSQL.StatementInvocations (testProcedure, procedureName, lineNumber, statement)
SELECT testMSSQL.GetCurrentTest(),
OBJECT_NAME(T.c.value('(data[@name="object_id"]/value)[1]', 'int')),
T.c.value('(data[@name="line_number"]/value)[1]', 'int'),
T.c.value('(data[@name="statement"]/value)[1]', 'VARCHAR(900)')
FROM @xml.nodes('RingBufferTarget/event') T(c)
WHERE T.c.value('(data[@name="nest_level"]/value)[1]', 'int') > 3
END
GO
这些程序分别启动和停止跟踪,最后一个程序将结果存储在 table 中,它在嵌套级别进行过滤,因此不会跟踪我自己的代码。
最后我有点像这样使用它:
start trace
start tran/savepoint
run SetUp (users code)
run test (users code)
save trace
save trace to variable
rollback tran (also catch errors and stuff like that)
save variable back to table so the trace is not rolled back