TRY/CATCH block vs SQL checks - sql

Shortly, I am wondering which of the following is the better practice:
to encapsulate my code in TRY/CATCH block and display the error message
to write own checks and display custom error messages
As I have read the TRY/CATCH block is not handling all types of errors. In my situation this is not an issue.
I am building dynamic SQL that executes specific store procedure. I can make my own checks like:
is the procedure that is going to be executing exists
are all parameters supplied
can be all values converted properly
or just to encapsulate the statement like this:
BEGIN TRY
EXEC sp_executesql #DynamicSQLStatement
SET #Status = 'OK'
END TRY
BEGIN CATCH
SET #Status = ERROR_MESSAGE()
END CATCH
Is there any difference if I make the checks on my own (for example performance difference) or I should leave this work to the server?
The reason I am asking is because in some languages (like JavaScript) the use of try/catch blocks is known as bad practice.

Typically it is going to be better to check for these things yourself than letting SQL Server catch an exception. Exception handling is not cheap, as I demonstrate in these posts:
Checking for potential constraint violations before entering SQL Server TRY and CATCH logic
Performance impact of different error handling techniques
Depending on the schema, volume, concurrency, and the frequency of failures you expect, your tipping point may be different, so at very high scale this may not always be the absolute most efficient way. But in addition to the fact that in most cases you're better off, writing your own error handling and prevention - while it takes time - allows you to fully understand all of your error conditions.
That all said, you should still have TRY / CATCH as a failsafe, because there can always be exceptions you didn't predict, and having it blow up gracefully is a lot better than throwing shrapnel everywhere.

A try/catch should only be used for critical errors. If there are possible errors that you can prevent by doing a simple if statement, you should do it. Don't rely on try/catch to make sure, for example, that a user entered a date in the correct format. Check that yourself.
Personally, if I get a critical exception like that, I'd prefer to see the call stack and where it happened. So, I only do a try/catch in the topmost layer of my project.

Using Try Catch Block you can still raise Custom Error Messages, Actually if you have Custom error Message then you can only show Custom error message you cannot sql server default error message. and you can also make use of many other error functions as well to get a lot more information about your error, Like
ERROR_LINE()
ERROR_MESSAGE()
ERROR_STATE()
ERROR_NUMBER()
ERROR_STATE(),
These functions can only be used in Catch block of TRY/CATCH block and makes our lifes a lot easier as a developer :)

Related

Where do you put SQL RAISERROR code?

I'm trying to set up a custom error message to pass to MS Access (from SQL Server) when a user enters a duplicate key (instead of system message 2627). I've read up on sp_addmessage and RAISERROR and TRY/CATCH blocks which all make perfect sense. But nowhere I've looked does it seem to say where you put the RAISERROR code (and TRY/CATCH block) so it will actually pass back to the application. So, where does the code go?
Don't think about it in terms of users entering duplicate keys. Instead, think in terms of users just entering keys, some of which turn out to be duplicates when you try to insert them. It's a subtle difference, but it helps you here, because it means you think in terms of having your code available for all new table inserts instead of just a specific type of insert.
When a user enters a key, an INSERT sql statement runs. If the key is a duplicate and you have the constraints defined on the table to the prevent that, the INSERT statement fails. If your Access application has you writing custom SQL, you can wrap this in a TRY/CATCH, and put the RAISERROR in the CATCH block. If your Access application is such that you never see any SQL, you may be stuck, and have to put up with the built-in behavior.

List of possible Exceptions per SQL-Command

I'm looking for a List of all possible exceptions which can occur for each SQL Command.
For example: If I have the following code:
Procedure p1
as
l_cnt number;
Begin
Select count(*)
Into l_cnt
From xyz;
Exceptions
When ... Then
...
End;
Now I'm wondering which exception can occur in this Select Into Statement. I know a few but are they all there is? That's why I'm looking for an overview of possible Exceptions per SQL.
A question on top would be: Is it recommended to catch all possible Exceptions raised by SQL Code inside PLSQL?
I know of "when others" which is the only way for me atm to catch "unknown" exceptions.
Of course if the list of possible exceptions for a SQL is very long I would only handle the relevant exeptions and catch the others by "when others".
To be honesty, your question is pretty common.
For example, you query can lead to the following exceptions:
TIMEOUT_ON_RESOURCE - A time out occurs while the database is waiting for a resource
STORAGE_ERROR - PL/SQL ran out of memory or memory was corrupted
I would suggest to learn predifined exceptions from official documentation and select suitable for each case.

Terminating a job in SQL Server during runtime

