I have an SSIS Package which I execute manually for testing. When I do so, an error occurs (see pic below). But first let me explain what happens in the package: There is just the dataflow itself. In there I query a view (OLE DB Source) which will provide me the parameters I will need for the next step. Then the arrow points to the OLE DB Command where I EXEC a stored procedure on the local DB server and hand over the parameters as well.
This SP is my wrapper where 3 main things happen: 1. SET XACT_ABORT ON; (we will need this for distributed transaction later on) 2. Call a helper SP which will create a new Synonym to my Remote Target table. (this creates a synonym like MY_REMOTE_TABLE, when it is created I can query it maunally with no problem) 3. Call the helper SP which will perform the main task.
This helper SP has a BEGIN DISTRIBUTED TRANSACTION. In there I insert into MY_REMOTE_TABLE some records from my local DB. Now I placed a log entry directly before and directly after the BEGIN DISTRIBUTED TRANSACTION, but in my log there is only the entry which I print before the transaction begins. So it looks like it fails as soon as It opens up the distributed transaction.
The pic below shows the error I get from SSIS, but I have no idea what to do about it. Any idea is very much appreciated!
Error: SSIS Error Code DTS_E_OLEDBERROR. An OLE DB error has occurred. Error code: 0x80040E14. An OLE DB record is available. Source: "Microsoft OLE DB Provider for SQL Server" Hresult: 0x80040E14 Description: "The Microsoft Distributed Transaction Coordinator (MS DTC) has cancelled the distributed transaction"
Error: SSIS Error Code DTS_E_INDUCEDTRANSFORMFAILUREONERROR. The "input "OLE DB Command Input" (140)" failed because error code 0xC020906E occurred, and the error row disposition on "input "OLE DB Command Input" (140)" specifies failure on error. An error occurred on the specified object of the specified component. There may be error messages posted before this with more information about the failure.
Error: SSIS Error Code DTS_E_PROCESSINPUTFAILED. The ProcessInput method on component "exec Run_My_Wrapper_SP" (135)" failed with error code 0xC0209029 while processing input "OLE DB Command Input" (140). The identified component returned an error from the ProcessInput method. The error is specific to the component, but the error is fatal and will cause the Data Flow task to stop running. There may be error messages posted before this with more information about the failure.
BEGIN TRY
BEGIN DISTRIBUTED TRANSACTION
-- do my stuff here
IF (##TRANCOUNT > 0 AND XACT_STATE() = 1)
BEGIN
COMMIT TRANSACTION
END
IF #Output_on = 1
EXEC sp_write_to_log 'End of DISTRIBUTED TRANSACTION!';
END TRY
BEGIN CATCH
IF (##TRANCOUNT > 0 AND XACT_STATE() = -1)
ROLLBACK TRANSACTION
INSERT INTO my_error_log (Time, Source, MSG, MSG_NR, Line_Nr)
VALUES (GETDATE(), ERROR_PROCEDURE() , ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_LINE());
IF #Output_on = 1
EXEC sp_write_to_log 'Error in DISTRIBUTED TRANSACTION!';
END CATCH;
Ensure that MSDTC is enabled on your local computer
Go to Start Menu > Run
At command prompt type dcomcnfg and press enter. Component Service Window will pop up.
Expand Component service, Right Click on My Computer and select start
MSDTC
Also verify by executing Helper SP in SQL Server Management Studio query window itself.
Using TRY...CATCH to handle error in the transaction block (BEGIN TRAN ... COMMIT)
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
/*******...YOUR QUERY HERE eg. DELETE FROM customer..*******/
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- retrieve error information
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_LINE () AS ErrorLine
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_MESSAGE() AS ErrorMessage;
IF (XACT_STATE()) = -1 --uncommittable transaction state.
BEGIN
SELECT
N'The transaction is in an uncommittable state.' +
'Rolling back transaction.'
ROLLBACK TRANSACTION;
END;
IF (XACT_STATE()) = 1 --committabletransaction state
BEGIN
SELECT
N'The transaction is committable.' +
'Committing transaction.'
COMMIT TRANSACTION;
END;
END CATCH;
GO
Related
I have a stored procedure that may be called from a transaction. When there is an exception I want to rollback the transaction (the top-level transaction). I would like to use something like this:
...procedure definition...
BEGIN
BEGIN TRY
--work&logic
END TRY
BEGIN CATCH
-- An error occurred!
IF ##TRANCOUNT > 0
ROLLBACK
END CATCH
END
The catch with this is, that the SQL Code Guard reports for this the warning EI020 - ROLLBACK TRANSACTION without BEGIN TRANSACTION. Is there a way to write this properly?
I've got a stored procedure that contains a try-catch block. In the catch block I call raiserror() to rethrow the error with some context.
I was expecting that if an error occurred the raiserror() would be called and execution would immediately return from the stored procedure to the calling code. However, this doesn't appear to be the case. It looks like execution of the stored procedure continues until it hits a return statement, then the raiserror() takes effect.
Is this correct - that raiserror() won't have an effect until return is called or the end of the stored procedure is reached?
I'm using SQL Server 2012.
EDIT:
in reply to request for details of the stored procedure, here's the relevant snippet of code:
DECLARE #ErrMsg VARCHAR(127) = 'Error in stored procedure ' + OBJECT_NAME(##PROCID) + ': %s';
declare #UpdateDateRecordCount table (LastUpdated datetime, NumberRecords int);
begin try;
insert into #UpdateDateRecordCount (LastUpdated, NumberRecords)
exec sp_ExecuteSql
#UpdateCountQuery,
N'#LastUpdated datetime',
#LastUpdated = #LastUpdated;
if ##rowcount <= 0
begin;
return 0;
end;
end try
begin catch;
declare #InsertError varchar(128) = 'Error getting updated date record count: '
+ ERROR_MESSAGE();
RAISERROR (#ErrMsg, 16, 1, #InsertError);
end catch;
-- Attempt to loop through the records in #UpdateDateRecordCount...
The #UpdateCountQuery argument will be set to something like:
N'select LastUpdated, count(*) from dbo.Part where LastUpdated > #LastUpdated group by LastUpdated;'
As I understand it, if you want the execution to stop, you need to raise the error within the TRY block, and then raise the error again in your CATCH block this will make sure that the error is "raised" to the caller.
Or you could add a RETURN statement after your RAISERROR statement in the CATCH block. This will exit the procedure and return to the caller.
Also, as suggested by MSDN you should try to use the THROW statement instead of RAISERROR since it (the RAISERROR) will be phased out.
That's not how it works in T-SQL. Nothing in the documentation for TRY...CATCH or RAISERROR specifies any special cases that would override:
When the code in the CATCH block finishes, control passes to the statement immediately after the END CATCH statement. Errors trapped by a CATCH block are not returned to the calling application. If any part of the error information must be returned to the application, the code in the CATCH block must do so by using mechanisms such as SELECT result sets or the RAISERROR and PRINT statements.
If you want the stored proc to exit, you need a RETURN statement as well.
It depends on the severity level that you use. There's a lot more information in the below link:
http://technet.microsoft.com/en-us/library/ms178592.aspx
But to quote the article:
The errors generated by RAISERROR operate the same as errors generated
by the Database Engine code. The values specified by RAISERROR are
reported by the ERROR_LINE, ERROR_MESSAGE, ERROR_NUMBER,
ERROR_PROCEDURE, ERROR_SEVERITY, ERROR_STATE, and ##ERROR system
functions. When RAISERROR is run with a severity of 11 or higher in a
TRY block, it transfers control to the associated CATCH block. The
error is returned to the caller if RAISERROR is run...
So if your severity level is 11 or higher then the control will be immediately transferred to the CATCH block.
The below example shows a severity level of 16:
RAISERROR ('Error raised in TRY block.', -- Message text.
16, -- Severity.
1 -- State.
);
I want to rollback all statements in the CATCH block when the error is encountered in the TRY block:
BEGIN TRY
begin transaction
create table t3(a int )
insert into t3 values(1)
insert into t3 values(1,2) --error occur
insert into t3 values(3)
END TRY
BEGIN CATCH
--just take care of rollback
IF ##TRANCOUNT <> 0
BEGIN
PRINT 'in catch,ROLLING BACK';
ROLLBACK
END
END CATCH
go
At first the error is caught since the PRINT in the CATCH block works. However, after several changes back and forth, the error seems not be caught in the CATCH any more since no more printing happens.
Therefore, I open a new query and execute the same thing. This time error can be caught again!!
Sorry about the big images
When you run this code in a tool like management studio, your transaction is mantained for your SPID (assigned to a query window).
So the inconsistent reult issue is because you don't close the transaction on all of your code paths (lets say the rollback dosn't get reached), your transaction is still active the next time you run the script.
If you add IF ##TRANCOUNT <> 0 rollback transaction to the begining of your script you will have a consistent output.
Also notice that the try catch block is not meant to catch errors at statement compile level.
If you replace your error by a division by zero for example (print 1 / 0) the catch will work properly.
In MSDN
The following types of errors are not handled by a CATCH block when they occur at the same level of execution as the TRY…CATCH construct:
Compile errors, such as syntax errors, that prevent a batch from
running.
Errors that occur during statement-level recompilation, such as object name resolution
Errors that occur after compilation because of deferred name resolution.
I have been researching the TRY/CATCH block and I am a little stumped on how to pass an error the way I need to do so. From what I have read and if I understand correctly, a RAISERROR in a CATCH block in SQL will be passed to the calling batch OR the calling application. The application is running a stored procedure which has a transaction in it. The transaction is wrapped in a TRY/CATCH block. In the CATCH block, I am raising the error if something in the transaction fails causing it to jump to CATCH. If running the procedure via SSMS, the error shows up fine and the transaction rolls back. However, if the application calls the stored procedure and the same error occurs, the application never knows about the error and thus doesn't now the procedure failed.
First of all, am I understanding correctly how the RAISERROR in CATCH works? If so, how can I get that error raised back to the calling application?
BEGIN TRY
BEGIN TRAN
...............
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
DECLARE #ErrMsg NVARCHAR(4000)
SELECT #ErrMsg = ERROR_MESSAGE()
RAISERROR(#ErrMsg, 16, 1)
END CATCH
I am Running Windows 7, SQL Server 2005
The easiest way to do what your trying to do would be to declare #ErrMsg as an output parameter of your procedure and handle that in your calling application.
You can read up on how RAISEERROR handles it's output here if you wish to continue using it to handle your error outputs. http://msdn.microsoft.com/en-us/library/ms178592.aspx
I need to use RAISERROR to throw a message(pop up message) and commit that transaction.Is there any option?
For severity 18 the transaction got rollback.I have changed the severity to 10 and tried like
RAISERROR('Your Reference Number is %s',10,0,#param);
this but it commits the transaction but doesnt show message.
What i need here is Message has to be thrown and transaction has to be commited
Any suggestion?
Don't use exceptions to pass back "OK" messages. You wouldn't in a c# or java program. Exception means "I've aborted because SHTF"
You'd use thsi to return meaningful data
SELECT 'Your Reference Number is ' + #param
In a typical template (from my answer Nested stored procedures containing TRY CATCH ROLLBACK pattern?)
SET XACT_ABORT, NOCOUNT ON
BEGIN TRY
BEGIN TRANSACTION
[...Perform work, call nested procedures...]
COMMIT TRANSACTION
SELECT 'Your Reference Number is ' + #param
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK TRANSACTION
RAISERROR [rethrow caught error using #ErrorNumber, #ErrorMessage, etc]
END CATCH
RAISERROR with severity above 10 will be treated like an exception by the ADO.Net client. Depending on how your call context looks like, this may or may not rollback the transaction. If you use a SqlTransaction or a TransactionScope in the client, or a BEGIN TRY/BEGIN CATCH block on the server side, this will likely roll back the transaction. Point is that RAISERROR neither commits nor rolls back the transaction, is your own code that rolls back or commits and we cannot know what you're doing from your post.
RAISERROR with severity bellow 10 will be considered a informational message and not cause an exception. See Database Engine Error Severities. This is probably why you say that the 'it doesn't show the message' (whatever that means). Client side frameworks treat the informational messages differently, for instance ADO.Net will raise an SqlConnection.InfoMessage event on the connection but will not raise an exception. You probably don't have anything set up in your application for this event and your code is simply ignoring the info messages. For example how to use the InfoMessage event see Connection Events (ADO.NET)
It sounds like you need to use the WITH NOWAIT parameter for RAISERROR - this will output it to the message window immediately:
RAISERROR('Your Reference Number is %s',10,0,#param) WITH NOWAIT