У меня есть хранимая процедура, которая вызывается в блоке 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;
источник
declare @t table (i int);declare @RC int;exec @RC = test;insert into @t values (@RC);select * from @t;
работает отлично.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)
Ответы:
Ошибка в
EXEC
частиINSERT-EXEC
оператора оставляет вашу транзакцию в обреченном состоянии.Если вас
PRINT
изXACT_STATE()
вCATCH
блоке он установлен на-1
.Не все ошибки приведут к этому состоянию. Следующая ошибка проверки проверки проходит через блок catch и
INSERT
успешно завершается.Добавление этого в
CATCH
блокНе помогает Выдает ошибку
Я не думаю, что есть какой-то способ восстановления после такой ошибки, как только она произошла. Для вашего конкретного случая использования вам все
INSERT ... EXEC
равно не нужно . Вы можете присвоить возвращаемое значение скалярной переменной, а затем вставить ее в отдельный оператор.Или, конечно, вы можете реструктурировать вызываемую хранимую процедуру, чтобы она вообще не вызывала этой ошибки.
источник