Java & MySql - How to escape query before execute it - java

I'm using Java for a web application, and I'm working with a MySql database. I need to escape the query before execute it. This is my actual code :
db_result=mydb.selectQuery("SELECT nickname FROM users WHERE nickname='"+log_check_user+"' AND password='"+log_check_pass+"'");
public Vector selectQuery(String query) {
Vector v = null;
String [] record;
int colonne = 0;
try {
Statement stmt = db.createStatement();
ResultSet rs = stmt.executeQuery(query);
v = new Vector();
ResultSetMetaData rsmd = rs.getMetaData();
colonne = rsmd.getColumnCount();
while(rs.next()) {
record = new String[colonne];
for (int i=0; i<colonne; i++) record[i] = rs.getString(i+1);
v.add( (String[]) record.clone() );
}
rs.close();
stmt.close();
} catch (Exception e) { e.printStackTrace(); errore = e.getMessage(); }
return v;
}
I need this, as you can believe, to avoid the SQL Injection problem! How can I do it?

Use a prepared statement:
Sometimes it is more convenient to use a PreparedStatement object for sending SQL statements to the database. This special type of statement is derived from the more general class, Statement...
If you want to execute a Statement object many times, it usually reduces execution time to use a PreparedStatement object instead.
The main feature of a PreparedStatement object is that, unlike a Statement object, it is given a SQL statement when it is created. The advantage to this is that in most cases, this SQL statement is sent to the DBMS right away, where it is compiled. As a result, the PreparedStatement object contains not just a SQL statement, but a SQL statement that has been precompiled. This means that when the PreparedStatement is executed, the DBMS can just run the PreparedStatement SQL statement without having to compile it first...

Related

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.

SELECT with WHERE using PreparedStatement

I have this method that selects movie showtimes by movie ID from a MySQL database and puts them in a Time[]. However, it is throwing a syntax exception near '? ORDER BY schedule_id' according to the trace.
public Time[] getShowTimes(int movieId) {
List<Time> list = new ArrayList<Time>();
try {
sql = "SELECT schedule_time FROM schedule WHERE movie_id = ? ORDER BY schedule_id";
ps = conn.prepareStatement(sql);
ps.setInt(1, movieId);
rs = ps.executeQuery(sql);
while(rs.next()) {
list.add(rs.getTime(1));
}
} catch(SQLException se) {
se.printStackTrace();
}
Time[] times = new Time[list.size()];
times = list.toArray(times);
return times;
}
I followed this example (if that helps). What could be wrong?
You are calling the executeQuery(String) method in your PreparedStatement, and that call is just inherited from Statement. But Statement just executes the query without any PreparedStatement placeholder semantics, hence the error.
Instead, you want to call the executeQuery() (no arguments) method. The SQL has already been prepared, and all placeholders have been assigned values, so the SQL argument string is not needed again.
rs = ps.executeQuery();

Getting resultset from insert statement

i have the below code, where I'm inserting records to a table. When I try to get resultset, it returns null. How to get the latest added row into a resultset?
String sql1 = "INSERT INTO [xxxx].[dbo].[xxxxxx](WORKFLOW_SEQ_NBR," +
" WORKFLOW_LOG_TYPE_CODE, WORKFLOW_STATUS_CODE, DISP_CODE, DISP_USER, DISP_COMMENT, DISP_TITLE, DISP_TS)" +
"VALUES(?,?,?,?,?,?,?,?)";
PreparedStatement pst = connect.prepareStatement(sql1);
pst.setString(1, ...);
pst.setString(2, ...);
...
...
...
pst.executeUpdate();
ResultSet rstest = pst.executeQuery();
// ResultSet rstest = pst.getResultSet();
EDIT: Resolved
added following method to go to the last added row
st.execute("Select * from [xxxx].[dbo].[xxxxxxxxx]");
ResultSet rstest = st.getResultSet();
rstest.afterLast();
GETLASTINSERTED:
while(rstest.previous()){
System.out.println(rstest.getObject(1));
break GETLASTINSERTED;//to read only the last row
}
When using a SQL statement such as INSERT, UPDATE or DELETE with a PreparedStatement, you must use executeUpdate, which will return the number of affeted rows. In this case there is simply no ResultSet produced by the sql operation and thus calling executeQuery will throw a SQLException.
If you actually need a ResultSet you must make another statement with a SELECT SQL operation.
See the javadoc for PreparedStatement#executeQuery and PreparedStatement#executeUpdate
Seems like this is an older question, but i'm looking for a similar solution, so maybe people will still need this.
If you're doing an insert statement, you can use the :
Connection.PreparedStatement(String, String[]) constructor, and assign those to a ResultSet with ps.getGeneratedKeys().
It would look something like this:
public void sqlQuery() {
PreparedStatement ps = null;
ResultSet rs = null;
Connection conn; //Assume this is a properly defined Connection
String sql = "insert whatever into whatever";
ps = conn.prepareStatement(sql, new String[]{"example"});
//do anything else you need to do with the preparedStatement
ps.execute;
rs = ps.getGeneratedKeys();
while(rs.next()){
//do whatever is needed with the ResultSet
}
ps.close();
rs.close();
}
Connection#prepareStatement() - Creates a PreparedStatement object for sending parameterized SQL statements to the database.
which means connect.prepareStatement(sql1); created the PreparedStatement object using your insert query.
and when you did pst.executeUpdate(); it will return the row count for SQL Data Manipulation Language (DML) statements or 0 for SQL statements that return nothing
Now if you again want to fetch the data inserted you need to create a new PreparedStatement object with Select query.
PreparedStatement pstmt = connect.prepareStatement("SELECT * FROM tableName");
then this shall give you the ResultSet object that contains the data produced by the query
ResultSet rstest = pstmt.executeQuery();

