Linked Server COMMIT TRANSACTION fail on TRY CATCH - sql-server

i'm working with Linked Server, and this code working fine
BEGIN TRY
INSERT INTO [Dev].[dbo].tb_test (no) SELECT no from [MYLINKEDSERVER].[mydb].[dbo].tb_test
DELETE FROM [MYLINKEDSERVER].[mydb].[dbo].tb_test
END TRY
BEGIN CATCH
SELECT 'fail'
END CATCH
but when i use it with COMMIT TRANSACTION, like this
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO [Dev].[dbo].tb_test (no) SELECT no from [MYLINKEDSERVER].[mydb].[dbo].tb_test
DELETE FROM [MYLINKEDSERVER].[mydb].[dbo].tb_test
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
END CATCH
show error
OLE DB provider "SQLNCLI11" for linked server "MYLINKEDSERVER" returned message
"The partner transaction manager has disabled its support for
remote/network transactions.".
What is wrong?

The solution is to write a stored procedure on remote server with return value, and execute it locally:
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO [Dev].[dbo].tb_test (no)
SELECT no
FROM [MYLINKEDSERVER].[mydb].[dbo].tb_test
DECLARE #returnvalue INT
EXEC #returnvalue = [MYLINKEDSERVER].[mydb].[dbo].sp_update #no
IF #returnvalue = 1
BEGIN
COMMIT
END
ELSE
BEGIN
ROLLBACK
END
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
END CATCH
The stored procedure:
CREATE PROCEDURE [dbo].[sp_update]
#no NVARCHAR(20)
AS
BEGIN
SET NOCOUNT ON
BEGIN TRY
BEGIN TRANSACTION
DELETE FROM mytb
WHERE no = #no
COMMIT
RETURN 1
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
RETURN 0
END CATCH
END
Hope help someone

Try executing below command on Server on which you are going to do insert operation.
EXEC sp_serveroption #server = 'ReadServerName',#optname = 'remote proc transaction promotion', #optvalue = 'false' ;
Also try executing below code. I have added BEGIN DISTRIBUTED TRANSACTION instead of BEGIN TRANSACTION.
BEGIN TRY
BEGIN DISTRIBUTED TRANSACTION
INSERT INTO [Dev].[dbo].tb_test (no) SELECT no from [MYLINKEDSERVER].[mydb].[dbo].tb_test
DELETE FROM [MYLINKEDSERVER].[mydb].[dbo].tb_test
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
END CATCH
Details are available at MS site.