Is there a way to make a scheduled job terminate (stop, quit, stop executing, report failure) within a stored procedure in that job?
For example, I have some check queries within a TRY block that do RAISERROR (59834,16,1) to go to the CATCH block to send an email saying that the check queries found a bad situation and the job must stop. The number 59834 was arbitrary but specific.
However, every time I test the job, even though I raised an error, the job continues to execute; it never reports a failure.
I have tried using the same RAISERROR in the CATCH block as I did in the TRY block, but that did not work either.
I want the job to stop in this once instance, it will run every day.
It sounds like the XACT_ABORT setting is not on. Without XACT_ABORT on, the execution will continue regardless of any errors encountered. More information about XACT_ABORT:
Microsoft BOL entry for XACT_ABORT
What is the benefit of using SET XACT_ABORT ON in a stored procedure?
So you might consider a SET XACT_ABORT ON at the start of the job.

How to get inner errors from try/catch clause in SQL Server

I am running a stored procedure in SQL Server 2008 inside a try/catch. The stored procedure and the stored procs it calls raise a few errors but in the try/catch you only get the last error from the stored procedure that you are running.
Is there a way/trick to be able to somehow catch ALL the errors generated by child stored proc calls while running a particular stored procedure? (assume that you have no access to any stored procedures so you can't modify where they can write the error, i.e. you can't just change all the stored procedures to stop raising errors and instead write them to some table and in your catch read from that table)
Here is a good resource for how to deal with error handling in SQL Server.
http://www.sqlservercentral.com/articles/Development/anerrorhandlingtemplatefor2005/2295/
However, some of the methods require that you have the ability to change the code in order to capture the errors. There is really no way of getting around this. You can't just ignore the error, keep processing, and then come around later to deal with the error. In most, if not all, languages, exceptions have to be dealt with at the time the exception was raised. T-SQL is no different.
I personally use a stored procedure to log any error whenever it occurs. Here is what I use:
CREATE PROCEDURE [dbo].[Error_Handler]
#returnMessage bit = 'False'
WITH EXEC AS CALLER
AS
BEGIN
INSERT INTO Errors (Number,Severity,State,[Procedure],Line,[Message])
VALUES (
ERROR_NUMBER(),
ERROR_SEVERITY(),
ERROR_STATE(),
isnull(ERROR_PROCEDURE(),'Ad-Hoc Query'),
isnull(ERROR_LINE(),0),
ERROR_MESSAGE())
IF(#returnMessage = 'True')
BEGIN
select Number,Severity,State,[Procedure],Line,[Message]
from Errors
where ErrorID = scope_identity()
END
END
If you have stored procs that are raising more than one error, they need to be replaced no matter what. You probably have data integrity errors in your database. That is a critical, "everything needs to stop right now until this is fixed" kind of issue. If you can't replace them and they were incorrectly written to allow processing to continue when an error was reached, then I know of no way to find the errors. Errors are not recorded unless you tell them to be recorded. If the stored procs belong to a product you bought from another vendor and that's why you can't change them, your best bet is to change to a vendor that actually understands how to program database code because there is no salvaging a product written that badly.
You wouldn't have a Java or c# methods raising error after error. Why do you expect SQL to allow this? An exception is an exception
If the DB Engine is throwing errors then you have problems.
What I've done before is to separate testing and checking code: find out what is wronf first and throw one exception If no errors, do your writes.

Is it appropriate to raise exceptions in stored procedures that wrap around CRUD operations, when the number of rows affected != 1?

This is a pretty specific question, albeit possibly subjective, but I've been using this pattern very frequently while not seeing others use it very often. Am I missing out on something or being too paranoid?
I wrap all my UPDATE,DELETE,INSERT operations in stored procedures, and only give EXECUTE on my package and SELECT on my tables, to my application. For the UPDATE and DELETE procedures I have an IF statement at the end in which I do the following:
IF SQL%ROWCOUNT <> 1 THEN
RAISE_APPLICATION_ERROR(-20001, 'Invalid number of rows affected: ' || SQL%ROWCOUNT);
END IF;
One could also do this check in the application code, as the number of rows affected is usually available after a SQL statement is executed.
So am I missing something or is this not the safest way to ensure you're updating or deleting exactly what you want to, nothing more, nothing less?
I think this is a fine way to go. If the pl/sql proc is expected to always update/delete/insert a row and it's considered an error otherwise, then what better place to put this check than in the pl/sql proc itself? That way, no matter what client side code (C#, JAVA, PHP, Rails, etc.) uses this proc, you have this error check centralized in one place.
However, I'm not sure you need the check for an insert. If the insert fails, you should get some sort of DB exception, so no need to check for it explicitly unless you are wrapping the error in some other error message and re-raising it.
In most cases I'd use an ORM like Hibernate, which does a similar thing in order to handle Optimistic locking. Also it will use the PK in the where clause.
So I would consider this kind of stored procedure a waste of time:
- A lot of effort for minimal benefit
- Makes usage of tools like ORMs harder, which solve more and more important problems.