##ERROR <> 0 in trigger - error-handling

I'm involved in new project right now and I faced with below logic in Sybase ASE trigger:
CREATE TRIGGER TR_TEST2
ON TBL_TEMP2
FOR INSERT
AS
insert into TBL_TEMP select * from inserted
if ##error != 0
begin
print 'ERROR!!!'
rollback trigger
end
I've checked this trigger with different cases and I can't understand when if ##error != 0 will be treated.
If there are some errors in INSERT, the trigger just fails with error and rolled back. And trigger execution will be aborted on the statement which raised error
Can someone explain me for what purposes if ##error != 0 is used in triggers and when it can trigger?

I've used for testing Sybase Central v.6.0
And it does't show any PRINT results if error occurs
When I've used QTODBC tool for connecting to Sybase ASE server, it threw me exception and printed 'ERROR!!!' message
So, this is the feature of Sybase Central environment
Actually, trigger resumes working when any error occurred

Related

How to handle a transaction in Sybase ASE?

I have to insert records into a table in a test environment, so that I now know that it will throw a primary key constraint violation. And because of the scripts that will be run independantly by other people once the time to migrate from an environment to another, I wish to make my script rollback whenever it encounters a problem.
My script is as follows:
use my_db
go
--
-- No rows of the given "my_code" must exist, as they shall be replaced.
--
if exists (
select 1
from my_table
where my_code like 'my_code'
) delete from my_table
where my_code like 'my_code'
--
-- All rows shall be inserted altogether, or rejected altogether at once.
--
begin tran a
insert into my_table (field1, field2, field3) values (value1, value2, value3)
if ##error != 0 or ##transtate != 0
begin
rollback tran a
end
insert into my_table (field1, field2, field3) values (value1, value2, value3)
if ##error != 0 or ##transtate != 0
begin
rollback tran a
end
commit tran a
go
I have tried what I could get from these posts:
Error Handling in Sybase
How to continue executing rest of while loop even if an exception occurs in sybase?
Transaction Handling in Sybase
I have tried with only verifying ##error, ##transtate and both, and I always get the message box reporting the error, and no records are rolled back, that is, the passing rows are still inserted.
I wonder whether there is a way to make sure that Sybase handles the transactions adequately as expected, or else, simply make sure it doesn't autocommit rows when they are inserted as SQL Server allows it - I mean, SQL Server inherit from Sybase, after all... So was it into Sybase, or is it new to SQL Server, I don't know.
I wish to avoid having the error and more preferably log the error and rollback or delete the inserted rows insde the transaction.
Notice that I don't use a stored procedure. This script is a one-timer to update the database for recent changes occured in the software that uses the database.
The code looks mostly correct. If you hit a duplicate-key error upon the insert, then this will be caught by the IF-test.
However, you should also add some logic (GOTO or additional IF-ELSE tests based on a flag) that skips the second insert when you have decided to roll back the first insert.
Currently your code will always execute the second insert, regardless. Unlike some other databases, in ASE control flow is not affected by an error condition and you need to intercept this yourself.
Also note that both inserts are identical, so if there is unique index on the table the second insert will always generate dup-key error if the first insert was successful.
It sounds as if you are using a client that checks the status after every statement or something? ASE itself does not pop up any error message boxes.
To develop this, it is best to run the script from the command line with
isql [...] -i yourscriptfile.sql
Just two remarks:
You are using a transaction name ('a'). This is not necessary and can in fact cause problems: when you roll back to a named transaction, as you do, that must be the outermost transaction or the rollback will fail. Best don't use transaction names.
This problem in the previous bullet can in fact occur if there is already a transaction active when you execute this code. You should always check this at the start of your script with
if ##trancount > 0
begin
print 'Error: transaction already active'
return
end
or something similar.
HTH,
Rob V.

SQL automatically throw if a statement fails?

Is there any way to have a stored procedure automatically throw if any statement fails due to an error?
I'm inside a stored proc with a merge statement which can fail due to a primary key violation, however execution still continues.
Do I have to resort to if ##error != 0 throw ... everywhere?
EDIT: I'm using MS SQL Server 2012
EDIT: This seems to work, but is there a less verbose solution? It seems as if the introduction of try/catch makes flow jump to the catch block when an error is encountered. From there I just rethrow the exception.
begin try
....do lots of sql code
end try
begin catch
throw;
end catch
Use SET xact_abort ON at the beginning of the statement. It will cause an automatic rollback if any particular statement fails.
See What is the benefit of using "SET XACT_ABORT ON" in a stored procedure?.
Edit: the above is for SQL-Server.
How about wrapping it in a transaction so that if anything fails it will roll back any changes and you can have it return an error message.
Something like
BEGIN Transaction
--Do some code
if ##error > 0
BEGIN
--Do your throw here and then
ROLLBACK TRANSACTION
END
ELSE
BEGIN
COMMIT TRANSACTION
END

