2010-05-14 1 views
2

호출 응용 프로그램이 저장 프로 시저를 통해 액세스 할 수있는 SQL Server 2008 데이터베이스를 상속 받았습니다.DML 명령이 저장 프로 시저에서 발행되었는지 여부를 확실하게 식별 할 수 있습니까?

데이터베이스의 각 테이블에는 삽입/업데이트/삭제 작업이 기록되는 섀도우 감사 테이블이 있습니다.

감사 테이블 채우기에 대한 성능 테스트에서는 OUTPUT 절을 사용하여 감사 레코드를 삽입하는 것이 트리거를 사용하는 것보다 20 % 정도 빠르므로 저장 프로 시저에서 구현되었습니다.

그러나이 디자인은 테이블에 대해 직접 실행되는 DML 문을 통해 테이블에 직접 적용된 변경 내용을 추적 할 수 없기 때문에 @@NESTLEVEL 값을 사용하여 트리거를 실행할 것인지 여부를 결정하는 트리거도 구현되었습니다 저장 프로 시저를 통해 실행되는 모든 DML은 @@NESTLEVEL> 1)이됩니다.

IF @@NESTLEVEL = 1 -- implies call is direct sql so generate history from here 
    BEGIN 
... insert into audit table 

가 DML 문을 동적 SQL에서 실행되는 업데이트 또는 @@NESTLEVEL 1 위에 제기되는 다른 상황을 추적하지 않기 때문에이 디자인은 결함이 : 트리거 코드의 몸 즉 이 같이 보입니다.

누구나 저장 프로 시저에 의해 트리거되지 않는 경우에만 트리거에서 실행할 수있는 완전히 신뢰할 수있는 방법을 제안 할 수 있습니까?

아니면 (내 생각에) 이것이 가능하지 않습니까?

답변

4

CONTEXT_INFO (Transact-SQL)을 사용하십시오. CONTEXT_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 

그냥 불량 삽입을 수행의 절차에 아무것도 기록하지에 트리거를 경고 값을 설정/update/delete 그들은 CONTEXT_INFO를 설정하지 않을 것이고 트리거는 변경을 기록 할 것입니다. 위조 된 코드가 CONTEXT_INFO를 사용하려고 시도 할 때 테이블 이름이나 @@ SPID 등과 같이 CONTEXT_INFO에 넣은 값을 생각하면 멋질 것입니다.

+0

방어 적으로 프로그램하는 것이 현명하고, CONTEXT_INFO에 이미 설정되어있는 것에 토큰을 "추가"할 수 있습니까? 마찬가지로 연결 기반이기 때문에 절차가 끝나면 토큰을 지워서는 안됩니까? 그리고 proc가 proc를 호출하면, 이미 존재하지 않는 경우에만 추가/제거해야합니다. 까다로워 질 수는 있지만 그래도 여전히 할 수있는 것처럼 느껴집니다. –

+1

@Philip Kelley, 위의 간단한 예제에서'SET CONTEXT_INFO 0x0'을 사용하여 값을 저장 한 다음 다시 설정할 수 있습니다. 가능성은 거의 끝이 없습니다. 이것은 기계의 단순한 예일 뿐이지 완전하게 포괄적 인 것이 아닙니다. –

+0

감사합니다. 이것은 훌륭한 해결책입니다. –

관련 문제