Is it possible anyhow to raise system exception on catching exception manually? - sql

I am writing a stored procedure where i m using try catch block.
Now i have a unique column in a table. When i try to insert duplicate value it throws exception with exception no 2627.
I want this to be done like this
if (exists(select * from tblABC where col1='value')=true)
raiseError(2627)--raise system error that would have thrown if i would have used insert query to insert duplicate value
EDIT:
I m using transaction which gets rollback on handling exception hence leading to increment of ##Identity value that got executed in previous queries b4 the exception occurred.
I want to check all such exception that could occur b4 actually inserting. For doing this, i would be checking for exception that could raise error manually using select statement with if else. Here i will be able to catch unique key violation but exception will not be occurred so i will be throwing exception deliberately here but that exception i want should be a system exception i.e error 2627
And which method will be better, using
insert query or checking for duplicate
value before insertion using Select
query ?
IS IT POSSIBLE ANYHOW TO RAISE SYSTEM
EXCEPTION ON CATCHING EXCEPTION
MANUALLY i.e THROWING SAME EXCEPTION THAT SQL WOULD HAVE THROWN

You can't raise system errors. RAISERROR(2627...) is illegal. Beside the fact that you're lying (no error 2627 occurred), you're missing the inserts into the message format.
Application should never rely on IDENTITY continuity, the fact that you complain that it 'increases the autoincrement' revels your application has a bug (in design for sure, if not in code). IDENTITY values may contain gaps, is part of their specifications.
As to what is better, to insert and catch, or to try to update: it depends on your prevalent pattern. If the value is likely to exist, the UPDATE first strategy is better. If the value is likely not to exist or if the probability is unknown it is better to INSERT and catch the error, for reasons of performance and, more importantly, correctness (SELECT check is never correct under concurrency).

Related

Is it a good thing to Raise Exceptions intentionally in PostgreSQL?

I am developing a PL function in Postgres, and in it I am modifying records of a table, according to some logic, then I execute a final query (basically counting), and if the number I get is positive, I throw an exception to rollback the transaction (since PostgreSQL's function doesn't support transactions explicitly).
So is this a good method to emulate transactions? Do you have better suggestions ?
PS: I am using PostgreSQL 9.2 but I am migrating to 9.3 soon, if this may help somehow.
If you wish to abort a transaction within a function, then yes, raising an exception is a good choice.
You can use subtransactions within PL/PgSQL functions by using BEGIN ... EXCEPTION blocks within the function. Use an inner BEGIN ... EXCEPTION block and within it RAISE an exception with a user defined SQLSTATE. Catch the exception in the EXCEPTION block.
A RAISE (of ERROR or higher) within a BEGIN ... EXCEPTION block will roll back work done within that block, as if you had used a SAVEPOINT and ROLLBACK TO SAVEPOINT.
Functions cannot force a rollback of the top level transaction; if you RAISE an exception, an outer pl/pgsql function can catch the exception in a BEGIN ... EXCEPTION block, or the client can use a ROLLBACK TO SAVEPOINT.
I have used this solution in the past. At issue is that the PLPGSQL language does not support the use of SAVEPOINT and ROLLBACK. Transactions wrap functions, not the other way around.
RAISE is the proper methodology to notify the client of some internal condition within a function. There are several levels of RAISE, the "worst" is EXCEPTION which will abort/rollback your transactions UNLESS something catches the exception and suppresses it.
For testing, use
`RAISE DEBUG 'some comment %', var;`
If you want to put something in your logs, but don't want to rollback, you can (typically) raise a WARNING. (Any level of RAISE can go to your logs, it depends on your configuration)

Rolled back but an error persists

