When exactly is an AFTER DELETE trigger fired - sql

I hope that you can help me on some SQL theory, as I am not 100% sure how this works.
If I have a trigger and I define it as
AFTER DELETE ON xxxx
I was wondering when exactly this would fire, in terms of transaction management?
So if I delete a record from my table I assume that the trigger will not fire until I type commit and finish the transaction. Is this correct?
If so, then I assume that if the commit on my delete statement works but the trigger fails for some reason then only the trigger would be rolled back, and the original executed delete statement that I performed would still be committed (because I have it defined as AFTER DELETE).
Can somebody please confirm this?
Thanks.

1. You delete a row on TABLE1 no COMMIT;
2. TRIGGER performs an action (This takes place before COMMIT or ROLLBACK for step1, but trigger will not have any commit or rollback in it)
3a. You apply commit - Both step1 and step2 gets completed .
3b. You apply rollback- Both step1 and step2 rolled back.
Either you give 3a or 3b

The purpose of SQL triggers is to ensure referential consistency. But when they would be exectued in a separate transaction commit, there would be the possibility that they leave data in an inconsistent state.
So the delete trigger is executed the moment you do the delete command. When this happens as a transaction and you roll it back, the triggered delete is also rolled back.

An AFTER DELETE trigger is fired after the delete statement is executed, and before the control is returned to the user - i.e., he perceives the delete statement and the code executed after it in a trigger as a single action (assuming the trigger just does DMLs and nothing funky like calling UTL_TCP :-)).
This has nothing to do with transaction management - once the DELETE and the AFTER DELETE trigger execute, you can choose to commit, to rollback, or to continue performing DML statements in the same transaction.

Related

If the table has more than one FOR INSERT trigger and one of them writes to an audit table and the other does a rollback is the audit rolled back

Let's say a table has a validation trigger that enforces some business logic:
TRG_MYTABLE_INSERT_UPDATE_VALIDATION
FOR INSERT, UPDATE on MYTABLE
and an audit trigger that writes all inserts and updates to another table.
TRG_MYTABLE_INSERT_UPDATE_AUDIT
FOR INSERT, UPDATE on MYTABLE
and there's no guarantee that they will be executed in a particular order, will a rollback in the VALIDATION trigger rollback the write to the audit table?
Are all of the triggers enlisted in the same transaction "behind the scenes"?
To answer the question about triggers and transactions: yes triggers are enlisted in the same explicit, or implicit, transaction as the code that executes the statement which makes the trigger fire is enlisted in.
Furthermore, in SQL Server triggers runs be default under XACT_ABORT ON which means that if an error happens in the trigger, the WHOLE transaction is rolled back immediately.
So the answer to your question is that if an error happens in either of the triggers, the whole transaction is rolled back.
You can however do a SET XACT_ABORT OFF in your transaction code, in which case, a rollback would only impact whatever you do in the trigger. That is UNLESS your calling code starts a transaction, and you explicitly do a ROLLBACK in your trigger.
The above is why you should be very careful with using triggers in the first place.

How to undo a ROLLBACK in sql?

I am learning Oracle SQL, and after a DELETE command I tried to do a ROLLBACK. The problem is that I pressed by mistake F9 a second time and the ROLLBACK ran once again. Now it has deleted all my INSERTs from the table and I don't know how can I get them back.
I tried to insert again the same queries, but there was a problem with the PK (primary key). Also, I can't delete the table to start all over again because I have other tables using FK (foreign keys) in conjunction with this one.
Unfortunately, you cannot undo a ROLLBACK, just like you cannot undo a COMMIT. This is by design.
What happens when you do ROLLBACK is that all un-commited changes until that point are lost. Calling ROLLBACK twice has no effect if you do not perform any changes between the two invocations.
So the question is : did you COMMIT your INSERTs before running your DELETE ?
if yes : the ROLLBACK just reverted the DELETE command, your INSERTs should not be lost
if no : the ROLLBACK reverted also the INSERTs
In both scenarios it does not matter whether your called ROLLBACK once or twice.
You can't undo a rollback. Rollback isn't an "undo" so it has no "redo". It's "throw these changes away, I don't want them"
I would suggest you start a second question where you explain what you meant by: "there was a problem with the PK (primary key)." and ask for help with that.
There's no way back, the only way is forward.

Where is the flaw in my trigger to override DELETE with a soft-delete?

