Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Locking table during transaction

Author  Topic 

smeghead
Starting Member

3 Posts

Posted - 2006-08-09 : 22:41:38
Hi,

Im trying to lock a table for the duration of a transaction. When I say lock, I dont just mean to stop insert and updates, but I also dont want anything to select from the table either.

The code is being run inside a trigger, which is shown below:


ALTER TRIGGER TR_UpdateTable_SetGlobalNumber ON dbo.Updates
INSTEAD OF INSERT
AS

BEGIN

DECLARE insertedItems CURSOR FAST_FORWARD FOR
SELECT TableId,ColumnsChanged,RowGuidValue,Operation,UpdateId,ShadowId
FROM inserted

DECLARE @tableId uniqueidentifier
DECLARE @columnsChanged varbinary(15)
DECLARE @operation tinyint
DECLARE @idValue uniqueidentifier
DECLARE @updateId uniqueidentifier
DECLARE @numInInserted bigint
DECLARE @offset bigint
DECLARE @nextNum bigint
DECLARE @nextIncrement bigint
DECLARE @globalUpdateNumber bigint
DECLARE @shadowId uniqueidentifier
DECLARE @doIncrement tinyint

OPEN insertedItems

SET @numInInserted = @@CURSOR_ROWS

-- within this transaction I dont want the GlobalUpdateNumber
-- table to be available to any other calls

BEGIN TRANSACTION

SELECT @globalUpdateNumber=UpdateNumber,@nextIncrement=UpdateIncrement
FROM GlobalUpdateNumber

IF ( 9223372036854775800 - @globalUpdateNumber < @numInInserted )
BEGIN
SET @doIncrement = 1
SET @offset = @numInInserted - (9223372036854775800 - @globalUpdateNumber)

UPDATE GlobalUpdateNumber SET UpdateNumber = @offset, UpdateIncrement=UpdateIncrement+1

SET @nextNum = 9223372036854775800-@numInInserted+@offset
END
ELSE
BEGIN
SET @doIncrement = 0
UPDATE GlobalUpdateNumber SET UpdateNumber = @globalUpdateNumber + @numInInserted

SET @nextNum = @globalUpdateNumber
END

COMMIT


FETCH NEXT FROM insertedItems INTO @tableId,@columnsChanged,@idValue,@operation,@updateId,@shadowId

WHILE @@FETCH_STATUS = 0
BEGIN

INSERT INTO Updates (TableId,ColumnsChanged,RowGuidValue,Operation,GlobalChangeNumber,GCNIncrement,UpdateId,ShadowId)
VALUES (@tableId,@columnsChanged,@idValue,@operation,@nextNum,@nextIncrement,@updateId,@shadowId)

IF ( @doIncrement = 1 AND @nextNum > 9223372036854775800 )
BEGIN
SET @nextNum = 0
SET @nextIncrement = @nextIncrement + 1
END
ELSE
SET @nextNum = @nextNum + 1

FETCH NEXT FROM insertedItems INTO @tableId,@columnsChanged,@idValue,@operation,@updateId,@shadowId

END

CLOSE insertedItems
DEALLOCATE insertedItems
END


The problem with the above was that when more than 1 item was being inserted at basically the same time, both would get the same number. So if "A" & "B" inserted at the same time, "A" would get 10 from the globalupdate number table, and then "B" would do the same before "A" could update the number to 11. Hence "A" and "B" would have 10 as their number, instead of "A"=10 and "B"=11.

I had a look for ways to lock a table, but was unable to find a solution which would solve this problem. I cant use ISOLATION LEVEL on the transaction, because that only stops inserts and updates. I also tried creating a function which returned a table (which I could lock in the select statement), however I cant update a table inside the function, which kind of defeated the purpose.

LoztInSpace
Aged Yak Warrior

940 Posts

Posted - 2006-08-11 : 00:51:11
Why would you want to do that? You realise that if you actually succeeded you would have the slowest system on the planet because you could only ever execute one transaction at a time? Can you use an identity instead? I think if you state the problem you are trying to solve you'll find an all round better solution.
Go to Top of Page

AndrewMurphy
Master Smack Fu Yak Hacker

2916 Posts

Posted - 2006-08-11 : 06:55:16
You'll also have a performance problem because you're invoking a CURSOR.
Go to Top of Page
   

- Advertisement -