April 19, 2012 at 6:42 am
Hi,
I have a stored procedure on serverA called SP1. In a try catch block in SP1, it executes a stored procedure called SP2 on serverB. SP2 runs some stuff in a Try Catch block. On failure, I want the catch block in SP1 on ServerA to handle the error from SP2 on ServerB and contine the stored procedure.
Below is an extract of the stored procedures I'm running.
SP1
DECLARE @Link1 VARCHAR(128),
@Link2 VARCHAR(128),
@sql VARCHAR(1024),
@errmsg NVARCHAR(2048),
@errsev TINYINT,
@errstate TINYINT,
@errno INT,
@errproc SYSNAME,
@errline INT
SET @Link1 = 'ServerA'
SET @Link2 = 'ServerB'
BEGIN TRY
IF EXISTS(SELECT name FROM SYS.SERVERS WHERE IS_LINKED = 1 AND name = @Link2)
BEGIN
SET @sql = 'EXEC(''dbo.CheckKb ' + '''''' + @Link1 + ''''''') AT ' + QUOTENAME(@Link2)
EXEC (@SQL)
END
ELSE
IF EXISTS(SELECT name FROM SYS.SERVERS WHERE IS_LINKED = 1 AND name = @Link1)
BEGIN
SET @sql = 'EXEC(''dbo.CheckKb ' + '''''' + @Link2 + ''''''') AT ' + QUOTENAME(@Link1)
EXEC (@SQL)
END
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION --any open transactions are rolled back in the event of a failure
--SET @errBit = 1
SELECT --get all the error information from the backups.
@errmsg = ERROR_MESSAGE(),
@errno = ERROR_NUMBER(),
@errsev = ERROR_SEVERITY(),
@errstate = ERROR_STATE(),
@errproc = ERROR_PROCEDURE(),
@errline = ERROR_LINE()
RAISERROR('The stored procedure error is: %s', 0, 1, @errmsg) WITH NOWAIT, LOG
END CATCH
CREATE PROCEDURE [dbo].[CheckKb]
@LinkedServerName sysname
with recompile
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare @srvr sysname
declare @retval int
declare @sql nvarchar(2000)
set @srvr = @LinkedServerName;
BEGIN TRY
EXEC @retval = sys.sp_testlinkedserver @srvr;
END TRY
BEGIN CATCH
WAITFOR DELAY '000:00:15'
BEGIN TRY
EXEC @retval = sys.sp_testlinkedserver @srvr;
END TRY
BEGIN CATCH
SET @retval = sign(@@error);
IF @retval <> 0
BEGIN
RAISERROR('There have been 2 failed attempts trying to check kb', 25, 1) WITH NOWAIT, LOG
RETURN
END
END CATCH
BEGIN
SET @retval = + 10;
RAISERROR('There was 1 failed attempt trying to check kb', 8, 1) with nowait
EXEC (@SQL)
END
END CATCH
IF @retval = 0
BEGIN
RAISERROR ('Successfully tested kb', 0, 1) with nowait
EXEC (@SQL)
END
END
I thought that if I set the error code above 20 using RAISERROR in SP2 and set XACT_ABORT ON in SP1, my catch block in SP1 would pick up the error thrown by SP2 and handle it accordingly. Howerver, if I run it 10 times on the trot, I get one of two different errors. I can't figure out why I'm not getting consistent error handling:
https://www.sqlservercentral.com/Forums/Uploads/image-unavailable.png
https://www.sqlservercentral.com/Forums/Uploads/image-unavailable.png
I want the error to come back consistenly like error2 in the link
I'm running SQL Server 2005 SP3 Enterprise Edition on Windows 2003 R2
Many thanks,
Andrew
April 20, 2012 at 1:00 am
anyone?
April 20, 2012 at 7:19 am
This will work, you just have to change the severity levels. When I tried 25, I got an error about the error only being specified by sysadmin roles. When I used 8 or 0, it never went into the Catch block because these are warnings and not errors. When I used 16, then it went into the catch block the way I expected it to. I setup a dummy proc on the linked server and then called it from the first database. Play around with the severity levels and you'll see what I mean. Here's what I ran:
Linked server:
Create PROCEDURE spv_test
AS
BEGIN
declare @e nvarchar(200) = 'Test Error Message'
RaisError(@e, 16, 1)
END
and then ran this:
declare @e nvarchar(200)
begin try
exec ('DatabaseName.dbo.spv_Test') at LinkedServer
set @e = 'No Error'
end try
begin catch
select @e = ERROR_MESSAGE()
end catch
Select @e
For better, quicker answers, click on the following...
http://www.sqlservercentral.com/articles/Best+Practices/61537/
For better answers on performance questions, click on the following...
http://www.sqlservercentral.com/articles/SQLServerCentral/66909/
April 20, 2012 at 8:20 am
Hi,
Thanks for the response.
I found your solution works, howerver, it's not quite how I'm trying to use it. In my procedure, if the stored procedure I run remotely fails, I need to try again. So, instead of your first block of code, it would be something more like:
create proc spv_test
as
begin
declare @e nvarchar(200)
declare @f nvarchar(200)
set @e = 'Test Error Message'
set @f = 'Another Test Error Message'
BEGIN TRY
SELECT 1/0
END TRY
BEGIN CATCH
BEGIN TRY
SELECT 1/0
END TRY
BEGIN CATCH
RAISERROR(@f, 16, 1)
END CATCH
RAISERROR(@e, 16, 1)
END CATCH
END
Doing it this way, I still get an error that's not caught by the local stored proc.
I had some feedback from a post on MSDN forums that suggested that TRY/CATCH and linked servers is buggy - with link to connect article (https://connect.microsoft.com/SQLServer/feedback/details/331635/try-catch-not-work-when-process-include-linked-server)
I've temporarily re-written it so that in SP2, on error, it drops an error flag in a local table, which is then queried by SP1 after SP2 completes. What the error flag says determines how SP1 then behaves.
Interested to see though if you can get above to work - bearing in mind I'm using SQL 2005 SP3.
Many thanks,
Andrew
April 20, 2012 at 8:48 am
I did get yours to work. I put a return after the first RaisError
alter proc spv_test
as
begin
declare @e nvarchar(200)
declare @f nvarchar(200)
set @e = 'Test Error Message'
set @f = 'Another Test Error Message'
BEGIN TRY
SELECT 1/0
END TRY
BEGIN CATCH
BEGIN TRY
SELECT 1/0
END TRY
BEGIN CATCH
RAISERROR(@f, 16, 1)
return
END CATCH
RAISERROR(@e, 16, 1)
END CATCH
END
For better, quicker answers, click on the following...
http://www.sqlservercentral.com/articles/Best+Practices/61537/
For better answers on performance questions, click on the following...
http://www.sqlservercentral.com/articles/SQLServerCentral/66909/
Viewing 5 posts - 1 through 4 (of 4 total)
You must be logged in to reply to this topic. Login to reply