I have a trigger created with
CREATE TRIGGER [CantDeleteStuff] ON [dbo].[Stuff]
INSTEAD OF DELETE
AS
BEGIN
ROLLBACK
UPDATE [dbo].[Stuff] SET [Deleted]=1 FROM DELETED WHERE [dbo].[Stuff].[Id] = DELETED.[Id]
END
GO
and I think it's intent is clear. But when I try to delete a row I get the error
The transaction ended in the trigger. The batch has been aborted.
How to fix?
Instead of Delete will replace the Delete with your triggering code.
According to Technet, the Rollback in your trigger is the issue. You can read more here.
A trigger operates as if there were an outstanding transaction in effect when the trigger is executed. This is true whether the statement firing the trigger is in an implicit or explicit transaction.
When a statement begins executing in autocommit mode, there is an implied BEGIN TRANSACTION to allow the recovery of all modifications generated by the statement if it encounters an error. This implied transaction has no effect on the other statements in the batch because it is either committed or rolled back when the statement completes. This implied transaction is still in effect, however, when a trigger is called.
When a trigger executes, an implicit transaction is started. If the trigger completes execution and ##TRANCOUNT = 0, error 3609 occurs and the batch is terminated. If a BEGIN TRANSACTION statement is issued in a trigger, it creates a nested transaction. In this situation, when a COMMIT TRANSACTION statement is executed, the statement will apply only to the nested transaction.
When using ROLLBACK TRANSACTION in a trigger, be aware of the following behavior:
All data modifications made to that point in the current transaction are rolled back, including any that were made by the trigger.
The trigger continues executing any remaining statements after the ROLLBACK statement. If any of these statements modify data, the modifications are not rolled back.
A ROLLBACK in a trigger closes and deallocates all cursors that were declared and opened in the batch containing the statement that fired the trigger. This includes cursors declared and opened in stored procedures called by the batch that fired the trigger. Cursors declared in a batch prior to the batch that fired the trigger are only closed. However, STATIC or INSENSITIVE cursors are left open if:
CURSOR_CLOSE_ON_COMMIT is set OFF.
The static cursor is either synchronous or a fully populated asynchronous cursor.
Instead of using ROLLBACK TRANSACTION, the SAVE TRANSACTION statement can be used to execute a partial rollback in a trigger.
https://technet.microsoft.com/en-us/library/ms187844(v=sql.105).aspx
So just remove the Rollback.

What happens when database shut down before triggers executed?

Assume I have table in PostgreSQL as follows:
CREATE TABLE A
(
userid integer,
productid integer,
description citext,
price numeric
)
and some triggers on it:
CREATE TRIGGER afterinsert
AFTER INSERT
ON A
FOR EACH ROW
EXECUTE PROCEDURE DoSomething1();
CREATE TRIGGER beforeinsert
BEFORE INSERT
ON A
FOR EACH ROW
EXECUTE PROCEDURE DoSomething2();
Now, if I do this:
Insert into A values (1,3,'some description',100.5)
What will happen is:
beforeinsert run DoSomething2()
the row is inserted to A
afterinsert run DoSomething1()
My question is what happens if between 2 and 3 the database shuts down?
when it starts again... what will hapen? will it roll back both the inserted row and roll back beforeinsert trigger?
Basically I just don't understand what is considered the Atomic operation in this case. is it the Insert + triggers or just the row?
The triggers are part of the transaction, and it won't commit until they've finished running. If the database shuts down before the transaction commits, it'll be rolled back. The rollback affects all changes that were made in the transaction, including the changes made by the triggers.
If you do a soft shutdown (that is, tell the database to shutdown: pg_ctl -m fast), it will rollback all open transactions. This includes all changes made by any trigger so far.
If you kill the database (like a kill -9), the database has no chance to properly commit or rollback everything. Next time you start the database, it will run a recovery and rollback all the changes to the point of the last successful commit.
All triggers are part of the ongoing transactions, all changes are only committed once all AFTER triggers finish.

Do queries executed in a Postgres trigger procedure run in the same transaction?

I have a BEFORE DELETE trigger which inserts rows into another table using SPI_exec.
Do these INSERT queries run in the same transaction as the one in which the original delete is executing? Hence, will the delete and all inserts roll back or commit together?
If not, how can I make that happen?
Yes, everything in triggers is in the same transaction as the triggering event.
Not directly related to the question, but normally you want to put side-effects in the AFTER trigger, rather than the BEFORE trigger.