SQLSTATE 24000 - Invalid Cursor State - java

I connect to a DB2 database and makes the following query. I don't understand why I get the error: "invalid cursor state".
public static void blivPar() {
try {
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
stmt.setMaxRows(1000);
ResultSet drenge = stmt.executeQuery("SELECT * FROM People WHERE sex='M'");
ResultSet piger = stmt.executeQuery("SELECT * FROM People WHERE sex='F'");
drenge.first();
piger.first();
int i=0;
while(drenge.next()) {
while(piger.next()) {
i++;
System.out.print(i);
stmt.execute("INSERT INTO Couples Values ('"+drenge.getString(1) +
"','" + drenge.getString(2) +
"','" + piger.getString(1) +
"','" + piger.getString(2) + "')");
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
Thank you.

Found this on the JDBC Javadocs for the Statement interface: "The object used for executing a static SQL statement and returning the results it produces.
By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists. "
see Statement javadoc
So it looks to me like you need two different Statements if you want two ResultSets open at the same time. Or you need to finish processing your first ResultSet and close it so you can re-use the Statement to create the second ResultSet.

Related

Value of ResultSet when the SQL statement is a wrong syntax?

I am using mySQL. As you see, the SQL statement is wrong at SELECT. So, I wonder what value the rs is?
I hope to get some advice. I thank you so much;
String sql = "SELCT * FROM user WHERE username = '" + username + "' and password = '" + password + "'";
ResultSet rs = stm.executeQuery(sql);
There would be no value because Statement.executeQuery(String) would throw a SQLException. As the linked Javadoc says,
Returns:
a ResultSet object that contains the data produced by the given query; never null
Throws:
SQLException - if a database access error occurs, this method is called on a closed Statement, the given SQL statement produces anything other than a single ResultSet object, the method is called on a PreparedStatement or CallableStatement
It will return you an exception having message like syntax error.
Easiest way to find is to debug your code by putting break points in code & examining / watching values of variables . Most IDEs have these debugging features. In addition to Elliott Frisch's answer, if I restructure your code like below then in case of invalid / incorrect SQL, control comes to catch block and you can see that value of rs remains null.
public void executeQuery(Connection conn, String username,String password) {
String sql = "SELCT * FROM user WHERE username = '" + username + "' and password = '" + password + "'";
ResultSet rs = null;
Statement stm = null;
try {
stm = conn.createStatement();
rs= stm.executeQuery(sql);
while(rs.next()) {
//Extract ResultSet here as per needed logic
}
} catch (SQLException e) {
// Your control comes here if query is wrong , put a break point at below line & examine value of rs
e.printStackTrace();
}finally {
// Close resources not needed after this method call like - result sets , statements & connection
}
}
Firstly statement won't execute, so next execution is depends on how you are going to handle that exception. So, if exception comes and if you handle also there will be null in ResultSet because no value assigned to it.

java.sql.SQLException: Operation not allowed after ResultSet closed [help] [duplicate]

When I execute the following code, I get an exception. I think it is because I'm preparing in new statement with he same connection object. How should I rewrite this so that I can create a prepared statement AND get to use rs2? Do I have to create a new connection object even if the connection is to the same DB?
try
{
//Get some stuff
String name = "";
String sql = "SELECT `name` FROM `user` WHERE `id` = " + userId + " LIMIT 1;";
ResultSet rs = statement.executeQuery(sql);
if(rs.next())
{
name = rs.getString("name");
}
String sql2 = "SELECT `id` FROM `profiles` WHERE `id` =" + profId + ";";
ResultSet rs2 = statement.executeQuery(sql2);
String updateSql = "INSERT INTO `blah`............";
PreparedStatement pst = (PreparedStatement)connection.prepareStatement(updateSql);
while(rs2.next())
{
int id = rs2.getInt("id");
int stuff = getStuff(id);
pst.setInt(1, stuff);
pst.addBatch();
}
pst.executeBatch();
}
catch (Exception e)
{
e.printStackTrace();
}
private int getStuff(int id)
{
try
{
String sql = "SELECT ......;";
ResultSet rs = statement.executeQuery(sql);
if(rs.next())
{
return rs.getInt("something");
}
return -1;
}//code continues
The problem is with the way you fetch data in getStuff(). Each time you visit getStuff() you obtain a fresh ResultSet but you don't close it.
This violates the expectation of the Statement class (see here - http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html):
By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists.
What makes things even worse is the rs from the calling code. It is also derived off-of the statement field but it is not closed.
Bottom line: you have several ResultSet pertaining to the same Statement object concurrently opened.
A ResultSet object is automatically
closed when the Statement object that
generated it is closed, re-executed,
or used to retrieve the next result
from a sequence of multiple results.
I guess after while(rs2.next()) you are trying to access something from rs1. But it's already closed since you reexecuted statement to get rs2 from it. Since you didn't close it, I beleive it's used again below.

While loop terminates only in one iterartion

try {
ResultSet rs = stat.executeQuery("select * from details where COURSEANDDEPT='"+username+"'");
//if (rs.next()) {
while (rs.next()) {
String logid=rs.getString(1);
char temp=' ';
ResultSet ag=stat.executeQuery("select type from login");
if (ag.next()) {
temp=ag.getString(1).charAt(0);
if (temp=='s' || temp=='S') {
String logid=ag.getString(1);
stat.executeQuery("insert into assignments values('"+logid+"','"+comments+"','P','"+userid+"','"+username+"')");
}
}
}
JOptionPane.showMessageDialog(this,"Assignment Sent To The Whole Class");
//} else {
//JOptionPane.showMessageDialog(this,"Invalid Branch");
//}
} catch (ClassNotFoundException | SQLException ex) {
Logger.getLogger(Assignments.class.getName()).log(Level.SEVERE, null, ex);
}
The while loop of rs.next() terminates only in one iteration even after containing 6 records in itself. How to rectify it?
The problem is that you use the same statement object for executing several queries. Addictional problems are
you don't close neither your statements neither your resultsets (see example).
you should use statements' parameters (see example).
you should not use select *, but list the columns you want back from statement (i'll not include this in the example).
one of the queries ("select type from login") is always repeated the same way, maybe there's an error on the query. Otherwise it should be executed once outside the main loop.
in the example i don't manage the connection but this should be done too
Lets suppose that you have a Connection object called conn
PreparedStatemet stat=null;
PreparedStatement innerStat=null;
PreparedStatement insertStat=null;
try {
stat=conn.prepareStatement("select * from details where COURSEANDDEPT=?");
stat.setString(1,username);
ResultSet rs = stat.executeQuery();
//if (rs.next()) {
while (rs.next()) {
String logid=rs.getString(1);
char temp=' ';
innerStat=conn.prepareStatement("select type from login");
ResultSet ag=innerStat.executeQuery();
if (ag.next()) {
temp=ag.getString(1).charAt(0);
if (temp=='s' || temp=='S') {
String logid=ag.getString(1);
ag.close();
innerStat.close();
insertStat=conn.prepareStatement("insert into assignments values(?,?,?,?,?)");
insertStat.setString(1,logId);
insertStat.setString(2,comments);
insertStat.setString(3,"P");
insertStat.setString(4,userid);
insertStat.setString(5,username);
insertStat.executeUpdate();
insertStat.close();
}//closes if on temp
} //closes if on ag
} //closes while
rs.close();
stat.close();
JOptionPane.showMessageDialog(this,"Assignment Sent To The Whole Class");
//} else {
//JOptionPane.showMessageDialog(this,"Invalid Branch");
//}
} catch (ClassNotFoundException | SQLException ex) {
Logger.getLogger(Assignments.class.getName()).log(Level.SEVERE, null, ex);
if(insertStat!=null) insertStat.close();
if(innerStat!=null) innertStat.close();
if(stat!=null) stat.close();
}
Your problem is that each connection can only handle one SQL statement at a time. You're trying to leave your first select statement open while you do a bunch of other statements. You can't do this on a single connection.
I suggest two changes to make this work.
Do the query against the login table first. Its result won't vary from one iteration to the next, so there is no point in repeating it over and over within the main loop.
Rewrite the queries against details and assignments as an insert/select statement. It's probably something like the following.
.
"insert into assignments " +
"select logid, ,'" + comments + "','P','" + userid + "','" + username + "' "
"from details " +
"where COURSEANDDEPT='"+username+"'"
Also, you might consider writing this with a PreparedStatement, depending on whether SQL injection attacks are a likelihood.

JDBC exception "Operation not allowed after ResultSet closed" when iterating over ResultSet

I have a problem with this code:
ResultSet dane = statement.executeQuery("SELECT * FROM ProWarns WHERE blahblah = '" + cel + "'");
while (dane.next()) {
// some code (only get some string from result)
if (TimeEnd <= EndTime) {
statement.executeUpdate(
"DELETE FROM ProWarns WHERE id = '" + id + "'"); //and error
statement.executeUpdate(
"UPDATE ProWarnsPlayers SET num = '" + NewV + "'" WHERE Pl = '"+ tar + "'");
}
}
Error: java.sql.SQLException: Operation not allowed after ResultSet closed. Where is the bug and how can I fix it?
PS:
I am including a Pastebin of my DB class, in case its helpful.
A Statement object caches its result set, so when you execute the additional operations in your for loop the original result set gets 'reset'. Which leads to the error that is happening, when you call dane.next. From the Javadoc:
By default, only one ResultSet object per Statement object can be open
at the same time. Therefore, if the reading of one ResultSet object is
interleaved with the reading of another, each must have been generated
by different Statement objects. All execution methods in the Statement
interface implicitly close a statment's current ResultSet object if an
open one exists.
Options? Use another Statement object to execute the inner queries.

Why rs.next() don't go to another record

If I remove beforeFirst() my function does only first record in ResultSet and go to end. If I use beforeFirst() I get an error ResultSet IS_TYPE_FORWARD_ONLY.
try {
ResultSet rs = stat.executeQuery("select _id, godziny_id from tblZmiany where harmonogram_id = " + h_id + " order by pracownik_id, Dzien");
rs.beforeFirst();
while (rs.next()) {
if (stat.executeUpdate("insert into tblWykonanie (Zmiana_id, Godziny_id) values ('" + rs.getLong(1) + "', " + rs.getInt(2) + ");") < 1) {
// Jeśli insert nie wstawił kolejnego rekordu
error_code = "Wystąpił problem podczas zatwierdzania harmonogramu.";
return false;
}
}
} catch (SQLException e) {
e.printStackTrace();
System.out.println(e.getMessage());
return false;
} catch (Exception e) {
error_code = e.getMessage();
return false;
}
return true;
You're using the same Statement object for both the SELECT and the INSERT. From the Javadoc:
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
To fix the problem, use a separate Statement object for the executeUpdate() call.
Also, I strongly advise you to change the code to use PreparedStatement with bound arguments (represented by ?). Building SQL statements bit by bit as you're doing right now could open up security vulnerabilities.
Your code has a major security flaw. You are vulnerable to SQL injection. Never, ever, ever, ever, ever, ever, ever, use string concatenation with SQL statements; use PreparedStatements instead!
harmonogram_id = " + h_id + " order by pracownik_id,
Take a look here to see how your application could be easily owned with simple tricks:
http://en.wikipedia.org/wiki/SQL_injection
To answer your question though, it depends on your database. You have to set a property during the connection creation:
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE),
ResultSet.HOLD_CURSORS_OVER_COMMIT);
From:
http://docs.oracle.com/javase/1.4.2/docs/guide/jdbc/getstart/resultset.html#1012735

Categories

Resources