How to fail SQL Agent job after CATCH? - sql-server

In SQL Server 2012 I have a SQL Agent Job that shows "success" when it goes into the CATCH block, but I want it to show failure. I thought THROW would do this but in the below code when the query performs CATCH, ROLLBACK, and THROW the agent job succeeds.
All I'm trying to do is rollback the previous updates if update2 or update3 fail (pk violation), and in that case let the SQL job show "failure".
Please clue me in...
BEGIN TRY
BEGIN TRAN
UPDATE 1
UPDATE 2
UPDATE 3
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
;THROW
END CATCH

Related

Is it possible to execute code in SQL Server when a user aborts a procedure?

I currently have an audit process that is part of all procedures and it is very basic at a high level.
Procedure is executed.
It inserts into the Audit table with a start time and status of Running.
It completes with out errors and then updates that record to show a status of Complete.
If there is an actual error it will update with a status of Error.
However if a user manually aborts the procedures via the SQL Server Management Studio no update will occur. The record will remain as "Running".
Is there any functionality I can use to capture this scenario so I can tie out the audit record?
You simply need to enclose it inside a transaction, and use XACT_ABORT for automatic rollback.
CREATE OR ALTER PROCEDURE YourProc
-- parameters here
AS
SET NOCOUNT, XACT_ABORT ON;
BEGIN TRAN;
-- everything else here
COMMIT;
Always use SET XACT_ABORT ON if you have a transaction. This ensures that if the code is aborted or it errors, the transaction will be rolled back and not left hanging.
Do not use TRY CATCH unless you want to actually handle the error and log it. It is not necessary to use CATCH to ensure a rollback if you have XACT_ABORT. If you do catch, then rethrow the error using THROW; rather than RAISERROR. For example:
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK;
INSERT Audit... ;
THROW;
END CATCH;
But note that certain errors cannot be caught, and a user abort cannot be caught either. I suggest you use XEvents for that .

Greenplum - How To Handle Deadlock

When try to run SQL transaction from Greenplum. getting this error.
Transaction (Process ID 52) was deadlocked on lock resources with
another process and has been chosen as the deadlock victim.
Rerun the transaction.
We Tried :
On SQL server it is working But we wanted to write same transaction on greenplum
Transaction A
RETRY: -- Label RETRY
BEGIN TRANSACTION
BEGIN TRY
truncate table tablename
WAITFOR DELAY '00:00:05' -- Wait for 5 ms
Insert into tablename
COMMIT TRANSACTION
END TRY
BEGIN CATCH
PRINT 'Rollback Transaction'
ROLLBACK TRANSACTION
IF ERROR_NUMBER() = 1205 -- Deadlock Error Number
BEGIN
WAITFOR DELAY '00:00:00.05' -- Wait for 5 ms
GOTO RETRY -- Go to Label RETRY
END
END CATCH
OUTPUT :
IT INCLUDES
Conversion of mentioned sql transaction (retry and try/catch )block in greenplum syntax.
As process ID keep changing , want to avoid hardcode value when passing into transaction.
3.Also, I am trying to understand this error belongs to SQL SERVER OR transaction we written in greenplum.
Data flow in talend is:
**Read from MS SQL SERVER >> write into hdfs >> load into greenplum**
Any help on it would be much appreciated ?
You cannot begin or end the transaction within a transaction in Greenplum. It auto commit or auto roll back.
Multi-Version Concurrency Control, there is always a data consistency and also query always executes in sequential within parallel mechanisms.
RETRY: -- Label RETRY
BEGIN
truncate table tablename
select pg_sleep(5) -- Wait for 5 ms
Insert into tablename
RAISE INFO 'Rollback Transaction'
IF ERROR_NUMBER = 1205 -- Deadlock Error Number
THEN
select pg_sleep(5) -- Wait for 5 ms
-- Go to Label RETRY
END

BEGIN TRY/CATCH and MSDTC error