How to fix my Prepared Statement to give me data from the DB in my application?

I have my Java program and I need to get data from my MYSQL DB,
I wrote this one out but its just sysout so getting data from my class and not using the Prepared Statement (I can delete the first 3 lines and it will work the same )
Could use some help to figure out how to get data from my DB and print it out
public void viewClientDetails(ClientsBean client) {
try {
PreparedStatement ps = connect.getConnection().prepareStatement(
"SELECT * FROM mbank.clients WHERE client_id = ?");
ps.setLong(1, client.getClient_id());
System.out.println(client.getClient_id());
System.out.println(client.getName());
System.out.println(client.getType());
System.out.println(client.getPhone());
System.out.println(client.getAddress());
System.out.println(client.getEmail());
System.out.println(client.getComment());
} catch (SQLException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null,
"Problem occurs while trying to see client details");
}
}
Well you're not actually executing the prepared statement... you're just preparing it. You should call PreparedStatement.executeQuery and use the ResultSet it returns:
// ...code as before...
try (ResultSet results = ps.executeQuery()) {
while (results.next()) {
// Use results.getInt etc
}
}
(You should use a try-with-resources statement to close the PreparedStatement too - or a manual try/finally block if you're not using Java 7.)
You need to do executeQuery on the preparedstatement to get a result set back of the query you performed.
You are simply not executing the query. Add a PreparedStatement.executeQuery() call. And fetch the results from the returned ResultSet.
For example:
PreparedStatement ps = connect.getConnection().prepareStatement("SELECT * FROM mbank.clients WHERE client_id = ?");
ps.setLong(1, client.getClient_id());
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String userid = rs.getString("id");
String username = rs.getString("name");
}
As #Jon Skeet pointed out, the declaration of ResultSet in Java 7 is updated to:
public interface ResultSet extends Wrapper, AutoCloseable
It is AutoClosable now, which means that you can and should use the try-with-resource pattern.
You can do the below.
PreparedStatement ps = connect.getConnection().prepareStatement(
"SELECT * FROM mbank.clients WHERE client_id = ?");
resultSet = ps.executeQuery();
while (resultSet.next()) {
String user = resultSet.getString("<COLUMN_1>");
String website = resultSet.getString("<COLUMN_2>");
String summary = resultSet.getString("<COLUMN_3>");
}

java.lang.OutOfMemoryError: Java heap space error when performing millions of queries

In my application, I need to perform millions of queries to MySQL database. The codes look as follows:
for (int i=0; i< num_rows ; i++) {
String query2="select id from mytable where x='"+ y.get(i) "'";
Statement stmt2 = Con0.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
ResultSet rs2 = stmt2.executeQuery(query2);
... // process result in rs2
rs2.close();
}
where num_rows is around 2 million. After 600k loops, java report an error and exit:
java.lang.OutOfMemoryError: Java heap space error.
What's wrong in my codes? How should I avoid such an error?
Thanks in advance!
Close your statements as well.
Statement is no good solution here. Try the following code:
PreparedStatement pre = Con0.prepareStatement("select id from mytable where x=?");
for (int i=0; i< num_rows ; i++) {
pre.setString(1, y.get(i));
ResultSet rs2 = pre.executeQuery();
... // process result in rs2
rs2.close();
pre.clearParameters();
}
pre.close();
I don't know if the answer accepted by you have solved your problem, since it doesn't change anything that could cause the problem.
The problem is when ResultSet is caching all the rows returned by the query, which can either be stored while you iterate through set, or prefetched. I've had similar problem with PostgreSQL JDBC driver, which ignored the cursor fetch size, when running in no-trasactional mode.
The JDBC driver should use cursors for such queries, so you should check driver's documentation about fetchSize parameter. As alternative, you can manage cursors yourself executing SQL command to create cursor and fetch next X rows.
Using a preparedStatement, since only the value of X changes in each loop, declared outside de loop should help. You're also, at least in the shown code, not closing the statement used, which might not help the garbage collector to free the used memory.
Assuming that you are using a single connection for all your queries, and assuming your code is more complicated than what you show us, it is critical that you ensure that each Statement and each ResultSet is closed when you are finished with it. This means that you need a try/finally block like this:
for (int i=0; i< num_rows ; i++) {
String query2="select id from mytable where x='"+ y.get(i) "'";
Statement stmt2 = Con0.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
ResultSet rs2 = null;
try {
rs2 = stmt2.executeQuery(query2);
... // process result in rs2
} finally {
try {
stmt2.close();
} catch (SQLException sqle) {
// complain to logs
}
try {
if (rs2 != null) { rs2.close(); }
} catch (SQLException sqle) {
}
}
}
If you do not aggressively and deterministically close all result set and statement objects, and if you do requests quickly enough, you will run out of memory.

Categories

Resources