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

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

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.

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.

Java. Statement execution in cycle

I try to execute INSERT query in cycle:
String selectTableSQL = "SELECT * "
+ "FROM testTable";
ResultSet rs = stmt.executeQuery(selectTableSQL);
while (rs.next()) {
String rangeName = rs.getString("RANGENAME");
insertTableSQL = "INSERT INTO testTable2 "
+ "VALUES ('" + rangeName + "')";
try {
stmt.executeUpdate(insertTableSQL);
} catch (SQLException e) {
// do nothing
}
But after one iteration this cycle breaks. If I don't execute INSERT query and print rangeName to screen everything works perfectly (there are a lot of values, not only one). So the problem is in statement execution. How can I solve it?
Thank you very much!
Of course it does: you're using the same stmt
Create a new stmt2 variable and use it inside loop without destroying the previous one.
First: Never do so
} catch (SQLException e) {
// do nothing
}
Add a e.printStackTrace() to the catch block.
I think you get an exception when you do so. You may need a second statement variable.

Getting an Integer From MySQL Select Statement

I would like to get an integer saved in my MySql DB into an Integer in Java. I have a Table, that includes PlayerName and Level. I would like to get The Level (Integer) From a Specific Player. And then Add Integer "Value" to it. Then put it back in the DB. My Code up to now is:
public void addinputPData(String loc, int value, Player player, String playername){
//add input Player Data
try{
logm("Putting Kill Death Int Data into " +player.getName() + "'s Profile!");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/WebCom", "root", "MyPW");
int ovalue = -1;
Statement stmt = (Statement) con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT "+loc+" FROM PlayerData WHERE PlayerName='"+playername+"'");
if(rs.next()){
ovalue= rs.getInt(loc);
}
if(ovalue == -1){
logm("Error Occured");
}
int nvalue = value + ovalue;
String insert = "UPDATE PlayerData SET "+ loc + "='" + nvalue + "' WHERE PlayerName='" + playername + "'";
stmt.executeUpdate(insert);
con.close();
}catch(Exception e){
logm("Could Not Send Data To MYSQL DATABASE SERVER s: "+ e.getMessage());
}
}
I don't know why this won't work, Is there anything obvious that i am missing? Thank you in advance.
So first what you must understand is that when you won't use parametrized statements, there is big danger of SQL Injection. So your code is very dirty written.
So anyway, use PreparedStatement with parametrized SQL statements for much more better performace. Now rewrite your code like this:
final String SELECT_QUERY = "SELECT level FROM PlayerData WHERE PlayerName = ?";
final String UPDATE_QUERY = "UPDATE PlayerData SET level = ? WHERE PlayerName = ?";
public boolean dataMethod(String playerName) {
Connection con = null;
PreparedStatement ps = null;
PreparedStatement ps1 = null;
ResultSet rs = null;
int dataLevel = 0;
try {
// getConnection etc...
ps = con.prepareStatement(SELECT_QUERY);
ps.setString(1, playerName) // first param is order of ? param, starts with 1(not 0)
rs = ps.executeQuery();
while (rs.next()) {
dataLevel = rs.getInt();
}
if (dataLevel > 0) {
ps1 = con.prepareStatement(UPDATE_QUERY);
ps1.setInt(1, dataLevel);
ps1.setString(2, playerName);
ps1.executeUpdate();
}
return true;
}
catch (SQLExcetion ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
finally {
if (con != null) {
con.close();
}
}
}
Step by step, first init your statement, sets parameters if you have then when you use select, you will retrieve data in ResultSet that is table of data generated with query. imlicitly cursor in ResultSet is position before first row so you have to use next() method to go on current row and with the help of getter method you add data from ResultSet to your variable. Then you check if it's correct, if do, init second statement and execute it. And that's all.
But you should consider when you use more that 1 operation, sets autoCommit on false and all operations will do in one Transaction, because implicitly in JDBC is one operation = one transaction. And second, you should consider to use SQL stored procedures for add any data, update data or delete. It's more safer yet and less code. So let database working when it able to do it and also it's faster of course.
At the last, really you should think about this approach and makes your code more safer, faster and cleaner. Not have look on simplicity but on efficiency, compability and security.
More about SQL Injection
And when you decided right to use stored procedure, you can use it like this:
CREATE OR REPLACE PROCEDURE SOME_NAME(VARCHAR v_name PlayerData.name%type)
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
// body
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
So now you have to create String for call procedure.
final String CALL_SOMENAME = "{call SOME_NAME(?)}";
Then intead of PreparedStatement you have to use CallableStatement that is interface used to execute SQL stored procedures.
cs.prepareCall(CALL_SOMENAME); // Creates a cs object for calling db stored procedures
cs.setString(1, playerName);
cs.execute();
I don't know why many people searching the easiest way to do something and don't look at performance and readability of code.
Regards
In the UPDATE statement, you're inserting the value for the "loc" column as a string (there are single quotes around the value). If the database column is an integer, then this could be causing a problem.
Tip: JDBC provides a class called PreparedStatement. This class allow you to build SQL queries safely. It makes sure that all user input is properly escaped in order to avoid security vulnerabilities.
PreparedStatement ps = con.prepareStatement("UPDATE PlayerData SET " + loc + " = ? WHERE PlayerName = ?");
ps.setInt(1, nvalue);
ps.setString(2, playername);
ps.execute();

SQLSTATE 24000 - Invalid Cursor State

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.

Categories

Resources