У меня есть хранимая процедура, которая вызывается в блоке insert-exec:
insert into @t
exec('test')
Как я могу обработать исключения, сгенерированные в хранимой процедуре, и при этом продолжить обработку?
Следующий код иллюстрирует проблему. То, что я хочу сделать, это вернуть 0 или -1 в зависимости от успеха или неудачи внутреннего exec()
вызова:
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.
Я попытался поиграться с инструкциями начала / совершения транзакции, но, похоже, ничего не работает.
Итак, как мне сделать, чтобы моя хранимая процедура обрабатывала ошибки, не прерывая общую транзакцию?
Отредактируйте в ответ Мартину:
Фактический код вызова:
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;
select @retval; return @retval
на конец. Если вы знаете другой способ получить возвращаемое значение из динамического вызова хранимой процедуры, я хотел бы знать.
DECLARE @RC INT;EXEC sp_executesql N'EXEC @RC = test', N'@RC INT OUTPUT', @RC = @RC OUTPUT;insert into @t VALUES (@RC)
declare @t table (i int);declare @RC int;exec @RC = test;insert into @t values (@RC);select * from @t;
работает отлично.