Raise a Particular Error in t-SQL with RAISERROR - sql-server-2005

I have a view that has an INSTEAD OF INSERT trigger (in SQL Server 2005). When the user inserts into the view, they are in fact making inserts and updates to a number of tables. The view is sufficiently complex that it cannot have an index, so is unfortunately unconstrained.
The view is being inserted into from C# using code that would be problematic to change. This code catches primary and unique key violations using the following:
try
{
... // Insert into view
}
catch (SqlException ex)
{
if (ex.Number == 2627 || ex.Number == 2601) // Primary key exception, unique constraint violation
{
... // Report the duplicate entry to the user
}
else
{
throw;
}
}
So my question is: can I use RAISERROR within my trigger to create an exception with number 2627 or 2601?

No. You'll have to wait for THROW in the next release (maybe)
You can only throw errors that you have put into sys.messages (50000+), or with text that gives 50000. Or embed it in the text and change your c#. You can't throw errors less than 50000
If the view is so complex that you can't use DRI, then it is too complex. Also, you'll have concurrency issues: overlapping calls will break your "uniqueness" at some point when you roll your own.

I'm not sure if you can actually RAISE a genuine primary key violation. Though you can RAISE your own error with your own message and then catch that. This will also allow you to distinguish between a genuine primary key violation and your own custom violations.
Perhaps the crudest way to accomplish this would be...
SQL Code (in TRIGGER definition maybe)...
RAISERROR('Custom View Violation',16,1);
C#...
try
{
//execute SP / Insert etc...
}
catch (SqlException ex)
{
if (ex.Message.Split('\r')[0] == "Custom View Violation")
{
//deal with your exception
}
}

Related

java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist error message in netbeans 8.0.1

