I am getting a parameter index out of range error when executing a prepared statement. I have several other statements working correctly. The only difference with this query is it's the only UPDATE. The rest are all INSERT, ADD, DELETE etc. Any guidance on what I may be doing wrong would be greatly appreciated.
sqlStatement = "UPDATE customer SET customerName = ?, addressId = ? WHERE customerId = ?;";
StatementHandler.setPreparedStatement(ConnectionHandler.connection, sqlStatement);
StatementHandler.getPreparedStatement().setString(1, name);
StatementHandler.getPreparedStatement().setInt(2, AddressDAO.getAddressId(address));
StatementHandler.getPreparedStatement().setInt(3, customerId);
StatementHandler.getPreparedStatement().executeUpdate();
Error:
java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 1).
I have put a couple print statement sin the middle of the code block and it seems to fail on the 3rd parameter. All values coming in are valid and match the types being assigned. MySQL is being used and the statement works fine if executed in the console.
Thank you for reading and any help you can provide.
Edit: Here is the statement handler method I am using as well. I am combing through to see what else I should add to help get this thing figured out. Thank you for the comments!
public class StatementHandler {
/**
* create statement reference
*/
private static PreparedStatement preparedStatement;
/**
* method to create statement object
*/
public static void setPreparedStatement(Connection connection, String sqlStatement) throws SQLException {
preparedStatement = connection.prepareStatement(sqlStatement);
}
/**
* getter to return statement object
*/
public static PreparedStatement getPreparedStatement(){
return preparedStatement;
}
}
Your snippet doesn't make it clear, but I can guess. I'll list a series of conclusions I'm drawing; you'd have to doublecheck these:
StatementHandler is a class (not a variable). (reason: You've capitalized it).
setPreparedStatement and getPreparedStatement are static methods in the StatementHandler class. (follows naturally).
You are using multiple threads (reason: That would be sufficient to explain this problem).
You aren't synchronizing (reason: Same as #3).
Then this result is obvious: You can't do that. Your entire VM has one global 'prepared statement' with multiple threads calling setPreparedStatement and getPreparedStatement in more or less arbitrary orders. One thread calls setPreparedStatement, then another thread does, then the first tries to get the prepared statement the other one set, and it all goes to hades in a handbasket.
You can't do it this way. Heck, you can't even share a connection between two threads (as they'd be getting in each other's way and messing up your transactions).
If you don't quite get what static does (And it is, admittedly, a bit of an advanced topic), don't ever use it. You can pretty much write all the java you'd ever want without using static methods. The one exception is public static void main which must be static, but just make that the one-liner: new MyClass().go();, with go() being a non-static method, and you're good to go.
I'd like to go one step further than rzwitserloot and presume that your AddressDAO uses StatementHandler, too.
The query for AddressDAO.getAddressId(address) has probably one parameter, which matches the 1 from the Exception, and replaces the prepredStatemt before setting the third parameter.
As proof it would be suffient assigning AddressDAO.getAddressId(address) to a variable(and use it afterwards) before setting the prepared statement.
Alternativly you can get once the prepared statement in a variable and use this variable afterwards.
Related
TL;DR: What's the recommended approach for reusing PreparedStatement objects in Java, without making a mess out of the code?
If I want to reuse them I have to define them all early in the code, and it becomes a mess.
If I don't create them until I need to, I can keep the code tidy and clean, but then I can't reuse the objects.
I have a method like this:
PreparedStatement psQuery = conn.prepareStatement("select ...");
PreparedStatement psChild = conn.prepareStatement("select ... where parent = ? and ...");
ResultSet rsQuery = psQuery.executeQuery();
while (rsQuery.next()) {
psChild.setInt(1, rsQuery.getInt("id"));
psChild.executeQuery();
...
}
I create two preparedStatement first, and then reuse them every time I need to execute those specific SQL queries. I don't define psChild inside my loop because then I'd be creating a new prepared statement in each iteration, instead of just reusing it.
Now, my code is much more complex. I'm actually using 13 different preparedStatement instances, and the code spreads through a few hundred lines. I'd very much like to split it into different methods, but I'm not sure how to properly do it. I can think of two options. The first one is like I'm doing it right now, only splitting into methods:
PreparedStatement psQuery = conn.prepareStatement("select ...");
PreparedStatement psChild = conn.prepareStatement("select ... where parent = ? and ...");
ResultSet rsQuery = psQuery.executeQuery();
while (rsQuery.next()) {
processChildren(rsQuery.getInt("id"), psChild);
}
The problem is, I end up with a processChildren with this signature:
private static void processChild(
...,
final PreparedStatement psFoo,
final PreparedStatement psBar,
final PreparedStatement psDoc,
final PreparedStatement psGrumpy,
final PreparedStatement psHappy,
final PreparedStatement psSleepy,
final PreparedStatement psDopey,
final PreparedStatement psBashful,
final PreparedStatement psSneezy,
final PreparedStatement psYetAnotherOne,
final PreparedStatement psAndAnotherOne,
final PreparedStatement psLastOne,
...) {
Not exactly great.
The other option would be to create each prepared statement in the method where I'll need it. That would be much cleaner, but it's the same as creating them inside the loop: I wouldn't be reusing them.
There is yet another option, to declare the variables as class attributes, this way I could create them first, and then reuse without the need to clutter the "children method" signatures. But this feels even more wrong, in the same way that using a global variable would. Worse, 13 "global" variables all of them with the same class and very similar names. No way I'm doing that!
How could I proceed?
Note: I'm aware of much better persistence solutions, such as JPA. I'm not looking for an alternative to prepared statements, I only want to know what's the usual approach in cases like mine.
Edit: It seems like I oversimplified my example. This is closer to what I need to do:
Retrieve all the records from database 1.
For each one of them (first loop):
Check if it exists in another database 2.
If it doesn't, create it in database 2, and:
Retrieve all children from database 1.
For each of the children (second loop):
Check if child exists in database 2.
If it doesn't, then insert it.
So I have two levels of nested loops which I can't get rid of. And creating the prepared statements over and over inside of the loops seems like a poor idea.
Abstract:
An application I work on uses top link, I'm having trouble finding out if and when top link automatically uses bind variables.
Problem Description:
Lets say I need to do something akin to validating if a vehicle full of people can travel somewhere, where each person could invalidate the trip, and provide error messages so the person could get their restrictions removed before the trip starts. A simple way to do that is to validate each member in the list, and display a list of errors. Lets say their info is stored on an oracle database and I query for each riders info using their unique ids, This query will be executed for each member in the list. A naïve implementation would cause a hard parse, a new execution path, despite only the unique id changing.
I've been reading about bind variables in sql, and how they allow for reuse of an execution path, avoiding cpu intensive hard parses.
A couple links on them are:
http://www.akadia.com/services/ora_bind_variables.html
https://oracle-base.com/articles/misc/literals-substitution-variables-and-bind-variables
An application I work on uses toplink and does something similar to the situation described above. I'm looking to make the validation faster, without changing the implementation much.
If I do something like the following:
Pseudo-code
public class userValidator{
private static DataReadQuery GET_USER_INFO;
static{
GET_USER_INFO = "select * from schema.userInfo ui where ui.id= #accountId"
GET_USER_INFO.bindAllParameters();
GET_USER_INFO.cacheStatement();
GET_USER_INFO.addArgument("accountId", String.class);
}
void validate(){
List<String> listOfUserAccountIds = getuserAccountIdList();
list args;
for(String userAccountId: listOfUserAccountIds){
args = new ArrayList(1);
args.add(userAccountId)
doSomethingWithInfo(getUnitOfWork().executequery(GET_USER_INFO, args);
}
}
}
The Question:
Will a new execution path be parsed for each execution of GET_USER_INFO?
What I have found:
If I understand the bindAllParameters function inside of the DatabaseQuery class well enough, it simple is a type validation to stop sql injection attacks.
There is also a shouldPrepare function inside the same class, however that seems to have to do more with allowing dynamic sql usage where the number of arguments is variable. A prepared DatabaseQuery has its sql written once with just the values of the variables changing based on the argument list passed in, which sounds like simple substitution and not bind variables.
So I'm at a lost.
This seems answered by the TopLink documentation
By default, TopLink enables parameterized SQL but not prepared
statement caching.
So prepared statements are used by default, just not cached. This means subsequent queries will have the added cost of re-preparing statements if not optimized by the driver. See this for more information on optimizations within TopLink
My question concerns precompiled SQL statements, created with SQLiteDatabase.compileStatement. In all examples I've seen first there is precompilation, next parameters are added, and next the statement is executed.
However I have impression that using precompiled statements makes sense if I precompile them once somewhere at the beggining and next I'm using previously precompiled statements many times only giving to them new parameters.
Thus the question. Is there any good practice, where (in what moment, what method of which class) to precompile those statements and how to execute them next.
I was wondering about extending SQLiteOpenHelper class (in fact I have to extend it always to cover onCreate and onUpdate methods) and to add to this firstly precompilation of all my sql statements in constructor and next to create my own methods to assure access to my database (=to bind parameters and next to execute statements).
Is that a good approach? If now, what is a good practice?
Just in order to clarify the situation, an example:
public class MySQLStatements
SQLiteDatabase db;
SQLiteStatement recordInsert;
public SQLDatabaseAndroid (SQLiteDatabase db){
this.db=db;
}
public void tableCreateExecute () {
db.execSQL ("CREATE TABLE....");
}
public long recordInsertExecute (par1, par2 etc....) {
// let's precompile sql statement if it hasn't been previously used
recordInsert = (recordInsert == null) ?
recordInsert = db.compileStatement(recordInsert()) : recordInsert;
and next sql part.
The part above is not fully correct java code but I believe it gives a good example what I want to achieve. Simply sql statement is pre-compiled only when used for the first time. Next it's kept for future use.
The question is what do you thinking about such a solution.
And another in what moment can I create MySQLStatements object? Can it be done in constructor of my class derived from SQLiteOpenHelper as last thing to be done? But then is that safe to get db by getWritableDatabase method. In methods onCreate, onUpdate can I skip the given db parameter and use previously got in constructor (by getWritableDatabase)?
In Java I would want to print out the query that is going to be submitted/queried on the database so that I can see whats the error when the query throws out exception.
It will be useful to exactly locate the issue instead of trying to understand Oracle Exception ID's and trying to match where exactly did it fail in the code. Any help please.
PreparedStatement ps = conn.prepareStatement("SELECT * FROM EMPLOYEES where EMPNAME=?");
ps.setString(1, "HULK");
ps.executeQuery();
Ideally I want to do a syso(ps) or syso(ps.getquery) and the output should be
SELECT * FROM EMPLOYEES WHERE EMPNAME='HULK'
or
SELECT * FROM EMPLOYEES WHERE EMPNAME=<HASHCODE OF THE OBJECT YOU ARE TRYING TO BIND>
Something interesting I ran across, Log4JDBC, which allows you to log SQL Calls. I haven't had a chance to use it yet, but I thought it was a great idea to be able to change the logging level and get the SQL calls into a log file.
This is more than you asked for, but I thought it might be worth throwing out there.
I think this is already been answered here.
Short answer: print toString() method or the PrepareStatement to see the query with the bind variables substituted with values.
BUT: It al depends of the implementor. Not all JDBC drivers add this nicety.
If your particular driver doesn't comply with this, then the only workaround would be composing the SQL by concatenating the values instead of using bind variables (losing the performance advantages the RDBMS gives you when using bind variables).
But for this you have to convert things to strings, etc.
This would be paradoxical, since I have found that concatenated SQLs are the most error prone and are the ones that need most printing and checking.
I can successfully connect to an oracle database and print out the list of all table names using the getAllTableNames() method.
My next Idea is to filter specific tables and display all of their columns.
I am running this query at the moment (I am including the entire method.)
static void getLengths(){
String query = "SELECT column_name from user_tab_columns where table_name = '<MytableName>'"
try{
ResultSet rs = db.runQuery(query);
System.out.println(rs):
} catch (Exception ex) {
System.out.println(ex);
//Seems to be successful
}
} //End of Method
In the System.out Window I am receiving this which makes me think I just need to view my result set somehow?
oracle.jdbc.driver.DcrollableResultSet#(different number everytime I run code)
Is my result set hiding somewhere? What is the best way to go about viewing it?
System.out.println(rs) just prints out the class name and handle of the ResultSet object. This is pretty useless.
You need to loop through the result set and read the appropriate fields. Generally you write something like:
ResultSet rs=db.runQuery(query) // I don't know where this function is coming from, but okay
while (rs.next())
{
String myColumn=rs.getString("column_name");
System.out.println(myColumn);
}
rs.close();
You might want to read up on JDBC in general, and look at the Java Docs for Connection, Statement, and ResultSet.
You have to iterate over your ResultSet to get the values.
Do something like that
while(rs.next()) {System.out.println(rs.getString("COLUMN_NAME"));}
ResultSet javadoc states
A table of data representing a database result set, which is usually generated by executing a statement that queries the database.
So, you'll have to use the appropriate getXXX(int index) methods where XXX is your equivalent Java Datatype. And don't forget to invoke next() before doing anything else!
Read Retrieving and Modifying Values from Result Sets to see an example of what you're trying to accomplish.
You will need to step through the result set, very rusty on my java, but you can probably call "toString()" on the resultset to at least show you what was returned although its not going to be very usable.
System.out.println(rs.toString())