I want to create several stored procedures (or user-defined functions) within a transaction. CREATE PROCEDURE
statement must be the only statement in the batch, so I have to use following template:
x
BEGIN TRANSACTION MyTransaction
USE MyDatabase
GO
CREATE PROCEDURE A
AS
-- The body of procedure A
GO
CREATE PROCEDURE B
AS
-- The body of procedure B
GO
CREATE PROCEDURE C
AS
-- The body of procedure C
GO
COMMIT TRANSACTION MyTransaction
The problem appears if an error occurs within one of the batches. For example, if error occurs while procedure B is creating, MyTransaction
with procedures A and B will be rolled back. But the script will continue to run. So, the procedure C will be created.
Also it’s not possible to skip the statement using GOTO
and @@error
counter checking, because it cannot go to a label outside the batch in which GOTO
is placed.
How to prevent any database changes if an error occurs?
Advertisement
Answer
You can try to do something like this with SET XACT_ABORT ON.
IF EXISTS (SELECT * FROM tempdb..sysobjects WHERE id=OBJECT_ID('tempdb..#tmpErrors')) DROP TABLE #tmpErrors
GO
CREATE TABLE #tmpErrors (Error int)
GO
SET XACT_ABORT ON
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO
BEGIN TRANSACTION
GO
PRINT N'Creating [Proc A]'
GO
-------------------------------------------------------------------------
CREATE PROCEDURE A
AS
-- The body of procedure A
GO
-------------------------------------------------------------------------
IF @@ERROR<>0 AND @@TRANCOUNT>0 ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT=0 BEGIN INSERT INTO #tmpErrors (Error) SELECT 1 BEGIN TRANSACTION END
GO
PRINT N'Creating [Proc B]'
GO
-------------------------------------------------------------------------
CREATE PROCEDURE B
AS
-- The body of procedure B
GO
-------------------------------------------------------------------------
IF @@ERROR<>0 AND @@TRANCOUNT>0 ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT=0 BEGIN INSERT INTO #tmpErrors (Error) SELECT 1 BEGIN TRANSACTION END
GO
IF EXISTS (SELECT * FROM #tmpErrors) ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT>0 BEGIN
PRINT 'The database update succeeded'
COMMIT TRANSACTION
END
ELSE PRINT 'The database update failed'
GO
DROP TABLE #tmpErrors
GO