views:

345

answers:

1

Hello,

I have a MSSSQL stored procedure performing a distributed transaction that looks like this:

SET XACT_ABORT ON;
SET NOCOUNT ON;

BEGIN TRY
  BEGIN DISTRIBUTED TRANSACTION


  insert into LNKSRV.INST.dbo.zz (id, val) values (1, 'a');
  insert into LNKSRV.INST.dbo.zz (id, val) values (2, 'b');


  COMMIT TRANSACTION
END TRY
BEGIN CATCH
  if (XACT_STATE() <> 0) 
  BEGIN
    ROLLBACK TRANSACTION;
  END
  print ERROR_MESSAGE();
  print ERROR_LINE();
  print ERROR_SEVERITY();

END CATCH

This works fine.

If I add this 3rd insert statement:

  insert into LNKSRV.INST.dbo.zz (id, val) values ('error', 'b');

...it fails correctly -- the transaction is rolled back on the remote server and control passes to the CATCH block and I get information about the error (can't convert 'error' to int).

But if I add this insert statement:

  insert into LNKSRV.INST.dbo.zz (id, val) values (-1, 'b');

..and I have a check contraint on the remote table requiring values > 0 in the id column, then things do not work as I expect. The transaction DOES roll back, but control DOES NOT transfer to the catch block. Instead, execution just dies and this is printed to the output window:

The Microsoft Distributed Transaction Coordinator (MS DTC) has cancelled the distributed transaction

Why? I need to log these errors in the catch blog.

+2  A: 

Since the distributed transaction coordinator is handling this, when the transaction fails on the distributed part of the transaction, the DTC sends a message in the form of an attention, which stops your code from executing, and which the TRY/CATCH cannot process.

SQL Server can detect on your end when you are trying to insert an incorrect data type into a table (even on a remote instance) but the constraint is processed on the linked server, which causes the attention to be sent to DTC and your TRY/CATCH to be ignored.

For more information see the first "Note" section in the "Using TRY...CATCH in Transact-SQL" section of SQL Server 2008 Books Online, located at:

http://msdn.microsoft.com/en-us/library/ms179296.aspx

casperOne
So your answer is, "I'm screwed"? :-|
Clyde
@Clyde: Not completely, you would handle it on the level of whatever is calling the database code. The exception would bubble up there and can be caught there.
casperOne