when i was trying to delete all records form Oracle database using the following code i got this exception,
QUERYY:: delete from DMUSER.CAMERA_DATA1
java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
Actually here I wanted to create a data mining application using oracle SQL developer and the netbeans IDE. So my workflow is looks like as follow in oracle SQL developer,
The code part that I have used to delete a record from database as follows,
public void deleteData()throws SQLException {
Statement stmt = null;
String query = "delete from DMUSER.CAMERA_DATA1";
System.out.println("QUERYY:: " + query);
try {
stmt = getConnection().createStatement();
int rs = stmt.executeUpdate(query);
if (rs > 0) {
System.out.println("<-------------------Record Deleted--------------->");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (stmt != null) {
stmt.close();
}
}
}
I'm very new to the environment and searched many related questions even in stack but couldn't find exact answer which makes my work successful. Please help me to solve this.
QUERYY:: delete from DMUSER.CAMERA_DATA1
java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not
exist
You need to check, if CAMERA_DATA1 table/view exists in DMUSER schema or not.
Try connecting to same database and schema and check, if table exist or not. If not, then you need to create this table/view in same schema.
Referring to your screenshot provided, I can see CAMERA_DATA table instead of CAMERA_DATA1. So, you can either correct the SQL query to below
String query = "delete from DMUSER.CAMERA_DATA";

Display string from raise_application_error in java program

I am raising some application errors from PL/SQL procedures. I am setting some messages for instance,
RAISE_APPLICATION_ERROR(-20001, 'message');
Is there any way, I can display 'message' in exception section in catch block of java program from which I called this procedure?
If you're doing catch (Exception e), message should be available from e.getMessage().
If you're doing catch (SQLException e) (or whatever the exception type is for your data access package) message should still be available from e.getMessage(). Additionally, the -20001 should come through in e.getErrorCode(). Note that it may come through as the absolute value (20001 as opposed to -20001); you'll have to experiment.
I think this post will help you out: Error catching
catch (GenericJdbcException ge) {
IF (se.getErrorCode() == -20001)
If your not using Hibernate you might need to change the error type.

How to catch error while inserting data with SqlDataSource

I have a SqlDataSource and a GridView.
What I want to do is, while the query is executed (i.e. for inserting a data), then after the data has inserted successfully, it should appear a message sounds: "The data deleted successfully". I've solved it by using GridView1_RowDeleted method.
Now the problem is, I want to catch the error while the query is failed to executed. If the query has failed to execute, then it should appear a message: "The data failed to insert.".
How to do it? I don't have an idea about this.
Need your help guys.
Thanks a lot.
You should be able to add a handler for the relevant event: inserted, deleted. Then, in the handler look at the SqlDataSourceStatusEventArgs property Exception. If it's not null then an
exception has occurred. For example if the selected command threw an
exception:
protected void SqlDataSource1_Selected(object sender, SqlDataSourceStatusEventArgs e)
{
if (e.Exception != null)
{
// handle the exception
}
}
--

Unique Key Violation in SQL Server - Is it safe to assume Error 2627?

I need to catch violation of UNIQUE constraints in a special way by a C# application I am developing. Is it safe to assume that Error 2627 will always correspond to a violation of this kind, so that I can use
if (ThisSqlException.Number == 2627)
{
// Handle unique constraint violation.
}
else
{
// Handle the remaing errors.
}
?
2627 is unique constraint (includes primary key), 2601 is unique index
SELECT * FROM sys.messages
WHERE text like '%duplicate%' and text like '%key%' and language_id = 1033
Here is a handy extension method I wrote to find these:
public static bool IsUniqueKeyViolation(this SqlException ex)
{
return ex.Errors.Cast<SqlError>().Any(e => e.Class == 14 && (e.Number == 2601 || e.Number == 2627 ));
}
Within an approximation, yes.
If you search the MS error and events site for SQL Server, error 2627, you should hopefully reach this page1, which indicates that the message will always concern a duplicate key violation (note which parts are parameterized, and which not):
Violation of %ls constraint '%.*ls'. Cannot insert duplicate key in object '%.*ls'.
1As #2020-06-18, Database engine errors and events would be the correct page to go to

Flush NHibernate whilst still allowing transaction rollback

I am trying to use NHibernate with legacy entities that are not mapped with NHibernate. On occasion this means that I need to manually flush NHibernate data to the database so that I don't receive foreign key exceptions when I try to connect the legacy entities with NHibernate-mapped entities.
A problem occurs when this takes place within a transaction that then needs to be rolled back. The data flushed from NHibernate does not rollback.
Is there anything I can do about this?
UPDATE
Still curious how to do this - I don't believe either of the answers given address the issue. I need to call Flush(). The question is, how do I rollback data that has been flushed?
check this: Force query execution without flush/commit
I seemed to have the same problem, i would flush and then i would rollback but some data would remain persisted in the database. However, there were some parts in my code that would call a commit, which cannot be rolled back. Consider the accepted answers' code snippet as the proper usage for transactions, flushes, rollbacks and commits and take into consideration that this pattern can be extended...
in a single unit of work (ie we consider a Request in a web application as a single unit of work and everything that happens in that request exists in a single transaction which onEndRequest is committed):
you call _sessionFactory.OpenSession(), _session.BeginTransaction(), _session.CommitTransaction() and _session.CloseSession() only once.
you can call _session.Flush() and _session.RollBackTransaction() as many times as you want, but Flush() is automatically called on Commit automatically. You may want to call a Flush when you need to make a query and ensure that the data fetched will not be stale.
Note that once a commit transaction is committed, all operations afterwards do not happen on that transaction. Instead NHibernate will create the necessary transaction under the hood (http://www.nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions) in which point
you already have problems tracking consistency and possibly logical integrity
If you really must call commit in the middle of your unit of work it is strongly advised to create a new transaction at that point so you can manage it explicitly
What's even better is to try out Nested Transactions will allegedly allow partial commits; you can rollback the "root" transaction and all changes will be reverted. I haven't really tested this feature of .NET and SQL Server, although the nested transaction in the database itself leaves a lot to be desired and i don't know how exactly ADO.NET instruments this feature.
points 1 to 4 have been tested with all versions of NHibernate starting from 1.2.
For the sake of formatting I allow myself to update tolism7's answer here.
use using and forget about transaction.Dispose() - the transaction will automatically be Dispose'd of at the end of the using block.
throw - don't throw ex because it means throwing away your stacktrace (see this post where it states "When the .NET Framework executes this statement: throw ex; it throws away all the stack information above the current function.")
.
public void CommitChanges()
{
using (var transaction = Session.BeginTransaction()) // <-- open scope
try
{
// do something
transaction.Commit();
}
catch (HibernateException)
{
transaction.Rollback();
_session.Close();
_session.Dispose();
throw; // <-- this way the stacktrace stays intact!
}
}
A VB.NET version of this piece of code can be found here.
When using transactions with NHibernate try to avoid using the Session.Flush() and instead use the transaction.Commit() which it calls the session.flush() internally.
If during the Commit() an error occurs and the transaction needs to be rolled back this can be addressed like this.
public static void CommitChanges()
{
ITransaction transaction = Session.BeginTransaction();
try
{
transaction.Commit();
}
catch (HibernateException ex)
{
transaction.Rollback();
//close and dispose session here
throw ex;
}
finally
{
transaction.Dispose();
}
}
Now, if a manual call to flush() or a call to commit() goes through successfully there isn't a way to roll back the transaction using NHibernate mechanisms.
Especially when calling the transaction.Commit() command the AdoTransaction created by NHibernate is then disposed right after the Commit() finishes so you cannot access it in order to roll back.
The code sample above allows you to catch errors that happen during commit and then roll back the transaction that has started already.
Now instead of calling the transaction.Commit() in the sample above you call the session.Flush() in my tests no data are saved in the Database as the transaction is never commited.
I have no idea how your code looks like but if you are calling in a pattern, as the above the code sample shows, the transaction.commit() instead of the Session.Flush() it should give you a way to achieve what you want.