I am using JDBC, and am running a query. Is there a way to get the reason it failed from the SQLException object returned?
In particular, I want to know if my query violated a foreign key constraint (and which one), or a key constraint.
Would this result be vendor-specific? Just in case, I am using the postgresql-8.4-701.jdbc4.jar driver. If it is vendor-specific, where would I find the codes?
EDIT: I want to do this dynamically - i.e.
if(violated foreign key constraint on attribute x) {
return 5;
} else if (violated primary key constraint) {
return 7;
} else {
return 0;
}
Or something like that.
EDIT: According to this post, there are no vendor-specific error codes for PostgreSQL JDBC. Dunno if that's still valid.
You can process the error code from the SQLException object.
sqlException.getErrorCode()
This retrieves the vendor-specific exception code for this SQLException object. By using the vendor-specific error code, you can branch to the required block of code.
try printing the stack trace (e is of SQLException type)
e.printStackTrace()
or getting the Message
e.getMessage()
These may give you some explanation of why the query failed
Related
I'm trying to do this at onUpgrade() in my Android Java App:
try {
db.execSQL("SELECT fechacontrol from parametres", null);
} catch(Exception e) {
e.printStackTrace();
db.execSQL("ALTER TABLE parametres ADD COLUMN fechacontrol BIGINT");
}
My problem is, the column fechacontrol exists, but I always end up in the exception block, then the app crashes because of a duplicated column name.
What am I doing wrong?
Thanks you all.
execSQL(anything, null) will throw an IllegalArgumentException due to null bindargs. That's why you always end up in the catch. There is execSQL(String) overload for executing SQL without bindargs.
However, database upgrades should not be done like this. The schema version number is stored in the database file and you get it as a param in onUpgrade(). Use that information to deduce what needs to be updated.
I am building a java project. I want to check if a primary key already exist in my table. For example I have the below code:
private void AddProductActionPerformed(java.awt.event.ActionEvent evt)
{
String query="INSERT INTO Products(Pro_Id ,Pro_Name,Pro_Price,Pro_Quantity,Pro_Supplier_id)VALUES ('"+Pro_Id.getText()+" ','"+Pro_Name.getText()+" ','"+Pro_Price.getText()+" ','"+Pro_Quantity.getText()+" ','"+Pro_Supplier_id.getText()+" ') ";
executeSQLQuery(query,"Inserted");
}
How can I get a message that tells me to change the entry of primary key if it already exists?
You can put your code inside try catch block.
Inside catch block check for SQLException
public static final int MYSQL_DUPLICATE_PK = 1062; // Replace 1062 with exception no. you are getting in case it is different for different database
try{
String query="INSERT INTO Products(Pro_Id ,Pro_Name,Pro_Price,Pro_Quantity,Pro_Supplier_id)VALUES ('"+Pro_Id.getText()+" ','"+Pro_Name.getText()+" ','"+Pro_Price.getText()+" ','"+Pro_Quantity.getText()+" ','"+Pro_Supplier_id.getText()+" ') ";
executeSQLQuery(query,"Inserted");
} catch(SQLException e){
if(e.getErrorCode() == MYSQL_DUPLICATE_PK ){
System.out.println("Primary key already used");
}
}
How can I get a message that tells me to change the entry of primary
key if it already exists?
Make sure you have marked Pro_Id as PRIMARY KEY while defining your table structure which will make sure this behavior and if you try to insert duplicate value it will throw error.
You would get an error if you try your code and the key already exists. Depending on this error for your program to work during a normal flow is not a good idea, as exceptions are always expensive in terms of performance. What you should do is check if the primary key exists already before trying to insert. This can be done by executing a SELECT query.
SELECT 1 FROM Products WHERE Pro_Id = :yourDesiredPk;
When the result of the query is not empty it would mean that it already exists.
A better idea is to consider using a sequence and using the next value aka auto increment, check it out on google (What is a sequence (Database)? When would we need it?). That way you can avoid having duplicate PK problems. But maybe your PK is not a number and has some business logic behind it, in that case a sequence is not an option.
Before insert record do one thing do count(*) and if count is 0 then and then insert the same otherwise show popup for duplicate query.
Consider an hypothetical User table:
-- postgres, but it could have been any other SQL database
CREATE TABLE User(
id SERIAL PRIMARY KEY,
mail VARCHAR(32) UNIQUE NOT NULL
);
Let's assume I attempt to add two users with the same mail:
session.save(new User(1, "xpto#gmail.com"));
session.save(new User(2, "xpto#gmail.com"));
and execute it through Hibernate. Hibernate will throw me an ConstraintViolationException:
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:129)
...
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "users_mail_key"
Detail: Key (mail)=(xpto#gmail.com) already exists.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
...
What I'd like to know is if there's some good way, other than having to manually parse the Exception's output text, to gather what is the reason of the error so I may correctly interpret and react to the problem.
I realize that this may actually be more of a Postgres Driver's problem than actually an Hibernate one, but I'm unsure at this stage so I thought it may opportune to ask in Hibernate's context.
So if you are able to get a value from getSQLState, you can handle the exception:
"All messages emitted by the PostgreSQL server are assigned five-character error codes that follow the SQL standard's conventions for "SQLSTATE" codes. Applications that need to know which error condition has occurred should usually test the error code, rather than looking at the textual error message."
From: http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html
23505 = unique_violation
Note: In this link there is also the list.
Well, after looking at Postgres Driver's source code it seems the problem lies with Postgres and not with Hibernate. PSQLException will contain some information, although it certainly isn't as polished as I first assumed :(
} catch (PSQLException e) {
ServerErrorMessage m = e.getServerErrorMessage();
System.out.println(m.getColumn());
System.out.println(m.getConstraint());
System.out.println(m.getDatatype());
System.out.println(m.getDetail());
System.out.println(m.getFile());
System.out.println(m.getHint());
System.out.println(m.getInternalPosition());
System.out.println(m.getInternalQuery());
System.out.println(m.getLine());
System.out.println(m.getMessage());
System.out.println(m.getPosition());
System.out.println(m.getRoutine());
System.out.println(m.getSchema());
System.out.println(m.getSeverity());
System.out.println(m.getSQLState());
System.out.println(m.getTable());
System.out.println(m.getWhere());
}
prints
null
users_mail_key
null
Key (mail)=(xpto#gmail.com) already exists.
nbtinsert.c
null
0
null
398
duplicate key value violates unique constraint "users_mail_key"
0
_bt_check_unique
public
ERROR
23505
users
null
I am currently using MyBATIS in my project.
I sometimes need to run an INSERT query but ignore if the row I'm trying to insert is already present on DB, but instead handle other SQL errors.
How can I find that the SQLException is related to primary key violation?
Something like
try {
sqlMap.insert(query, params);
} catch (DuplicateKeyException ex) {
//Do nothing, it's OK for mew
} catch (SQLException ex) {
throw ex;
}
I suppose that specific exception doesn't really exist...
SQL isn't my strong point, but you could look into the Error Code and SQL State codes contained within the SQLException that would be thrown. Those may offer more insight into why the query failed.
I need to apply a check so that a user cannot register using an email id which already exists in the database.
Put a constraint on the email column, or select before insert.
There are indeed basically two ways to achieve this:
Test if record exists before inserting, inside the same transaction. The ResultSet#next() of the SELECT should return false. Then do INSERT.
Just do INSERT anyway and determine if SQLException#getSQLState() of any catched SQLException starts with 23 which is a constraint violation as per the SQL specification. It can namely be caused by more factors than "just" a constraint violation. You should namely not handle every SQLException as a constraint violation.
public static boolean isConstraintViolation(SQLException e) {
return e.getSQLState().startsWith("23");
}
I would opt for the first way as it is semantically more correct. It is in fact not an exceptional circumstance. You namely know that it is potentially going to happen. But it may potentially fail in heavy concurrent environment where transactions are not synchronized (either unawarely or to optimize performance). You may then want to determine the exception instead.
That said, you normally don't want to put a PK on an email field. They are namely subject to changes. Rather use a DB-managed autogenerated PK (MySQL: BIGINT UNSIGNED AUTO_INCREMENT, Oracle/PostgreSQL: SERIAL, SQLServer: IDENTITY) and give the email field an UNIQUE key.
Probably something like this DAO method :
public boolean isDuplicateEntry(String email) {
Session session = getSession();
try {
User user = (User) session.get(User.class, email);
session.close();
return (null != user);
} catch (RuntimeException e) {
log.error("get failed", e);
session.close();
throw e;
}
}
Put a unique constraint on the relevant column in the database table. For example (MySQL):
ALTER TABLE Users ADD UNIQUE (Email)
edit - If the e-mail field is already a primary key as you write in a comment above, then you don't need this, because primary keys are by definition unique. Then in Java you could catch the SQLException that you get if you'd insert a record with a primary key that already exists, or you can do a SELECT ... WHERE Email=? before you try the insert to see if there is already a record with that e-mail address.
You may:
make the email field unique, try to insert and catch the exception
or
make a select before each insert