1/ The following code snippet show me the expected error: The INSERT statement conflicted with the FOREIGN KEY constraint FK_...
SET XACT_ABORT ON;
BEGIN TRANSACTION
INSERT INTO linkedsrv1.db1.[dbo].tbl1 ([Col1], [Col2])
VALUES (1200, 0)
COMMIT TRANSACTION
2/ But when I put this in a BEGIN TRY/CATCH, the error message is vague: Msg 1206, Level 18, State 118, Line 18
The Microsoft Distributed Transaction Coordinator (MS DTC) has cancelled the distributed transaction.
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION
-- Error is on this line
INSERT INTO linkedsrv1.db1.[dbo].tbl1 ([IdWebsite], [IdProductType])
VALUES (1200, 0)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
PRINT 'Error' -- Code not reached
SELECT ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_SEVERITY(), ERROR_STATE()
IF XACT_STATE() != 0
ROLLBACK TRANSACTION
END CATCH
Any idea why this happens?
Later edit:
It works in case I remove the unneeded explicit transaction. It is still not clear why I get this error when I put BEGIN/COMMIT TRAN.
I get the same error in case I have multiple inserts in multiple tables situated on linked server.
Any comment / remark is welcomed.
From MSDN:
SYMPTOMS
Consider the following scenario. You use the SQL Native Client OLE DB provider (SQLNCLI) in SQL Server 2005 to create a linked server. You create a distributed transaction. The distributed transaction contains a query that uses the linked server to retrieve data from a table. When you commit the distributed transaction, you may receive the following error message:
Msg 1206, Level 18, State 167, Line 3
The Microsoft Distributed Transaction Coordinator (MS DTC) has cancelled
the distributed transaction.
Additionally, you may receive the following error message when you run a query after this behavior occurs:
Msg 8525, Level 16, State 1, Line 1
Distributed transaction completed. Either enlist this session in a new
transaction or the NULL transaction.
This problem occurs if the following conditions are true:
You use the SQLNCLI provider to create a linked server between two
instances of SQL Server 2005.
The XACT_ABORT option is set to ON.
In the distributed transaction, you try to release a rowset before
all rows in the rowset are processed.
Note This problem may also occur if you call the ReleaseRows method in a distributed transaction to release a rowset before you commit a distributed transaction in an application.
CAUSE
This problem occurs because the SQLNCLI provider incorrectly sends an attention signal to the linked server to roll back the distributed transaction.
WORKAROUND
To prevent the SQLNCLI provider from sending an attention signal to the server, use the SQLNCLI provider to consume fully any rowsets that the OLE DB consumer creates.
Update
you need to configure 'remote proc trans' to "1" in server parameters.
Ex:
exec sp_configure 'remote proc trans','1'
reconfigure with override
This will permmit you to execute any distributed queries.
More Update
If you are using .Net framework in front end too, then I think you can use
TransactionScope Class. Remove transaction from query and put the Transaction in code level.
I have went to through this pain!
If you are performing any CRUD operation on a single table TRANSACTION is not needed.
In this case, the problem is, XACT_STATE() returns -1 because there is an error in the active transaction. But, ROLLBACK TRANSACTION fails, since there is NO transactions happened. You did only one transaction, INSERT, which failed, so there are no other transactions to rollback.
Its always better to relay on ##TRANCOUNT than XACT_STATE() (at least in this case).
to make it work, change like this(though I don't support TRAN for single table):
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION
BEGIN TRANSACTION starts a distributed transaction between the server running the statements and the linked server, since potentially you can run updates against both servers. When the INSERT fails it needs to cancel the distributed transaction, thus the error you are getting. So you have to handle errors on two levels (insert and transaction). In this scenario, you'll need two TRY/CATCH blocks as follows:
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION
BEGIN TRY
-- Error is on this line
INSERT INTO linkedsrv1.db1.[dbo].tbl1 ([IdWebsite], [IdProductType])
VALUES (1200, 0)
END TRY
BEGIN CATCH
SELECT 'Insert Error', ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_SEVERITY(), ERROR_STATE()
RAISERROR (15600,-1,-1, 'INSERT ERROR');
END CATCH
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT 'Transaction Error', ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_SEVERITY(), ERROR_STATE()
IF XACT_STATE() != 0
ROLLBACK TRANSACTION
END CATCH

SQL Server Insert hangs - blocked by a process

when i try to run an insert within an application, it hangs and eventually times out.
i ran the EXEC SP_WHO2 while it was still running and noticed that it was blocked by another process and there was a "lock" in the "wait type"
what does this mean? how do i fix it? i'm so lost.
the process that was in the "Blocked By" field had a delete statement in it. i validated the statement and it works fine.
Seems like your previous transaction is in open state due to some error in your stored procedure which prevents commiting /rollbacking the transaction in the absence of exception handling. This causes the table locking and application
gets hang in next request
Below is the recommended approach...
set xact_abort on
Begin Try
Begin Tran
//SQl Query
Commit Tran
End Try
Begin Catch
Rollback Tran
End Catch

Roll back in SQL Server 2005

My question: Is it possible to rollback a stored procedure from another stored procedure in SQL Server 2005?
I have SP1 to insert the values into one table and SP2 to insert the values into another table.
So, if any error comes while executing the SP2 I want to rollback the SP1 also.
Please anyone help me to solve my problem.
Thanks,
Bharath
You need to wrap both calls in a single transaction.
if you call them in SQL then this is way, or using a more comprehensive version like the other answer by answered 7 mins ago gbn.
create proc doall as
BEGIN TRY
BEGIN TRAN
EXECUTE SP1
EXECUTE SP1
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
END CATCH;
if you're calling the SPs from another source, such as from a non SQL program, you need to setup the outer transaction using a Microsoft Distributed Transaction Coordinator (MSDTC) service.
Depending on the API you're using you set up the transaction in Code, and then commit and rollback in code, dependant on conditions.
for example in .net you can use the System.Transactions namespace to create distributed transactions.
In the main program
var tran = new System.Transactions.Transaction();
.
.
.
in one piece of code doe a db call (and pass the tran object to the sql connection) so it enlists in the transaction... if it fails - abort the transaction (trans.Rollback())
.
.
.
.
in another piece of code do another db call (and pass the tran object to the sql connection) so it enlists in the transaction... if it fails - abort the transaction (trans.Rollback())
.
.
.
later...
if both pieces of code succeed commit the transaction
This is a good introduction to the this namespace if you're using .net
You need a wrapper stored procedure to manage the transaction.
##TRANCOUNT on entry and exit to a stored procedure must be the same, otherwise you get error 266. So you can't exit SP1 having started a TXN for example.
I assume that SP1 and SP2 ca nbe called standalone so you need a nested transaction.
Then you hit the same error because
BEGIN TRAN adds one to ##TRANCOUNT
COMMIT TRAN subtracts one from ##TRANCOUNT
ROLLBACK makes ##TRANCOUNT zero
So you can still get error 266.
My answer here explains more about it, including nesting, error 266 suppression etc: Nested stored procedures containing TRY CATCH ROLLBACK pattern?
So in your case, you need soemthing like this
CREATE PROCEDURE Wrapper
AS
SET XACT_ABORT, NOCOUNT ON
DECLARE #starttrancount int
BEGIN TRY
SELECT #starttrancount = ##TRANCOUNT
IF #starttrancount = 0
BEGIN TRANSACTION
EXEC SP1
EXEC SP2
IF #starttrancount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 AND #starttrancount = 0
ROLLBACK TRANSACTION
RAISERROR [rethrow caught error using #ErrorNumber, #ErrorMessage, etc]
END CATCH
GO

Resources