views:

90

answers:

2

I've got a T-SQL stored procedure running on a Sybase ASE database server that is sometimes failing to commit all of its operations, even though it completes without exception. Here's a rough example of what it does.

BEGIN TRANSACTION

UPDATE TABLE1
SET FIELD1 = @NEW_VALUE1
WHERE KEY1 = @KEY_VALUE1

IF @@error <> 0 OR @@rowcount <> 1 BEGIN
    ROLLBACK
    RETURN 1
END

UPDATE TABLE2
SET FIELD2 = @NEW_VALUE2
WHERE KEY2 = @KEY_VALUE2

IF @@error <> 0 OR @@rowcount <> 1 BEGIN
    ROLLBACK
    RETURN 2
END

INSERT TABLE2 (FIELD2, FIELD3)
VALUES (@NEW_VALUE3a, @NEW_VALUE3b)

IF @@error <> 0 OR @@rowcount <> 1 BEGIN
    ROLLBACK
    RETURN 3
END

COMMIT TRANSACTION
RETURN 0

The procedure is called at least hundreds of times a day. In a small percentage of those cases (probably < 3%), only the INSERT statement commits. The proc completes and returns 0, but the two UPDATEs don't take. Originally we thought it might be that the WHERE clauses on the UPDATEs weren't matching anything, so we added the IF @@rowcount logic. But even with those checks in there, the INSERT is still happening and the procedure is still completing and returning 0.

I'm looking for ideas about what might cause this type of problem. Is there anything about the way SQL transactions work, or the way Sybase works specifically, that could be causing the COMMIT not to commit everything? Is there something about my IF blocks that could allow the UPDATE to not match anything but the procedure to continue? Any other ideas?

+1  A: 

is is possible that they are updating, but something is changing the values back? try adding a update trigger on those tables and within that trigger insert into a log table. for rows that appear to have not been updated look in the log, is there a row or not?

KM
That's it exactly! I was looking for a database problem, but it's actually an application problem. There's a bug in the application logic that allows the user to open the same record twice and save it two different ways, effectively undoing the updates (but leaving the insert) from the first save. It doesn't happen often because it doesn't make any sense for the user to use the application that way. But users don't always make sense, so I'll need to plug the hole and make sure the workflow makes it harder for them to do things like that. Thanks!
John M Gant
if it is a stale data thing, where two screens are open and the first is saved then the second is saved (removing the first data), you can use a LastChgDate to prevent the problem. When you load the data, load the LastChgDate, when you save, pass it in and in the UPDATE add _AND LastChgDate=@LastChgDate_. If @@ROWCOUNT=0 issue an error message that "someone else just saved the data before you"
KM
+1  A: 

Not knowing how you set the values for your variables, it occurs to me that if the value of @NEW_VALUE1 is the same as the previous value in FIELD1 , the update would succeed and yet appear to have not changed anything making you think the transaction had not happened.

You also could have a trigger that is affecting the update.

HLGEM
Thanks. I unfortunately couldn't give much actual detail, which does make it hard to give a specific answer. I didn't mention it in the question, but I've got application log data that shows the details of the stored proc call, and I've verified that the values of @NEW_VALUE1 and @KEY_VALUE1 are as expected (and not identical).
John M Gant
I hadn't thought about the trigger. Sybase (at least the version we're on) doesn't have BEFORE UPDATE triggers, so a trigger can't be preventing it, but it is possible that an UPDATE trigger could be changing it back. I'll check that.
John M Gant
Nope, no triggers on that table.
John M Gant
Since @NEW_VALUE1 is assigned to FIELD1 but @KEY_VALUE1 is compared with KEY1, I think your first sentence needs fixing - "if the value of @NEW_VALUE1 is the same as the previous value in FIELD1".
Jonathan Leffler
Yes Jonathan. Thanks, have fixed to say that.
HLGEM