Reputation: 1336
I have a SQL Stored Procedure with Transaction
.
I actaully wrote the SP with three stages,each does something in different table.
The problem is , when the SP gets to the 3rd stage, one of the columns is varchar(20)
, but I inserted a string with 30 chars and eventhough the SP completed succefully , while I expceted it to get into the Catch block and make a ROLLBACK
.
The 3rd stage didn't commit , and no rows were added to the table, but still, it feels like the Transcation
didn't work and the two first stages committed.
Here's my SQL SP:
USE [dbfoo]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[io_sp_admin]
@id BIGINT = 0, @firstName VARCHAR(20),@lastName VARCHAR(20) ,@email VARCHAR(50), @birthDate DATETIME
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION [TranAddEmp]
OPEN SYMMETRIC KEY io_key DECRYPTION BY CERTIFICATE foo
--stage1
DECLARE @identity BIGINT = 0
INSERT INTO [dbo].[t1]
([id],
[deleted],
[user_name],
VALUES
(EncryptByKey(KEY_GUID('io_key'), CONVERT(VARBINARY(100),CAST(@id AS VARCHAR(10)))),
0,
'IoAdmin'
SELECT @identity = @@identity
--satge2
INSERT INTO [dbo].[t2]
([id]
,[deleted]
,[user_name]
VALUES
(@identity,
EncryptByKey(KEY_GUID('io_key'), CONVERT(VARBINARY(100),CAST(@ms_zehut AS VARCHAR(10)))),
0,
'IoAdmin'
--stage 3
INSERT INTO t3(
id,
lastName,
firstName,
birtdate,
email)
SELECT
@identity,
@lastName ,
@firstName ,
@birthDate,
@email
CLOSE ALL SYMMETRIC KEYS
SELECT CAST(1 as BIT) as 'Status', 'Succeeded' as 'ReturnMessage'
COMMIT TRANSACTION [TranAddEmp]
END TRY
BEGIN CATCH
SELECT CAST(0 as BIT) as 'Status', 'ADMIN - Add employee failed' as 'ReturnMessage'
ROLLBACK TRANSACTION [TranAddEmp]
END CATCH
END
Upvotes: 4
Views: 57
Reputation: 43636
You can see clearly that If you pass a string, which has bigger length then allowed, you will get the following error and the transaction is a rollback is performed:
Msg 8152, Level 16, State 30, Line 18 String or binary data would be truncated.
DROP TABLE IF EXISTS [dbo].[DataSource];
CREATE TABLE [dbo].[DataSource]
(
[value] VARCHAR(8)
);
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO [dbo].[DataSource] ([value])
VALUES ('123');
INSERT INTO [dbo].[DataSource] ([value])
VALUES ('very large string');
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN;
ROLLBACK TRANSACTION;
END;
THROW;
END CATCH
SELECT *
FROM [dbo].[DataSource];
So, there is nothing wrong with your code. But you are passing the strings through variables and the the value is automatically truncated to fit the variable length.
So, check the following:
DROP TABLE IF EXISTS [dbo].[DataSource];
CREATE TABLE [dbo].[DataSource]
(
[value] VARCHAR(8)
);
DECLARE @values VARCHAR(8) = 'very large string';
SELECT @values;
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO [dbo].[DataSource] ([value])
VALUES ('123');
INSERT INTO [dbo].[DataSource] ([value])
VALUES (@values);
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN;
ROLLBACK TRANSACTION;
END;
THROW;
END CATCH
SELECT *
FROM [dbo].[DataSource];
So, you can check the if the input parameters are valid before calling the stored procedure or to increase the value of the input parameters and rely on the engine. Anyway, I prefer validating the data before using it - it's seems more clear for me (why we are allowing a user to enter name with larger length if it is not allowed?).
Upvotes: 2