What Happens when an Error Occurs?

Many programming languages have a fairly consistent behaviour when there is a run-time error. Common is that the execution simply terminates in case of an error, unless you have set up an exception handler that takes care the error. In other languages, some error variable is set and you have to check this variable. T-SQL is confusing, because depending on what error that occurs and in which context it occurs, SQL Server can take no less than four different actions. I first give an overview of these alternatives, followed by a more detailed discussion of which errors that cause which actions. I then discuss two special cases: trigger context and user-defined functions.
The Possible Actions

These are the four main possible actions SQL Server can take:

Statement-termination. The current statement is aborted and rolled back. Execution continues on the next statement. Any open transaction is not rolled back. @@error is set to the number of the error. Since the statement is rolled back, this means that if you run an UPDATE statement that affects 1000 rows, and for one row a CHECK constraint is violated, none of the rows will be updated. But if the UPDATE statement was part of a longer transaction, the effect of the preceding INSERT, UPDATE or DELETE statements are not affected. You need to issue a ROLLBACK TRANSACTION yourself to undo them.

Scope-abortion. The current scope (stored procedure, user-defined function, or block of loose SQL statements, including dynamic SQL) is aborted, and execution continues on the next statement in the calling scope. That is, if stored procedure A calls B and B runs into a scope-aborting error, execution continues in A, just after the call to B. @@error is set, but the aborted procedure does not have a return value, but the variable to receive the return value is unaffected. As for statement-termination, any outstanding transaction is not affected, not even if it was started by the aborted procedure.

Batch-abortion. The execution of the entire batch – that is, the block of SQL statements that the client submitted to SQL Server – is aborted. Any open transaction is rolled back. @@error is still set, so if you would retrieve @@error first in the next batch, you would see a non-zero value. There is no way you can intercept batch-abortion in T-SQL code. (Almost. We will look a possibility using linked servers later on.)

Connection-termination. The client is disconnected and any open transaction is rolled back. In this case there is no @@error to access.

One can note from this, that there are two things that cannot happen:

    The transaction is rolled back, but execution of the current batch continues.
    The batch is aborted, but the transaction is not rolled back.

But I like to stress that this is based on my own observations. I have found no documentation that actually states that these two cases cannot occur under any circumstances.

The above caters for most of the error situations in SQL Server, but since a hallmark of the error handling in SQL Server is inconsistency, every now and then I discover some new odd situation. I am overlooking these cases here, not to burden the reader with too many nitty-gritty details.

There is however, one more situation you should be aware of and that is batch-cancellation. The client may at any time tell SQL Server to stop executing the batch, and SQL Server will comply more or less immediately. In this situation SQL Server will not roll back any open transaction. (In the general case that is. It seems that if the T-SQL execution is in a trigger, when the cancellation request comes, then there is a rollback.) However, if the current statement when the cancellation request comes in is an UPDATE, INSERT or DELETE statement, then SQL Server will roll back the updates from that particular statement. Batch-cancellation may occur because an explicit call to a cancellation method in the client code, but the most common reason is that a query timeout in the client library expires. ODBC, OLE DB, ADO and ADO.Net all have a default timeout of 30 seconds. (Which judging from the questions on the newsgroups, many programmers believe to come from SQL Server, but not so.)

Comments

Popular posts from this blog

Google to FTS Syntax Cheat Sheet

@@rowcount

Sql Index