У мене збережена процедура, яка викликається у блоці 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 = '+ @ запит +'; виберіть @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;
працює чудово.