I have an error of
java.sql.SQLException: The prepared statement has been finalized
which happens when I call the same preparedStatement a second time. I am calling it in a method.
Here is the database Java class (the relevant piece)
//create the charge table. (ps is PreparedStatement)
try{
statement.executeUpdate("CREATE TABLE charge(username TEXT NOT NULL, date DATETIME DEFAULT CURRENT_TIMESTAMP, charge REAL, PRIMARY KEY(username, date));");
} catch (SQLException ex) {
System.out.println("charge table creation failed. exception" + ex);
}
Method that creates a charge:
public void createCharge(String username, double amount){
try {
System.out.println(username + amount);
ps = connection.prepareStatement("INSERT INTO charge VALUES(?, ?, ?);");
ps.setString(1, username);
ps.setDate(2, DateConvert.toSQLDate(Date.valueOf(LocalDate.MIN)));
ps.setDouble(3, amount);
ps.executeUpdate();
ps.clearParameters();
System.out.println("Complete");
} catch (SQLException ex) {
Logger.getLogger(MontsRentalDatabase.class.getName()).log(Level.SEVERE, null, ex);
}
}
This is in the class where the charge is created:
public void createCharge(String username, double amount){
try {
System.out.println(username + amount);
ps = connection.prepareStatement("INSERT INTO charge VALUES(?, ?, ?);");
ps.setString(1, username);
ps.setDate(2, DateConvert.toSQLDate(Date.valueOf(LocalDate.MIN)));
ps.setDouble(3, amount);
ps.executeUpdate(); //Line 170
ps.clearParameters();
System.out.println("Complete");
} catch (SQLException ex) {
Logger.getLogger(MontsRentalDatabase.class.getName()).log(Level.SEVERE, null, ex);
}
}
The class that converts a normal date to sqldate:
public class DateConvert {
public static java.sql.Date toSQLDate(java.util.Date date){
return new java.sql.Date(date.getTime());
}
public static java.util.Date toJavaDate(java.sql.Date date){
return new java.util.Date(date.getTime());
}
}
The error is in line 170 of create charge, which is when ps.executeUpdate runs. It runs successful the first time, fails on the second.
Log:
450100.0
Complete
450150.0
SEVERE: null
java.sql.SQLException: The prepared statement has been finalized
at org.sqlite.core.NativeDB.throwex(NativeDB.java:429)
at org.sqlite.core.NativeDB.reset(Native Method)
at org.sqlite.core.DB.executeUpdate(DB.java:878)
at org.sqlite.jdbc3.JDBC3PreparedStatement.executeUpdate(JDBC3PreparedStatement.java:99)
at server.RentalDatabase.createCharge(RentalDatabase.java:170)
Thanks for any help,
J
I believe that this is a bug in version 3.14.2.1 of the SQLite JDBC driver.
It seems to me that you're getting a unique constraint violation exception, but the SQLite JDBC driver is tripping over itself attempting to report this exception and some other exception is getting thrown instead.
I was able to reproduce your exception using sqlite-jdbc version 3.14.2.1 if I tried to insert the same data multiple times, e.g. by re-running your code. I downgraded the SQLite JDBC driver to 3.8.11.2 and I got the following exception after running your code:
java.sql.SQLException: [SQLITE_CONSTRAINT] Abort due to constraint violation (UNIQUE constraint failed: charge.username, charge.date)
at org.sqlite.core.DB.newSQLException(DB.java:890)
at org.sqlite.core.DB.newSQLException(DB.java:901)
at org.sqlite.core.DB.execute(DB.java:810)
at org.sqlite.core.DB.executeUpdate(DB.java:847)
at org.sqlite.jdbc3.JDBC3PreparedStatement.executeUpdate(JDBC3PreparedStatement.java:86)
at com.example.MontsRentalDatabase.createCharge(MontsRentalDatabase.java:40)
at com.example.Main.main(Main.java:17)
Of course, when re-running the program, the data I'm trying to insert is in the table already. So a unique constraint violation is to be expected.
I then added the line
statement.execute("DROP TABLE IF EXISTS charge");
to createChargeTable(), above the line that creates the table. The code then ran successfully multiple times using either version of the SQLite JDBC driver.
This bug has now been fixed in sqlite-jdbc version 3.15.1, so the fix is therefore to upgrade to this version or later.
After you create a prepared statement, you should close it and not use it again. I don't see it in your code, but you stated: "which happens when I call the same preparedStatement a second time".
Your 'ps' variable should be a local variable, declared in a try-with-resource block such as:
try (PreparedStatement ps = connection.prepareStatement("INSERT INTO charge VALUES(?, ?, ?);")) {
ps.setString(1, username);
ps.setDate(2, DateConvert.toSQLDate(Date.valueOf(LocalDate.MIN)));
ps.setDouble(3, amount);
ps.executeUpdate(); //Line 170
ps.clearParameters();
System.out.println("Complete");
}
That way it can't be used after its been closed.
Related
I have a JavaFX application which uses an embedded database to store all data. Establishing a connection and inserting data works just fine besides the column 'id' auto incrementing by 100 instead of 1. I've read(Wrong auto increment in embedded Derby/ Java DB) that I have to shut down the database properly by using following code in my main class:
#Override
public void stop() {
try {
DriverManager.getConnection("jdbc:derby:"+"db"+";shutdown=true");
}
catch (SQLException sqlException){
sqlException.printStackTrace();
System.out.println("Database shutted down...");
}
}
However it's still incrementing by 100 and I'm not sure why.
My code for establishing a connection and doing inserts:
try {
Connection connection = DriverManager.getConnection("jdbc:derby:db");
connection.setAutoCommit(true);
System.out.println("Connection established");
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO orders(order_name, order_date, price) VALUES (?, ?, ?)");
preparedStatement.setString(1, "TestOrder");
preparedStatement.setDate(2, Date.valueOf(LocalDate.now()));
preparedStatement.setDouble(3, 1.1);
preparedStatement.execute();
preparedStatement.close();
connection.close();
} catch (SQLException throwables) {
System.out.println("Unable to establish connection");
throwables.printStackTrace();
}
And my SQL statement to create the table
DROP TABLE orders;
CREATE TABLE orders(
order_number INTEGER PRIMARY KEY NOT NULL GENERATED ALWAYS AS IDENTITY(START WITH 1, INCREMENT BY 1),
order_name VARCHAR(100),
order_date DATE,
price DECIMAL(4, 2));
My java code for SQL Query is
String sqlSt="INSERT INTO users(id,name,place) values ("+null+",'"+request.getParameter("name")+"','"+request.getParameter("place")+"');";
I have tried out
name= a'); DROP TABLE users; --
as well as
place =a'); DROP TABLE users; --
but it returns an Ecxeption as below
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DROP TABLE users; --','chennai')' at line 1
Note: when i tried the same in mysql command line. It worked!!!! i don't know what happens in jdbc
The real problem is actually JDBC, it only allows one sql if you dont tell it otherwise.
Look at this question for more info:
Multiple queries executed in java in single statement
But also i would try this instead, name =
a',''); DROP TABLE users; --
Since you specificed 3 columns in your insert:
(id,name,place)
You need to provide 3 values for the sql to be valid, not just 2.
Also you can sent the text null, sending a java null value is not necessary and i am not even sure how that works. I think this might be better:
String sqlSt="INSERT INTO users(id,name,place) values (null,'"+request.getParameter("name")+"','"+request.getParameter("place")+"');";
Instead of null, use an empty string ''
String sqlSt = "INSERT INTO users(id, name, place) values ('', '" + request.getParameter("name") + "', '" + request.getParameter("place") + "');";
It's better to use prepared statements to avoid confusion.
String sqlSt = "INSERT INTO users(id, name, place) values ('', ?, ?)";
PreparedStatement ps = null;
try {
ps = connection.prepareStatement(query);
ps.setString(1, request.getParameter("name"));
ps.setString(2, request.getParameter("place"));
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
ps.close();
}
The real problem is with your Query. It is better to use a PreparedStatement for executing a query.
Your Code should be :
String sqlSt="INSERT INTO users(id,name,place) values (?,?,?)";
PreparedStatement pstmt = null;
try{
pstmt = dbConnection.prepareStatement(sqlSt);
pstmt.setString(1,null);
pstmt.setString(2,request.getParameter("name"));
pstmt.setString(3,request.getParameter("place"));
pstmt.executeUpdate();
}catch (Exception e) {
e.printStackTrace();
} finally {
pstmt.close();
}
If you don't want to use a PreparedStatement, just remove last ; from your query.
So your query will be :
String sqlSt="INSERT INTO users(id,name,place) values ("+null+",'"+request.getParameter("name")+"','"+request.getParameter("place")+"')";
I made one table Login using oracle. Firstly I have taken fields- id,username,password and connected database in java program for signup. I was trying to execute insert query before it was running fine than I altered table Login and dropped column id. Then again I tried to run insert query from java program but now I am getting below error. I am not getting what happened after alteration. I think changes should reflect everywhere but I am stuck with this exception.
java.sql.SQLSyntaxErrorException: ORA-04098: trigger 'SURABHI.BI_LOGIN' is invalid and failed re-validation
JAVA CODE:
public void insertLogin(String user,String pass) {
String query = "insert into Login(username,password)" + " values(?,?)";
try {
ps = con.prepareStatement(query);
ps.setString(1, user);
ps.setString(2, pass);
ps.execute();
System.out.println("inserted");
} catch(Exception e) {
e.printStackTrace();
}
}
It seems your table has a before insert trigger and it is invalid, probably because you dropped column id and it is used by the trigger.
Check your trigger and compile it successfully.
I've looked on here before, but none of the answers helped me out!
I have the following code:
public void addSerialToDb(String serial) {
System.out.println(serial);
try{
System.out.println(getMaxInt());
}catch (Exception e){
e.printStackTrace();
}
String serialV2 = ""+serial;
try{
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(url, user, password);
pst = con.prepareStatement("INSERT INTO blogdata.serials" + "VALUES(?, ?)");
pst.setInt(1, getMaxInt());
pst.setString(2, serialV2);
pst.executeUpdate();
}catch (Exception e) {
e.printStackTrace();
}
closeDataBase();
}
In my database scheme, there are 2 columns, first one is integer (id) and second one is a VARCHAR(45) (serial). But still I get the following error:
java.sql.SQLException: Parameter index out of range (2 > number of parameters, which is 0).
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:897)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:886)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3321)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3306)
at com.mysql.jdbc.PreparedStatement.setString(PreparedStatement.java:4021)
at DataBase.SerialDataBase.addSerialToDb(SerialDataBase.java:41)
I used this method on another program, but since switched to IntelliJ it stopped working.
Thanks in advance!
EDIT:
I forgot to mention, I'm using Java 1.8, the mySql connector 5.1.40 and running MySql 5.7.15
According to your comment getMaxInt() method, the problems is because of prepare statement object. It's being updated in getMaxInt() method and parameters not match error occurred. I think it's program logic error and you just need to change this program logic. I also recommend to not concat the String if it's not needed.
Below is just ok.
pst = con.prepareStatement("INSERT INTO blogdata.serials (column1,column2) VALUES (?,?)";
Try using the insert statement like this:
"INSERT INTO blogdata.serials (column1,column2) VALUES (?,?)";
I'm trying to insert a new record into an MS SQL database, and I'm getting an exception I've never seen before. When I call executeUpdate the following exception is thrown:
com.microsoft.sqlserver.jdbc.SQLServerException: A result set was generated for update.
This is the Java code that produces the error:
// addComment method adds a new comment for a given requestId
public CommentBean addComment(CommentBean comment) {
PreparedStatement stmt = null;
INative nat = null;
Connection conn = null;
try {
nat = dbConn.retrieveNative();
conn = (Connection)nat.getNative("java.sql.Connection");
stmt = conn.prepareStatement(ADD_COMMENT);
stmt.setInt(1, comment.getRequestId());
stmt.setString(2, comment.getComment());
stmt.setString(3, new SimpleDateFormat("MM/dd/yyyy").format(comment.getDateCreated()));
stmt.setString(4, comment.getCreatedBy());
comment.setCommentId(stmt.executeUpdate()); // exception
} catch(Exception ex) {
System.err.println("ProjectRegistration::SQLDAO - addComment");
ex.printStackTrace();
} finally {
try {
if (stmt != null) stmt.close();
} catch (Exception e) {}
}
return comment;
}// end addComment
Where ADD_COMMENT is defined as a String:
private static final String ADD_COMMENT = "INSERT INTO RequestComments OUTPUT INSERTED.commentId VALUES(?,?,?,?)";
For the sake of being thorough, the table is defined as:
CREATE TABLE RequestComments (
commentId int NOT NULL PRIMARY KEY IDENTITY(1,1),
requestId int FOREIGN KEY REFERENCES Requests(requestId),
comment varchar(400),
dateCreated date,
createdBy varchar(12)
);
I don't think I'm doing anything terribly complicated here, but I can't think of why I'm getting this exception. I have a method in the same class which does the exact same type of insertion (literally the same query with a different table name and number of values), and it has no issues. Does anyone have any ideas on how to resolve this issue?
This particular error can also be caused by an INSERT-trigger, which has a SELECT-statement as a part of the trigger code.
To test whether this is the case, you can try:
using executeQuery(), instead of executeUpdate() - and display the result.
executing the insert in tool like MySQL Workbench, SQL Server Management Studio, or whatever flavour of database design tools are available for your DBMS, to see whether a result is returned.
Related: sql server error "A result set was generated for update"
I'm hoping this may help others looking at the same error message, as it did for me. My solution was to live with a call to executeQuery(), although it only handles an underlying issue, instead of fixing it.
This instruction stmt.executeUpdate() is not returning the commentId, it returns a ResultSet which you could then get the commentId from. Something like this,
ResultSet rs = stmt.executeQuery(); // Not update, you're returning a ResultSet.
if (rs.next()) {
comment.setCommentId(rs.getInt(1));
}
you are using OUTPUT in your insert query i.e you will get a resultset after your query executes and to hold that you need an object of class ResultSet to hold that data
SqlServer : When SET NOCOUNT is ON, the count is not returned. When SET NOCOUNT is OFF, the count is returned.
Connection conn = DriverManager.getConnection(connectDB,user,pwd);
String sql = " set nocount off;INSERT INTO test (name) values (1)";
PreparedStatement prepareStatement = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
System.out.println(prepareStatement.executeUpdate());
ResultSet generatedKeys = prepareStatement.getGeneratedKeys();
if(generatedKeys.next()){
System.out.println(generatedKeys.getString(1));
}
Related:
set-nocount-on-usage
I've had a similar problem where after a while an insert on a autonumber table would give a "A result set was generated for update." at random. I use connection pooling and somehow the driver can get into a state where executeUpdate in combination with Statement.RETURN_GENERATED_KEYS doesn't work anymore. I found out that in this state an executeQuery does the trick, but in the initial state executeQuery does not work. This lead me to the following workaround:
PreparedStatement psInsert = connection.prepareStatement("INSERT INTO XYZ (A,B,C) VALUES(?,?,?)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = null;
try {
psInsert.setString(1, "A");
psInsert.setString(2, "B");
psInsert.setString(3, "C");
Savepoint savePoint = connection.setSavepoint();
try {
psInsert.executeUpdate();
rs = psInsert.getGeneratedKeys();
} catch (SQLServerException sqe)
{
if (!sqe.getMessage().equals("A result set was generated for update."))
throw sqe;
connection.rollback(savePoint);
rs = psInsert.executeQuery();
}
rs.next();
idField = rs.getInt(1);
} finally {
if(rs != null)
rs.close();
psInsert.close();
}