Semantics:
I am using PostGreSql 9.0.3 as my Dbms. Actually i was tried to accomplish one of the objectives assigned for me, which is to Raise Exception with some predefined message when some conditions failed in a IF - Statement inside my stored procedure. As a result of that exception, The Process should needs to be rolled back.
Syntax:
For r3 in select itemname,stock from stock s,items it where s.itemno=it.itemno and it.itemno=$2[I].itemno and s.stockpointno=$1.stockpointno loop
if xStock > r3.stock then
RAISE EXCEPTION '%', r3.itemname || ' decreased down from the low stock level';
end if;
End Loop;
where r3 is a record and xStock is a Double Precision Variable.
Then At the end of the stored procedure i just included the following code in order to roll
back the transactions happened.
Exception when raise_exception then rollback transaction;
The problem i am facing is when ever the manual exception getting raised, The following error bumps up.
DA00014:ERROR: XX000: SPI_execute_plan_with_paramlist failed executing query "rollback transaction": SPI_ERROR_TRANSACTION
Though the above error occured, transactions are not happened while i was checking in the tables. I don't know the exact reason why this particular error is raising when rolling back is in progress. Can anybody tell what may be the possible mistake which i was made in my code? And also suggest solutions to fix this issue.
While some database engines allow COMMIT or ROLLBACK inside a function or procedure, PostgreSQL does not. Any attempt to do that leads to an error:
ERROR: cannot begin/end transactions in PL/pgSQL
That includes code inside an exception block.
On the other hand, a RAISE EXCEPTION alone will abort the transaction with the function-supplied error message, so there's no need to trap your own exception. It would work as expected if you just removed your exception block.
As said by the plpgsql documentation in Trapping Errors:
By default, any error occurring in a PL/pgSQL function aborts
execution of the function, and indeed of the surrounding transaction
as well
You current code raises the exception, then traps it and fails in the exception block itself because of the forbidden ROLLBACK statement, which leads to the SQL engine aborting the transaction.

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.

Can a SQL INSERT fail without raising an exception in PL/SQL

Are there any cases where an INSERT in SQL (specifically Oracle-PL/SQL) can fail without an exception being thrown? I'm seeing checks in code after INSERT where it verifies that SQL%ROWCOUNT = 1 ELSE it raises its own user-defined exception. I don't see how that can ever happen.
It can't fail without an exception, no. Probably the developer who wrote the code didn't know that.
An after statement trigger could conceivably delete the row just inserted. And of course an INSERT...SELECT might find no rows to insert, and so would result in SQL%ROWCOUNT = 0.
In addition to the trigger-based issue #mcabral mentioned, you could have an insert that is successful but inserts other than 1 row. For example, the insert into blah(col1) select col2 from foo style of insert.
As #TonyAndrews and #GinoA mentioned, there are several ways an INSERT could return something other than exactly one row (triggers, INSERT INTO tablename SELECT... syntax).
But the bigger issue is that you're in PL/SQL. As such, the SQL%ROWCOUNT value can be used as a condition to determine the program execution flow including issuing COMMIT or ROLLBACK statements.
Even with just raising a user-defined exception, the calling PL/SQL block can handle the exception itself.
EDIT: Someone should modify the question title to indicate PL/SQL (as indicated in the question itself), since that's not the same thing as SQL scope the title suggests.

Entity Framework: How to properly handle exceptions that occur due to SQL constraints

I use Entity Framework to access my SQL data. I have some constraints in the database schema and I wonder how to handle exceptions that are caused by these constraints.
As example, I get the following exception in a case where two users try to add an (almost) identical entity to the DB concurrently.
System.Data.UpdateException
"An error occurred while updating the entries. See the InnerException for details."
(inner exception) System.Data.SqlClient.SqlException
"Violation of UNIQUE KEY constraint 'Unique_GiftId'. Cannot insert duplicate key in object 'dbo.Donations'.\r\nThe statement has been terminated."
How do I properly catch this specific exception?
Dirty solution:
catch (UpdateException ex)
{
SqlException innerException = ex.InnerException as SqlException;
if (innerException != null && innerException.Message.StartsWith("Violation of UNIQUE KEY constraint 'Unique_GiftId'"))
{
// handle exception here..
}
else
{
throw;
}
}
Now while this approach works, it has some downsides:
No type safety: The code depends on the exception message which contains the name of the unique column.
Dependency on the SqlCLient classes (broken abstraction)
Do you know a better solution for this?
Thanks for all feedback..
Note: I do not want to code the constraints manually within the application layer, I want to have them in the DB.
You should be able to trap the SQL error number (which is SqlException.Number)
In this case it's 2627 which has been the same forever for SQL Server.
If you want abstraction, then you'll always have some dependency on the database engine because each one will throw different exception numbers and messages.
One way is to inspect the Errors property of the inner SqlException. The SqlError class has a Number property that identifies the exact error. See the master.dbo.sysmessages table for a list of all error codes.
Of course this still ties you to Sql Server. I'm not aware of a way to abstract this away other than roll your own 'EF exception analyzer'.
This scenario should not happen as the key should never be assign explicitly when using EF; rather allowing the context to assign an appropriate one. If its a concurrency issue then you should do the update in a transaction scope.
Then if you have an UpdateException you could retry the update again. You can safely do that in a transaction scope and only complete the scope when the update goes thorough. In this scenario the chances of the update going through the next time is greater than the first one.