How to Ignoring errors in Trigger and Perform respective operation in MS SQL Server

I have created AFTER INSERT TRIGGER
Now if any case if an error occurs while executing Trigger. It should not effect Insert Operation on Triggered table.
In One word if any ERROR occurs in trigger it should Ignore it.
As I have used
BEGIN TRY
END TRY
BEGIN CATCH
END CATCH
But it give following error message and Rolled back Insert operation on Triggered table
An error was raised during trigger execution. The batch has been
aborted and the user transaction, if any, has been rolled back.
Interesting problem. By default, triggers are designed that if they fail, they rollback the command that fired it. So whenever trigger is executing there is an active transaction, whatever there was an explicit BEGIN TRANSACTION or not on the outside. And also BEGIN/TRY inside trigger will not work. Your best practice would be not to write any code in trigger that could possibly fail - unless it is desired to also fail the firing statement.
In this situation, to suppress this behavior, there are some workarounds.
Option A (the ugly way):
Since transaction is active at the beginning of trigger, you can just COMMIT it and continue with your trigger commands:
CREATE TRIGGER tgTest1 ON Test1 AFTER INSERT
AS
BEGIN
COMMIT;
... do whatever trigger does
END;
Note that if there is an error in trigger code this will still produce the error message, but data in Test1 table are safely inserted.
Option B (also ugly):
You can move your code from trigger to stored procedure. Then call that stored procedure from Wrapper SP that implements BEGIN/TRY and at the end - call Wrapper SP from trigger. This might be a bit tricky to move data from INSERTED table around if needed in the logic (which is in SP now) - probably using some temp tables.
SQLFiddle DEMO
You cannot, and any attempt to solve it is snake oil. No amount of TRY/CATCH or ##ERROR check will work around the fundamental issue.
If you want to use the tightly coupling of a trigger then you must buy into the lower availability induced by the coupling.
If you want to preserve the availability (ie. have the INSERT succeed) then you must give up coupling (remove the trigger). You must do all the processing you were planning to do in the trigger in a separate transaction that starts after your INSERT committed. A SQL Agent job that polls the table for newly inserted rows, an Service Broker launched procedure or even an application layer step are all going to fit the bill.
The accepted answer's option A gave me the following error: "The transaction ended in the trigger. The batch has been aborted.". I circumvented the problem by using the SQL below.
CREATE TRIGGER tgTest1 ON Test1 AFTER INSERT
AS
BEGIN
SET XACT_ABORT OFF
BEGIN TRY
SELECT [Column1] INTO #TableInserted FROM [inserted]
EXECUTE sp_executesql N'INSERT INTO [Table]([Column1]) SELECT [Column1] FROM #TableInserted'
END TRY
BEGIN CATCH
END CATCH
SET XACT_ABORT ON
END

Execute Statements in a Transaction - Sql Server 2005

i need to update a database where some of the table have changed (columns have been added). I want to perform this action in a proper transaction. If the code executes without any problem then i will commit the changes otherwise i will rollback the database back to its original state.
I want to do something like this:
BEGIN TRANSACTION
...Execute some sql statements here
COMMIT TRANSACTION (When every thing goes well)
ROLLBACK TRANSACTION (When something goes wrong)
Please tell me what is the best way to do this i know there is a ##TranCount variable but dont know its exact purpose.
Thanks.
Begin Transaction
Alter Table dbo.MyTable
Add Col1 varchar(50)
If ##Error = 0
Begin
Commit Transaction
End
Else
Begin
Rollback Transaction
End
##Error gets reset after each SQL Statement so you must check it immediately after each statement has been executed to check for any errors.

Raising errors in After Triggers Sql Server 2005

If I raise an error in an AFTER UPDATE trigger in Sql Server 2005, will that cause the update which caused the trigger to be fired to roll back, even if the statement was not executed within a transaction?
Thanks.
No, you have to rollback transaction by calling ROLLBACK TRAN:
CREATE TRIGGER trg_au_table
ON dbo.table
AFTER UPDATE
AS
BEGIN
ROLLBACK TRAN
END
GO
This example will prevent from updating any record.
This:
CREATE TRIGGER trg_au_table
ON dbo.table
AFTER UPDATE
AS
BEGIN
RAISERROR('This is a test', 16, 1)
END
GO
will only raise the error but the change will be made in the table.