insert-exec 블록을 사용하여 호출 된 저장 프로 시저에서 예외 처리


10

insert-exec 블록에서 호출되는 저장 프로 시저가 있습니다.

insert into @t
    exec('test')

저장 프로 시저에서 생성 된 예외를 처리하고 계속 처리하려면 어떻게해야합니까?

다음 코드는 문제를 보여줍니다. 내부 exec()통화 의 성공 또는 실패에 따라 0 또는 -1을 반환하려고합니다 .

alter procedure test -- or create
as
begin try
    declare @retval int;
    -- This code assumes that PrintMax exists already so this generates an error
    exec('create procedure PrintMax as begin print ''hello world'' end;')
    set @retval = 0;
    select @retval;
    return(@retval);
end try
begin catch
    -- if @@TRANCOUNT > 0 commit;
    print ERROR_MESSAGE();
    set @retval = -1;
    select @retval;
    return(@retval);
end catch;
go

declare @t table (i int);

insert into @t
    exec('test');

select *
from @t;

내 문제는 return(-1)입니다. 성공 경로는 괜찮습니다.

저장 프로 시저에서 try / catch 블록을 제외하면 오류가 발생하고 삽입이 실패합니다. 그러나 내가하고 싶은 일은 오류를 처리하고 좋은 값을 반환하는 것입니다.

코드는 다음과 같은 메시지를 반환합니다.

Msg 3930, Level 16, State 1, Line 6
The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.

이것은 아마도 내가 경험 한 최악의 오류 메시지 일 것입니다. "중첩 된 트랜잭션에서 오류를 처리하지 않았습니다."를 의미하는 것 같습니다.

에 넣으면 if @@TRANCOUNT > 0메시지가 나타납니다.

Msg 3916, Level 16, State 0, Procedure gordontest, Line 7
Cannot use the COMMIT statement within an INSERT-EXEC statement unless BEGIN TRANSACTION is used first.

트랜잭션 시작 / 커밋을 사용하여 시도했지만 아무것도 작동하지 않는 것 같습니다.

그렇다면 전체 트랜잭션을 중단하지 않고 저장 프로 시저에서 오류를 처리하도록하려면 어떻게해야합니까?

Martin에 대한 답변으로 수정 :

실제 호출 코드는 다음과 같습니다.

        declare @RetvalTable table (retval int);

        set @retval = -1;

        insert into @RetvalTable
            exec('

@retval int 선언; exec @retval = '+ @ query +'; @retval '선택);

        select @retval = retval from @RetvalTable;

@query저장 프로 시저 호출은 어디에 있습니까 ? 저장 프로 시저에서 반환 값을 얻는 것이 목표입니다. 이것이 insert(또는 더 구체적으로, 거래를 시작 하지 않고) 가능하다면 , 그것은 좋을 것입니다.

값이 너무 많아 테이블에 값을 저장하기 위해 일반적으로 저장 프로 시저를 수정할 수 없습니다. 그들 중 하나 가 실패하고 그것을 수정할 수 있습니다. 내 현재 최고의 솔루션은 다음과 같습니다.

if (@StoredProcedure = 'sp_rep__post') -- causing me a problem
begin
    exec @retval = sp_rep__post;
end;
else
begin
    -- the code I'm using now
end;

테이블 변수에 무엇을 삽입하려고합니까? 반환 값은 어쨌든 삽입되지 않습니다. declare @t table (i int);declare @RC int;exec @RC = test;insert into @t values (@RC);select * from @t;잘 작동합니다.
Martin Smith

@MartinSmith. . . 코드가 실제로 작동하는 방식은 select @retval; return @retval결국 더 비슷 합니다. 동적 저장 프로 시저 호출에서 반환 값을 얻는 다른 방법을 알고 있다면 알고 싶습니다.
Gordon Linoff 2013

또 다른 방법은 다음과 같습니다DECLARE @RC INT;EXEC sp_executesql N'EXEC @RC = test', N'@RC INT OUTPUT', @RC = @RC OUTPUT;insert into @t VALUES (@RC)
Martin Smith

@MartinSmith. . . 나는 그것이 효과가 있다고 생각합니다. 우리는 반나절 동안 하드웨어 오류 ( "로그 파일에 쓰는 작업을 지원할 수 없습니다"는 하드웨어 오류와 같은 소리)를 찾고 지난 몇 시간 동안 코드를 올바르게 작성하려고했습니다. 변수 대체는 훌륭한 답변입니다.
Gordon Linoff 2013

답변:


13

명세서 EXEC부분의 오류는 INSERT-EXEC거래를 파기 한 상태로 두는 것입니다.

당신이 만약 PRINT밖으로 XACT_STATE()에서 CATCH이 설정되어 블록 -1.

모든 오류가이 상태를 설정하지는 않습니다. 다음 점검 제한 조건 오류는 catch 블록으로 전달되고 INSERT성공합니다.

ALTER PROCEDURE test -- or create
AS
  BEGIN try
      DECLARE @retval INT;

      DECLARE @t TABLE(x INT CHECK (x = 0))

      INSERT INTO @t
      VALUES      (1)

      SET @retval = 0;

      SELECT @retval;

      RETURN( @retval );
  END try

  BEGIN catch
      PRINT XACT_STATE()

      PRINT ERROR_MESSAGE();

      SET @retval = -1;

      SELECT @retval;

      RETURN( @retval );
  END catch; 

이것을 CATCH블록에 추가

 IF (XACT_STATE()) = -1
BEGIN
    ROLLBACK TRANSACTION;
END;

도움이되지 않습니다. 그것은 오류를 준다

INSERT-EXEC 문에서 ROLLBACK 문을 사용할 수 없습니다.

그런 오류가 발생하면 복구 할 수있는 방법이 없다고 생각합니다. 특정 사용 사례의 경우 INSERT ... EXEC어쨌든 필요하지 않습니다 . 반환 값을 스칼라 변수에 할당 한 다음 별도의 명령문에 삽입 할 수 있습니다.

DECLARE @RC INT;

EXEC sp_executesql
  N'EXEC @RC = test',
  N'@RC INT OUTPUT',
  @RC = @RC OUTPUT;

INSERT INTO @t
VALUES      (@RC) 

물론 호출 된 저장 프로 시저를 재구성하여 해당 오류가 전혀 발생하지 않도록 할 수 있습니다.

DECLARE @RetVal INT = -1

IF OBJECT_ID('PrintMax', 'P') IS NULL
  BEGIN
      EXEC('create procedure PrintMax as begin print ''hello world'' end;')

      SET @RetVal = 0
  END

SELECT @RetVal;

RETURN( @RetVal ); 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.