I am working on a web application using Java and MySQL.
I created a method that is supposed to return an ArrayList of the respective column name based on the various tables in the database.
However, when I debugged the method, I realised the while(rs.next()) causes an error. I used this site for reference, hence I am not sure what went wrong.
This is the code. Thanks.
// Returns the the all the columns in the table
public ArrayList getColumnName(String tableName) throws SQLException {
ResultSet rs = null;
List<String> columnName = new ArrayList<String>();
Statement st = null;
Connection con = null;
try {
// Get a connection from the connection factory
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/information_schema", "root", "xxxx");
// Create a Statement object so we can submit SQL statements to the driver
st = con.createStatement();
StringBuilder sql = new StringBuilder("SELECT column_name FROM information_schema.columns " +
"WHERE table_schema = 'testDB' AND table_name = '");
sql.append(tableName).append("'");
rs = st.executeQuery(sql.toString());
while (rs.next()) { // getting error..
columnName.add(rs.getString("column_name"));
}
} catch (SQLException ex) {
Logger.getLogger(ModificationPage.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if (con != null || st != null) {
st.close();
con.close();
}
}
return (ArrayList) columnName;
}
According to the Javadoc of 1.6 (not sure which version of Java you're using):
Throws:
SQLException - if a database access error occurs or this method is called on a closed result set
It's very, very unlikely that if you actually got to the line where rs.next() was called, that a database error occurred just then. So, the most likely result is that the result set was closed.
Please alter your code to the following and see if you still get the error on the same line:
while (!rs.isClosed() && rs.next()) { // getting error..
columnName.add(rs.getString("column_name"));
}
Also, Holy SQL Injection Attack, Batman!
Taking the raw string as you're doing and enclosing it within single quotes leads this code to have an SQL injection vulnerability. Basically all a malicious user has to do is end your query with a single quote (') and run a query of their own afterwards.
So, the exception never happens ?
A query error should be thrown at rs = st.executeQuery(sql.toString()) if that were the case, but if it make it to whileand didn't iterate, it's because of an empty resultset
Maybe you're passing wrong arguments to the query ?
Related
I am facing a problem with retrieving a column from database
This is my code
public String ShowtimeQur(int MovieID)
{
rs3 = null;
String RoomID=null;
String ShowTime = null;
try
{
String qu ="Select Room_ID from Movie_Shows_in where Movie_ID="+MovieID;
//getRoomQur.setInt(1, MovieID);
rs3=getRoomQur.executeQuery(qu);
RoomID=rs3.getString("Room_ID");
getShowtimequr.setString(1, RoomID);
rs4=getShowtimequr.executeQuery();
ShowTime=rs4.getString("Show_Times");
}
catch (SQLException e)
{
e.printStackTrace();
}
return ShowTime;
}
I keep get this type of error
java.sql.SQLException: Invalid operation at current cursor position.
Use PreparedStatement.
PreparedStatement statement = con.prepareStatement("Select Room_ID from Movie_Shows_in where Movie_ID=?");
statement.setInt(1, MovieID);
ResultSet res = statement.executeQuery()
...
rest of your code
Never, never, never use string concatenation to build queries, as you put yourself at risk of SQL Injection
Like the answer before, you shoud declare a "ResulSet result" variable, and after the execute of the query, you should call "result.next()" method to point the cursor on the first row (initially is pointed to row 0 which does not exist) and then call a retrive data mehod like "result.getString(columnNumber)" by example.
This question already has answers here:
mysql prepared statement error: MySQLSyntaxErrorException
(2 answers)
Closed 6 years ago.
I've a course table with the columns,
id, teacher_id and name.
This is the method that I'm using to get a course by id.
public static Course getById(int id) throws SQLException {
String query = "SELECT * FROM courses WHERE id = ?" ;
Course course = new Course();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try{
DriverManager.registerDriver(new com.mysql.jdbc.Driver ());
connection = (Connection) DriverManager.getConnection(ConnectDb.CONN_STRING, ConnectDb.USERNAME, ConnectDb.PASSWORD);
statement = (PreparedStatement) connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
statement.setInt(1, id);
resultSet = statement.executeQuery(query);
while (resultSet.next()) {
course.setId(resultSet.getInt("id"));
course.setName(resultSet.getString("name"));
course.setTeacherId(resultSet.getInt("teacher_id"));
}
}catch (SQLException e) {
System.err.println(e);
}finally{
if (resultSet != null) resultSet.close();;
if (statement != null) statement.close();
if(connection != null) connection.close();
}
return course;
}// end of method
When I run this method, I get an output id :0, teacher_id : 0
The server log says that I've an SQLException
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 '?' at line 1
The bug is here:
resultSet = statement.executeQuery(query);
You're not calling PreparedStatement#executeQuery, you're calling Statement#executeQuery (Statement is a superinterface of PreparedStatement). So the parameter substitution isn't happening and you're actually sending that ? to the server.
Change it to:
resultSet = statement.executeQuery();
// No argument here ---------------^
(And yes, this is an API design flaw; and no, you're not the first to fall into it.)
There are a few other things about that code that could use improvement:
You're always returning a Course, even if an exception occurred. Best practices would be to allow the exception to propagate to the caller; second-best practices would be to return some kind of flag to the caller that an error occurred, such as null.
The try-with-resources statement can make that code both shorter and clearer
You shouldn't have to cast the return values of getConnection or prepareStatement.
You're using while, but you're expecting only a single result. if would make more sense.
On that topic, you can give the driver a hint in that regard by using setMaxRows.
Your method declares that it can throw SQLException, which is literally true since it calls close, but the only useful SQLException is actually being caught, logged, and suppressed by the code, making declaring it on the method a bit misleading.
I'm told modern JDBC drivers don't need the registerDriver call anymore. (I personally haven't used JDBC for a while now, so...)
Here's an example incoporating the above. It allows an exception to propagate, so errors (exceptional conditions) are not handled in the normal flow of code; it returns null if there's no matching course:
public static Course getById(int id) throws SQLException {
String query = "SELECT * FROM courses WHERE id = ?";
try (
Connection connection = DriverManager.getConnection(ConnectDb.CONN_STRING, ConnectDb.USERNAME, ConnectDb.PASSWORD);
PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
) {
statement.setInt(1, id);
statement.setMaxRows(1);
try (
ResultSet resultSet = statement.executeQuery();
) {
if (resultSet.next()) {
Course course = new Course();
course.setId(resultSet.getInt("id"));
course.setName(resultSet.getString("name"));
course.setTeacherId(resultSet.getInt("teacher_id"));
return course;
}
// No matching course
return null;
}
}
} // end of method
That can probably be improved further, but you get the idea.
In my Java application I have to use data that comes from an Access 2010 database. I used the graphical query creator from Access to create the appropriate query and it works great.
Unfortunately, when I try to use a prepared statement with that query (in order to use a parameter) in my Java application I got an NPE
messageChildrenRequest.setString(1, blockId);
ResultSet result = messageChildrenRequest.executeQuery();
The NPE occurs when i set the parameter with setString() and my query is not execute but when i look with the debugger the statement is not null...
My query given by access is :
SELECT IRSIDD.[BLOCK ID], IRSIDD.[IDENTIFICATION CHIFFREE], IRSIDD.MSG_ID, MAIN.SUB_FIELD_ID, MAIN.ORDER, FIELD.[FIELD NAME], FIELD.TYPE, FIELD.[RC 'TYPE] "
FROM IRSIDD LEFT JOIN (MAIN LEFT JOIN FIELD ON MAIN.SUB_FIELD_ID = FIELD.[FIELD ID]) ON IRSIDD.[BLOCK ID] = MAIN.BLOCK_ID "
WHERE ((IRSIDD.[BLOCK ID])=?)
The StackTrace gives me :
Exception in thread "main"
java.lang.NullPointerException
at sun.jdbc.odbc.JdbcOdbcPreparedStatement.clearParameter(Unknown Source)
at sun.jdbc.odbc.JdbcOdbcPreparedStatement.setChar(Unknown Source)
at sun.jdbc.odbc.JdbcOdbcPreparedStatement.setString(Unknown Source)
When I tried a very simple prepared statement :
SELECT * FROM table1 WHERE table1.id = ?
I didn't get any NPE when setting the parameter so I suspect that Access and java JDBC do not have the same way to deal with join.
Does someone already that kind of problem or can confirm that the structure of my query is the problem here?
Connection connection = null;
CallableStatement callStmt = null;
String myParam = "test";
String statement = "SELECT * FROM table1 WHERE table1.id = ?";
try {
connection = DatabasePoolUtil.getDefaultConnection(); //Connects
callStmt = connection.prepareCall(statement);
callStmt.setString(1,myParam);
callStmt.execute();
}
catch (SQLException ex) {
// Do something
}
finally { // connection has to be closed
if (callStmt != null) {
callStmt.close();
}
if (connection != null) {
connection.close();
}
}
The ODBC (and OLEDB) interfaces to an Access database expose different types of saved Access queries as either "Views" or "Stored Procedures":
Access query appears under ODBC/OLEDB as
------------------------------- ---------------------------
Select query without parameters View
Select query with parameters Stored Procedure
Append query (INSERT) Stored Procedure
Update query Stored Procedure
Delete query Stored Procedure
Since your Access saved query has parameters it will look like a Stored Procedure under ODBC and therefore you need to use a CallableStatement to work with it.
For example, given the following saved parameter query named [myParameterQuery] in Access
PARAMETERS specificID Long;
SELECT Table1.*
FROM Table1
WHERE (((Table1.ID)=[specificID]));
we need to use the following Java code to retrieve the row for ID=3:
String connectionString = "jdbc:odbc:"
+ "DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};"
+ "DBQ=C:/Users/Public/32224442.accdb;";
try (Connection conn = DriverManager.getConnection(connectionString)) {
try (CallableStatement cs = conn.prepareCall("{call myParameterQuery(?)}")) {
cs.setInt(1, 3); // set "specificID" parameter to 3
try (ResultSet rs = cs.executeQuery()) {
rs.next();
System.out.println(rs.getInt(1));
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
System.exit(0);
}
The corresponding C# code would be:
string myConnectionString =
#"Driver={Microsoft Access Driver (*.mdb, *.accdb)};" +
#"Dbq=C:\Users\Public\32224442.accdb;";
using (var con = new OdbcConnection(myConnectionString))
{
con.Open();
using (var cmd = new OdbcCommand("{CALL myParameterQuery (?)}", con))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("?", OdbcType.Int).Value = 3; // set "specificID" parameter to 3
using (OdbcDataReader rdr = cmd.ExecuteReader())
{
rdr.Read();
Console.WriteLine(rdr[0]);
}
}
}
This question already has answers here:
ResultSet exception - before start of result set
(6 answers)
Closed 5 years ago.
try
{
PreparedStatement s = (PreparedStatement) conn.prepareStatement("SELECT voters.Check,count(*) FROM voting.voters where FirstName="+first+"and LastName="+last+" and SSN="+voter_ID);
//java.sql.Statement k = conn.createStatement();
rs=s.executeQuery();
//s.executeQuery("SELECT voters.Check,count(*) FROM voting.voters where FirstName="+first+"and LastName="+last+" and SSN="+voter_ID);
System.out.println(rs.first());
c=rs.getInt(1);
d=rs.getInt(2);
System.out.println(c);
System.out.println(d);
if(c==1 && d==1)
{
s.executeUpdate("update cand set total=total+1 where ssn="+can_ID);
System.out.println("Succeful vote");
System.out.println("after vote");
s.executeUpdate("update voters set voters.Check=1 where ssn="+voter_ID);
toclient=1;
PreparedStatement qw = (PreparedStatement) conn.prepareStatement("select FirstName from cand where ssn="+can_ID);
// rs=k.executeQuery("select FirstName from cand where ssn="+can_ID);
rs1 = qw.executeQuery();//Error Here Plz help me
String name1= (String) rs1.getString(1);
System.out.println(name1);
s.executeUpdate("update voters set VTO="+name1+"where ssn="+voter_ID);
System.out.println(rs.getString(1));
}
else
{
if(c != -1)
toclient =2;
if( d ==0)
toclient =3;
if( d>1)
toclient =4;
}
System.out.println("out-----------");
rs.close();
s.close();
}
catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Error IS :
java.sql.SQLException: Before start of result set
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1072)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:986)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:981)
The common practice is to use rs.next() method with while cycle:
PreparedStatement st = conn.prepareStatement("select 1 from mytable");
ResultSet rs = st.executeQuery();
while (rs.next()) {
// do something with result set
}
rs.close();
st.close();
I've omitted try/catch/finally clauses for clarity. Note that you should invoke each close() method in separate finally block.
While rs1.first() may work, to avoid exception I would like to avoid it and use rs1.next() instead.
See javadoc of ResultSet.first():
SQLException - if a database access error occurs; this method is called on a closed result set or the result set type is TYPE_FORWARD_ONLY
SQLFeatureNotSupportedException - if the JDBC driver does not support this method
while next doesn't have this limitation
Code:
if (rs1.next()) {
String name1 = rs1.getString(1);
}
Tips: avoid useless type casting (your code is full of them)
In your code snippet you create PreparedStatements but you do not use them correctly. Prepared statements are meant to be used as a kind of 'statement template' which is bound to values before it executes. To quote the javadoc:
PreparedStatement pstmt = con.prepareStatement(
"UPDATE EMPLOYEES SET SALARY = ? WHERE ID = ?");
pstmt.setBigDecimal(1, 153833.00)
pstmt.setInt(2, 110592)
This has two big advantages over your current usage of PreparedStatement:
one PreparedStatement can be used for multiple executes
it prevents a possible SQL injection attack
The second one here is the biggie, if for instance your variables first and last are collected in a user interface and not reformatted, you run the risk of parts of SQL being input for those values, which then end up in your statements! Using bound parameters they will just be used as values, not part of the SQL statement.
When you get a resultset, the cursor is placed before the first row. Trying to get anything before moving your cursor to the first row will cause the error you received. You need to move the cursor to the first row using this line:
rs1.first();
before calling
String name1 = (String) rs1.getString(1);
Of course, make sure the resultset contains entries before calling rs1.getString(1).
Call rs1.first() before using the ResultSet.
Moves the cursor to the first row in this ResultSet object.
Initially the cursor position of the ResultSet is before the start of the set. The first() method returns true if there is data in the set. So preferably:
if (rs1.first()) {
String name1 = (String) rs1.getString(1);
}
So, to be sure the proper use of PreparedStatment, here is your original example adjusted for best practices (note the cast is redundant):
PreparedStatement s = conn.prepareStatement(
"SELECT voters.Check,count(*) " +
"FROM voting.voters " +
"where FirstName=? and LastName=? and SSN=?");
s.setString(1,first);
s.setString(2,last);
s.setString(3,voter_ID);
ResultSet rs = s.executeQuery();
while( rs.next() ) {
c = rs.getInt(1);
d = rs.getInt(2);
}
Hope this helps... :)
As soon as my code gets to my while(rs.next()) loop it produces the ResultSet is closed exception. What causes this exception and how can I correct for it?
EDIT: I notice in my code that I am nesting while(rs.next()) loop with another (rs2.next()), both result sets coming from the same DB, is this an issue?
Sounds like you executed another statement in the same connection before traversing the result set from the first statement. If you're nesting the processing of two result sets from the same database, you're doing something wrong. The combination of those sets should be done on the database side.
This could be caused by a number of reasons, including the driver you are using.
a) Some drivers do not allow nested statements. Depending if your driver supports JDBC 3.0 you should check the third parameter when creating the Statement object. For instance, I had the same problem with the JayBird driver to Firebird, but the code worked fine with the postgres driver. Then I added the third parameter to the createStatement method call and set it to ResultSet.HOLD_CURSORS_OVER_COMMIT, and the code started working fine for Firebird too.
static void testNestedRS() throws SQLException {
Connection con =null;
try {
// GET A CONNECTION
con = ConexionDesdeArchivo.obtenerConexion("examen-dest");
String sql1 = "select * from reportes_clasificacion";
Statement st1 = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
ResultSet rs1 = null;
try {
// EXECUTE THE FIRST QRY
rs1 = st1.executeQuery(sql1);
while (rs1.next()) {
// THIS LINE WILL BE PRINTED JUST ONCE ON
// SOME DRIVERS UNLESS YOU CREATE THE STATEMENT
// WITH 3 PARAMETERS USING
// ResultSet.HOLD_CURSORS_OVER_COMMIT
System.out.println("ST1 Row #: " + rs1.getRow());
String sql2 = "select * from reportes";
Statement st2 = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
// EXECUTE THE SECOND QRY. THIS CLOSES THE FIRST
// ResultSet ON SOME DRIVERS WITHOUT USING
// ResultSet.HOLD_CURSORS_OVER_COMMIT
st2.executeQuery(sql2);
st2.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
rs1.close();
st1.close();
}
} catch (SQLException e) {
} finally {
con.close();
}
}
b) There could be a bug in your code. Remember that you cannot reuse the Statement object, once you re-execute a query on the same statement object, all the opened resultsets associated with the statement are closed. Make sure you are not closing the statement.
Also, you can only have one result set open from each statement. So if you are iterating through two result sets at the same time, make sure they are executed on different statements. Opening a second result set on one statement will implicitly close the first.
http://java.sun.com/javase/6/docs/api/java/sql/Statement.html
The exception states that your result is closed. You should examine your code and look for all location where you issue a ResultSet.close() call. Also look for Statement.close() and Connection.close(). For sure, one of them gets called before rs.next() is called.
You may have closed either the Connection or Statement that made the ResultSet, which would lead to the ResultSet being closed as well.
Proper jdbc call should look something like:
try {
Connection conn;
Statement stmt;
ResultSet rs;
try {
conn = DriverManager.getConnection(myUrl,"","");
stmt = conn.createStatement();
rs = stmt.executeQuery(myQuery);
while ( rs.next() ) {
// process results
}
} catch (SqlException e) {
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
} finally {
// you should release your resources here
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
} catch (SqlException e) {
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
}
you can close connection (or statement) only after you get result from result set. Safest way is to do it in finally block. However close() could also throe SqlException, hence the other try-catch block.
I got same error everything was correct only i was using same statement interface object to execute and update the database.
After separating i.e. using different objects of statement interface for updating and executing query i resolved this error. i.e. do get rid from this do not use same statement object for both updating and executing the query.
Check whether you have declared the method where this code is executing as static. If it is static there may be some other thread resetting the ResultSet.
make sure you have closed all your statments and resultsets before running rs.next. Finaly guarantees this
public boolean flowExists( Integer idStatusPrevious, Integer idStatus, Connection connection ) {
LogUtil.logRequestMethod();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = connection.prepareStatement( Constants.SCRIPT_SELECT_FIND_FLOW_STATUS_BY_STATUS );
ps.setInt( 1, idStatusPrevious );
ps.setInt( 2, idStatus );
rs = ps.executeQuery();
Long count = 0L;
if ( rs != null ) {
while ( rs.next() ) {
count = rs.getLong( 1 );
break;
}
}
LogUtil.logSuccessMethod();
return count > 0L;
} catch ( Exception e ) {
String errorMsg = String
.format( Constants.ERROR_FINALIZED_METHOD, ( e.getMessage() != null ? e.getMessage() : "" ) );
LogUtil.logError( errorMsg, e );
throw new FatalException( errorMsg );
} finally {
rs.close();
ps.close();
}
A ResultSetClosedException could be thrown for two reasons.
1.) You have opened another connection to the database without closing all other connections.
2.) Your ResultSet may be returning no values. So when you try to access data from the ResultSet java will throw a ResultSetClosedException.
It happens also when using a ResultSet without being in a #Transactional method.
ScrollableResults results = getScrollableResults("select e from MyEntity e");
while (results.next()) {
...
}
results.close();
if MyEntity has eager relationships with other entities. the second time results.next() is invoked the ResultSet is closed exception is raised.
so if you use ScrollableResults on entities with eager relationships make sure your method is run transactionally.
"result set is closed" happened to me when using tag <collection> in MyBatis nested (one-to-many) xml <select> statement
A Spring solution could be to have a (Java) Spring #Service layer, where class/methods calling MyBatis select-collection statements are annotated with
#Transactional(propagation = Propagation.REQUIRED)
annotations being:
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
this solution does not require to set the following datasource properties (i.e., in JBoss EAP standalone*.xml):
<xa-datasource-property name="downgradeHoldCursorsUnderXa">**true**\</xa-datasource-property>
<xa-datasource-property name="resultSetHoldability">**1**</xa-datasource-property>