Try this it should work
DECLARE #ServerName SYSNAME
, #Message nvarchar(1000)
, #CMD1 nvarchar(max)
--
DECLARE #Server_List Table
( SrvID SMALLINT
, SrvName SYSNAME )
--
Set NoCount ON
--
-- Load up linked server list
--
BEGIN
INSERT INTO #Server_List (SrvID, SrvName)
SELECT SrvID
, SrvName
FROM [master].[SYS].sysservers
ORDER BY SrvID ASC
END
--
SELECT TOP 1 #ServerName = SrvName
FROM #Server_List
ORDER BY SrvID ASC
--
-- Loop through the Linked Server List
--
WHILE EXISTS ( SELECT * FROM #Server_List )
BEGIN
SELECT #Message = 'Server Name is '+ #ServerName
--
RAISERROR (#Message, 10,1) WITH NOWAIT
--
SET #CMD1 = 'EXEC master.dbo.sp_serveroption #server=N'''
+ #ServerName
+ ''', #optname=N''rpc'', #optvalue=N''true'''
Exec sp_executesql #cmd1
--
SET #CMD1 = 'EXEC master.dbo.sp_serveroption #server=N'''
+ #ServerName
+ ''', #optname=N''rpc out'', #optvalue=N''true'''
Exec sp_executesql #cmd1
--
set #cmd1 = 'EXEC master.dbo.sp_serveroption #server = '''
+ #ServerName
+ ''', #optname=N''remote proc transaction promotion'', #optvalue=N''false'''
Exec sp_executesql #stmt=#cmd1,#params=N''
--
DELETE FROM #Server_List WHERE SrvName = #ServerName
--
SELECT TOP 1 #ServerName = SrvName
FROM #Server_List
ORDER BY SrvID ASC
--
END

Related

Will all transaction in this stored procedure be rolled back

I have created a stored procedure (shown below) in SQL Server and tried to include a Rollback Transaction as I need to have a "stored procedure that has a transaction around it, so that if/when it fails all inserts will be rolled back."
I am unsure if this work or not, or will work, I cannot test yet as only developing locally, but wondered if someone wouldn't mind looking over the Rollback Transaction part of the stored procedure and advise if on the right path?
USE AutomatedTesting
GO
ALTER PROCEDURE [dbo].[spInsertTestCases]
(#AddedTFS INT,
#Scenario NVARCHAR(500),
#TargetTableName NVARCHAR(100),
#TargetFieldName NVARCHAR(100),
#ExpectedResult NVARCHAR(100),
#TargetTableDBName NVARCHAR(100),
#TargetTableSchema NVARCHAR(100),
#TargetFieldIsDateTime NVARCHAR(1),
#TestCaseIdentifiers dbo.TestCaseIdentifiers READONLY ) -- can only be READONLY. meaning you cannot amend the param
/* #TestCaseIdentifiers var will be prepopulated
TestDataIdentifiersNEW is a custom data type which has fields (TestSequence ColumnName ColumnValue IsAlphaNumeric)
so stored procedure is called like:
EXEC [dbo].[spTest_UserDefinedDatatype] 'param1','param2' #temp_testdata
#temp_testdata will already be defined and popualted(INSERT INTO ) before exec to add in 1 to many rows.
for example:
ColumnName ColumnValue
PATIENTID 123456
SOURCESYS PAS
in simple terms above EXEC is:
EXEC [dbo].[spTest_UserDefinedDatatype] 'param1','param2' 'PATIENTID 123456'
'SOURCESYS PAS'
*/
AS
BEGIN TRY
BEGIN TRANSACTION
BEGIN
--DECLARE #TableNameUpdate SYSNAME = #TargetTableName
--DECLARE #CDI SYSNAME = REPLACE(#TargetTableName,'CDO','CDI') -- so if targettablename param is CDO then swap it to CDI. why?
DECLARE #sql VARCHAR(MAX) = ' INSERT INTO [dbo].[TestCasesIdentifier] ([TestCaseId], [TestCaseSequence], [FieldName], [FieldValue], [AlphaNumeric]) VALUES '
DECLARE #i INT = 1
DECLARE #TableNameUpdate SYSNAME = #TargetTableName
DECLARE #CDI SYSNAME = REPLACE(#TargetTableName,'CDO','CDI')
DECLARE #ColName SYSNAME
DECLARE #Ret NVARCHAR(256)
DECLARE #sql2 NVARCHAR(MAX)
DECLARE #TestCaseID INT = -1 --does this need default variable?
DECLARE #ErrorCode INT = ##error
DECLARE #TestSequence INT
DECLARE #ColumnName VARCHAR(100)
DECLARE #ColumnValue VARCHAR(100)
DECLARE #IsAlphaNumeric BIT
DECLARE #TableTestSequence INT = ISNULL((SELECT MAX([TableTestSequence]) + 1 FROM TestCases WHERE #TargetTableName = [TargetTableName]), 1)
-- INSERT into TestCases. 1 record
-- An assumption that a number of fields will have defaults on them - if not, extra fields will need adding
INSERT INTO [dbo].[TestCases] ([AddedTFS], [TableTestSequence], [Scenario],
[TargetTableName], [TargetFieldName], [ExpectedResult],
[TargetTableDBName], [TargetTableSchema], [TargetFieldIsDateTime])
VALUES (#AddedTFS, -- AddedTFS (The TFS Number of the Development carried out)
ISNULL((SELECT MAX([TableTestSequence]) + 1 -- TableTestSequence (Generates the next Sequence Number for a Table)
FROM TestCases -- if table doesnt exist in TestCases then sets to 1
WHERE #TargetTableName = [TargetTableName]), 1),
#Scenario, -- Scenario (A description of the scenario use GIVEN and WHERE)
#TargetTableName, -- TargetTableName (References the Target Table entered at the top of this SQL - SET #TableName = 'CDO_APC_ELECTIVE_ADMISSION_LIST')
#TargetFieldName, -- TargetFieldName (The Field in which we want to test)
#ExpectedResult, -- ExpectedResult (The expected output/result of the field in which we want to test)
#TargetTableDBName, -- The DB to be used
#TargetTableSchema, -- the schema to be used
#TargetFieldIsDateTime) ---- 1 = Yes, 0 = No (Is Target field a datetime field)
-- Grab the identity value just generated by the last statement and the last error code generated
-- in order to reference TestCases PK when adding to TestCaseIdentifiers
SELECT #TestCaseID = SCOPE_IDENTITY(), #ErrorCode = ##error
IF #ErrorCode = 0 --OR #TestCaseID <> -1 -- #ErrorCode <> 0 if error then back out testcases INSERT? surely should use BEGIN/ROLLBACK tran
--IF #ErrorCode = 0 OR #TestCaseID <> -1
-- If there was no error creating the TestCase record, create the records for the WHERE clause
BEGIN
/*
rollback insert if no matching records
rollback insert if SQL returns more than 1 record
return error message to user
*/
SELECT
ic.index_column_id, c.name
INTO #tmp
FROM sys.indexes i
JOIN sys.index_columns ic ON i.object_id = ic.object_id
AND i.index_id = ic.index_id
JOIN sys.columns c ON c.column_id = ic.column_id
AND c.object_id = ic.object_id
JOIN sys.tables t ON c.object_id = t.object_id
WHERE t.name = #CDI
AND i.is_primary_key = 1
IF (SELECT COUNT(*) FROM #TestCaseIdentifiers) = 0
--IF #PKValues IS NULL
BEGIN
WHILE #i <= (SELECT COUNT(*) FROM #tmp)
BEGIN
SELECT #ColName = [name]
FROM #tmp
WHERE index_column_id = #i
-- if #expectedvalue IS NULL
SET #sql2 = 'SELECT TOP 1 #RetvalOut = ' + QUOTENAME(#ColName) + ' FROM ' + QUOTENAME(#CDI) + ' ORDER BY NEWID()'
-- else
-- SET #sql2 = ''
EXECUTE sp_executesql #command = #sql2, #ParmDefinition = N'#RetvalOut NVARCHAR(MAX) OUTPUT', #retvalOut = #Ret OUTPUT
SET #sql += '(' + CONVERT(VARCHAR(100),#TestCaseID) + ',' + CONVERT(VARCHAR(10),#i) + ',''' + #ColName + ''',''' + #Ret + ''',1),'
SET #i+=1
SELECT #sql = REVERSE(SUBSTRING(REVERSE(#sql),2,8000))
PRINT #sql
EXEC #sql
END
END
ELSE
BEGIN
--PRINT 'got here'
DECLARE csr_TestCaseIdentifierInsert CURSOR FOR
SELECT [TestSequence],[ColumnName],[ColumnValue],[IsAlphaNumeric]
FROM #TestCaseIdentifiers
ORDER BY [TestSequence]
OPEN csr_TestCaseIdentifierInsert
FETCH NEXT FROM csr_TestCaseIdentifierInsert INTO #TestSequence, #ColumnName, #ColumnValue, #IsAlphaNumeric
WHILE ##fetch_status = 0
BEGIN
INSERT INTO [dbo].[TestCasesIdentifier]
([TestCaseId],
[TestCaseSequence],
[FieldName],
[FieldValue],
[AlphaNumeric])
VALUES
(#TestCaseID, #TestSequence, #ColumnName, #ColumnValue,#IsAlphaNumeric)
FETCH NEXT FROM csr_TestCaseIdentifierInsert INTO #TestSequence, #ColumnName, #ColumnValue, #IsAlphaNumeric
END
CLOSE csr_TestCaseIdentifierInsert
DEALLOCATE csr_TestCaseIdentifierInsert
END -- loop to add records to testcasesidentifier
END
END
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN
DECLARE #ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
DECLARE #ErrorSeverity INT = ERROR_SEVERITY()
DECLARE #ErrorState INT = ERROR_STATE()
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH
You are almost there. I usually wrap the stored proc code within a BEGIN..END block as well, then next comes the most important part: you must add SET XACT_ABORT ON; before your TRY..CATCH and BEGIN TRAN, as SQL Server defaults the XACT_ABORT to OFF. Otherwise not everything will be rolled back.
Example setup:
CREATE PROCEDURE dbo.uspMyTestProc
AS
BEGIN
SET NOCOUNT, XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
-- Do your magic stuff here before committing...
COMMIT;
END TRY
BEGIN CATCH
IF ##trancount > 0
ROLLBACK TRANSACTION;
-- Add extra error logging here if you want...
END CATCH;
END;
GO
Also, if you want to add a possible stacktrace if you are using nested procedures et cetera you might want to consider using a generic error handler à la Erland Sommerskog. We adapted this approach completely. See for more details How to handle Transaction in Nested procedure in SQL server?

How to rollback transaction in a stored procedure?

When the internal SP tries to rollback transaction it completed with an error:
Msg 266, Level 16, State 2, Procedure ptest, Line 0 [Batch Start Line
37] Transaction count after EXECUTE indicates a mismatching number of
BEGIN and COMMIT statements. Previous count = 1, current count = 0.
Is it possible to rollback transaction inside the internal SP?
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ptest]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql #statement = N'CREATE PROCEDURE [dbo].[ptest] AS'
END
GRANT EXECUTE on [dbo].[ptest] to public;
GO
ALTER PROCEDURE [dbo].[ptest]
#parrollback bit = 0
AS
BEGIN
SET NOCOUNT ON
SET XACT_ABORT OFF
select ##TRANCOUNT as '##TRANCOUNT:[ptest] '
if #parrollback is not null and #parrollback>0
if ##TRANCOUNT>0 rollback tran;
END
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[pcaller]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql #statement = N'CREATE PROCEDURE [dbo].[pcaller] AS'
END
GRANT EXECUTE on [dbo].[pcaller] to public;
GO
ALTER PROCEDURE [dbo].[pcaller]
AS
BEGIN
SET NOCOUNT ON
begin tran
select ##TRANCOUNT as '##TRANCOUNT: before [ptest]'
exec ptest 1
select ##TRANCOUNT as '##TRANCOUNT: after [ptest] '
if ##TRANCOUNT>0 rollback tran;
END
GO
-------------
exec pcaller
/*
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ptest]') AND type in (N'P', N'PC'))
drop proc pcaller
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ptest]') AND type in (N'P', N'PC'))
drop proc ptest
*/
try not to handle parent transactions inside a child procedure (exception when XACT_STATE() = -1). Handle the transaction at the "execution" level that started it.
if a procedure is executed in a parent transaction, then create a savepoint and rollback to it when needed. capture the execution result of the child procedure and handle the transaction at the parent level (if the parent is the one that begun the transaction).
CREATE OR ALTER PROCEDURE [dbo].[ptest] #parrollback bit = 0
AS
BEGIN
SET NOCOUNT ON
SET XACT_ABORT OFF
DECLARE #trancount INT = ##TRANCOUNT;
IF #trancount = 0
BEGIN
BEGIN TRANSACTION;
END
ELSE
BEGIN
SAVE TRANSACTION MySavepoint;
END
--do stuff.........
--when it is time to commit or check for errors
--assume #parrollback is the main control criterium
IF #parrollback = 1
BEGIN
IF #trancount = 0
BEGIN
ROLLBACK TRANSACTION;
RETURN(0);
END
ELSE
BEGIN
ROLLBACK TRANSACTION MySavePoint
RETURN (1);
END
END
--just handle #parrollback <> 1, for completeness of the test
IF #trancount = 0
BEGIN
COMMIT TRANSACTION;
END
RETURN (0);
END
GO
CREATE OR ALTER PROCEDURE dbo.pcaller
AS
BEGIN
SET NOCOUNT ON
DECLARE #ptestexec INT;
BEGIN TRANSACTION
select ##TRANCOUNT as '##TRANCOUNT: before [ptest]'
EXEC #ptestexec = dbo.ptest #parrollback = 1;
IF #ptestexec = 1
BEGIN
ROLLBACK TRANSACTION
END
ELSE
BEGIN
COMMIT TRANSACTION
END
--execute ptest, outside of a transaction
EXEC #ptestexec = dbo.ptest #parrollback = 0;
SELECT ##TRANCOUNT AS trancount1;
EXEC #ptestexec = dbo.ptest #parrollback = 1;
SELECT ##TRANCOUNT AS trancount2;
--execute ptest, outside of a transaction
BEGIN TRANSACTION;
--ptest executed in a parent transaction
EXEC #ptestexec = dbo.ptest #parrollback = 0;
SELECT ##TRANCOUNT AS trancount3; --ptest does not affect the parent transactions
COMMIT TRANSACTION --or rollback
END
GO
EXEC dbo.pcaller
GO

undo stored procedure if there is an error on execution

alter proc insert_toplam 'deneme2'
#str nvarchar(100)
as
begin
insert into tblSekiller(sekilURL)
select #str
insert into tbl_fake
select #str
end
i want prevent procedure from inserting table_1 if somehow the procedure give an error on line insert into tbl_fake is it possible?
You can use TRY-CATCH and do the following:
BEGIN TRANSACTION;
BEGIN TRY
INSERT INTO tblSekiller(sekilURL)
SELECT #str
INSERT INTO tbl_fake
SELECT #str
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION; -- if your insert generated an error, rollback
END CATCH;
IF ##TRANCOUNT > 0
COMMIT TRANSACTION; -- otherwise, commit the transaction
GO

Try-Catch with Stored Procedures in SQL server

I have created a stored procedure with try-catch for deleting records.A message should be displayed if a record is deleted or if there is an error.The delete procedure works but the message is not being displayed.
Also,it asks me to input a value for #msg and #return when executing the procedure.
Here is my Stored Procedure code:
IF OBJECT_ID('[dbo].[usp_AttendanceDelete]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[usp_AttendanceDelete]
END
GO
CREATE PROCEDURE [dbo].[usp_AttendanceDelete]
#A_ID int,
#msg VARCHAR(50) OUTPUT,
#return INT OUTPUT
AS
BEGIN
SET NOCOUNT ON
BEGIN TRANSACTION
BEGIN TRY
DELETE
FROM [dbo].[Attendance]
WHERE [A_ID] = #A_ID
SET #msg = 'Attendance Deleted'
SET #return = 1
END TRY
BEGIN CATCH
--SELECT error_message() as error
SET #msg = 'Attendance Delete FAIL.'
SET #return = 0
GOTO fail_rollback
END CATCH
COMMIT TRANSACTION
RETURN
fail_rollback:
ROLLBACK TRANSACTION
RETURN
END
GO
Here is the code to execute the procedure:
EXECUTE [dbo].[usp_AttendanceDelete]
#A_ID ='234',
#msg='success',
#return ='1'
You can supply variables rather than values when calling the stored procedure and you need to remember to mark them as output also:
DECLARE #msg varchar(50)
DECLARE #return int
EXECUTE [dbo].[usp_AttendanceDelete]
#A_ID ='234',
#msg=#msg output,
#return=#return output
--Do something with msg/return
Try this Query below
IF OBJECT_ID('[dbo].[usp_AttendanceDelete]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[usp_AttendanceDelete]
END
GO
CREATE PROCEDURE [dbo].[usp_AttendanceDelete]
#A_ID int,
#msg VARCHAR(100) OUTPUT,
#return INT OUTPUT
AS
BEGIN TRANSACTION;
BEGIN TRY
IF EXISTS(SELECT 1 FROM [Attendance] WHERE [A_ID] = #A_ID)
Begin
DELETE
FROM [dbo].[Attendance]
WHERE [A_ID] = #A_ID
SELECT #msg = 'Attendance Deleted'
SELECT #return = 1
END
ELSE
Begin
SELECT #msg='IN Put Record doesn''t exists'
END
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION;
END CATCH;
IF ##TRANCOUNT > 0
COMMIT TRANSACTION;
GO
DECLARE #msg VARCHAR(100),#return INt
EXEC DBO.[usp_AttendanceDelete] 2,#msg OUT,#return OUT
SELECT #msg, #return

How to rollback everything(t-sql) if restoring of DB is failed?

I insert new record to Project table and after that I restore DB and inserting some row to that DB.
I want the following:
If record was inserted to Project table but restoring DB(by CreateDB stored procedure below) is failed, so I want to rollback everything
If inserting record failed I also want to rollback everything
To achieve this I'm using transaction, but I get the following error RESTORE DATABASE is terminating abnormally.
Below are the scripts I use for this purpose.
What is the problem and how to fix it?
CreateProject
ALTER PROCEDURE CreateProject
#name nvarchar(50)
AS
SET XACT_ABORT, NOCOUNT ON
DECLARE #starttrancount int
BEGIN TRY
SELECT #starttrancount = ##TRANCOUNT
IF #starttrancount = 0
BEGIN TRANSACTION
DECLARE #sql nvarchar(MAX)
DECLARE #projId int
DECLARE #dbName nvarchar(128)
-- ======================================================================
-- Create new project
-- ======================================================================
INSERT INTO Project(Name)
VALUES(#name)
-- ======================================================================
-- Generate dbname that will be used to restore db with that name
-- ======================================================================
SET #projId = SCOPE_IDENTITY()
SET #dbName = 'Site' + CONVERT(nvarchar(20), #projId)
-- ======================================================================
-- Create db with #dbname
-- ======================================================================
EXEC CreateDB #dbName
--Insert some records to tables in created DB
...
...
IF #starttrancount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
DECLARE #ErrorMessage NVARCHAR(4000)
DECLARE #ErrorState INT
DECLARE #ErrorSeverity INT
IF XACT_STATE() <> 0 AND #starttrancount = 0
ROLLBACK TRANSACTION
SELECT
#ErrorMessage = 'Source:CopyPage\r\t' + ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage,
#ErrorSeverity,
#ErrorState);
END CATCH
CreateDB
ALTER PROCEDURE CreateDB
#newDbname nvarchar(128),
#restoreFrom nvarchar(MAX) = 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Backup\Site.bak'
AS
SET XACT_ABORT, NOCOUNT ON
BEGIN TRY
DECLARE #newMdfPath nvarchar(MAX) = 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\' + #newDbname + '.mdf'
DECLARE #newLdfPath nvarchar(MAX) = 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\' + #newDbname + '_log.ldf'
RESTORE DATABASE #newDbname FROM DISK=#restoreFrom
WITH RECOVERY,
MOVE 'Site' TO #newMdfPath,
MOVE 'Site_log' TO #newLdfPath
END TRY
BEGIN CATCH
DECLARE #ErrorMessage NVARCHAR(4000)
DECLARE #ErrorState INT
DECLARE #ErrorSeverity INT
SELECT
#ErrorMessage = 'Source:PrepareNewSite\r\t' + ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage,
#ErrorSeverity,
#ErrorState);
END CATCH
You can't "roll back" a database restore, its not an ATOMic operation.
You'll have to trap the error and undo-it manually.
would you want to rollback only current transation?
begin tran
-- perform.......
if ##error>0
rollback tran
commit tran

Resources