Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 是否可以确定DML命令是否是从存储过程发出的?_Sql Server_Sql Server 2008 - Fatal编程技术网

Sql server 是否可以确定DML命令是否是从存储过程发出的?

Sql server 是否可以确定DML命令是否是从存储过程发出的?,sql-server,sql-server-2008,Sql Server,Sql Server 2008,我继承了一个SQLServer2008数据库,调用应用程序可以通过存储过程访问该数据库 数据库中的每个表都有一个卷影审核表,其中记录了的插入/更新/删除操作 填充审计表的性能测试表明,使用OUTPUT子句插入审计记录比使用触发器快20%左右,因此这已在存储过程中实现 但是,由于此设计无法通过直接针对表发出的DML语句跟踪对表所做的更改,因此还实现了触发器,它使用@@NESTLEVEL的值来确定是否运行触发器(假设所有通过存储过程运行的DML都将具有>级别>1)。 i、 e.触发代码的主体类似于:

我继承了一个SQLServer2008数据库,调用应用程序可以通过存储过程访问该数据库

数据库中的每个表都有一个卷影审核表,其中记录了的插入/更新/删除操作

填充审计表的性能测试表明,使用
OUTPUT
子句插入审计记录比使用触发器快20%左右,因此这已在存储过程中实现

但是,由于此设计无法通过直接针对表发出的DML语句跟踪对表所做的更改,因此还实现了触发器,它使用
@@NESTLEVEL
的值来确定是否运行触发器(假设所有通过存储过程运行的DML都将具有
>级别
>1)。
i、 e.触发代码的主体类似于:

IF  @@NESTLEVEL =   1   -- implies call is direct sql so generate history from here
    BEGIN
... insert into audit table
此设计有缺陷,因为它不会跟踪在动态SQL中执行DML语句的更新,或任何其他将
@@NESTLEVEL
提升到1以上的上下文

有谁能推荐一种完全可靠的方法,我们可以在触发器中使用它来执行它们(如果不是由存储过程触发的话)


或者这(正如我所怀疑的)是不可能的?

我不这么认为。有一种方法可以访问调用堆栈使用。在过程中设置一个值来警告触发器不要记录任何内容:

--in the procedure doing the insert/update/delete

DECLARE @CONTEXT_INFO  varbinary(128)
SET @CONTEXT_INFO =cast('SkipTrigger=Y'+REPLICATE(' ',128) as varbinary(128))
SET CONTEXT_INFO @CONTEXT_INFO

--do insert/update/delete that will fire the trigger

SET CONTEXT_INFO 0x0 
--here is the portion of the trigger to retrieve the value:

IF CAST(CONTEXT_INFO() AS VARCHAR(128))='SkipTrigger=Y'
BEGIN
    --log your data here
END
在触发器检查上下文_INFO中,确定是否需要执行任何操作:

--in the procedure doing the insert/update/delete

DECLARE @CONTEXT_INFO  varbinary(128)
SET @CONTEXT_INFO =cast('SkipTrigger=Y'+REPLICATE(' ',128) as varbinary(128))
SET CONTEXT_INFO @CONTEXT_INFO

--do insert/update/delete that will fire the trigger

SET CONTEXT_INFO 0x0 
--here is the portion of the trigger to retrieve the value:

IF CAST(CONTEXT_INFO() AS VARCHAR(128))='SkipTrigger=Y'
BEGIN
    --log your data here
END

对于刚刚执行恶意插入/更新/删除操作的任何人,他们都不会设置上下文信息,触发器会记录更改。您可能会喜欢输入上下文信息的值,如表名或@SPID等。如果您认为恶意代码也会尝试使用上下文信息。

进行防御性编程是否明智d“添加”您对上下文信息中可能已经设置的任何内容的标记?同样,由于它是基于连接的,他们不应该在过程结束时清除其标记吗?如果一个进程调用一个进程,您应该只添加/清除它,如果它不在那里呢?这可能会很棘手,但听起来非常可行。@Philip Kelley,在上面的简单示例中,我通过执行
SET CONTEXT_INFO 0x0
来清除它。您可以在更改它之前存储它的值,然后将其设置回原位。您也可以打开/pop值,等等。这种可能性几乎是无穷无尽的,这只是一个简单的力学示例,不是一个完全全面的示例。谢谢-这是一个伟大的解决方案。