Reputation: 537
I am writing some code in SQL using the PreparedStatement
to help with SQL injection.
Example:
stm = c.prepareStatement("UPDATE "
+ listResults.get(i).get(TemplateFile.TYPEOFPLAY).toLowerCase()
+ " SET score=? WHERE player_name_fkey=? AND school_name_fkey=? AND tournament_number=?;");
stm.setInt(1, Utilities.readNumber(listResults.get(i).get(TemplateFile.TOURNAMENT + j - 1)));
stm.setString(2, listResults.get(i).get(TemplateFile.NAME));
stm.setString(3, listResults.get(i).get(TemplateFile.SCHOOL_NAME));
stm.setInt(4, j);
My question is the following: is there a way to get the PreparedStatement object to allow parameters (the ? sign) to be used for database names and columns. For example:
stm = c.prepareStatement("UPDATE ? SET score=? WHERE player_name_fkey=? AND school_name_fkey=? AND tournament_number=?;");
stm.setString(1, listResults.get(i).get(TemplateFile.TYPEOFPLAY).toLowerCase());
stm.setInt(2, Utilities.readNumber(listResults.get(i).get(TemplateFile.TOURNAMENT + j - 1)));
stm.setString(3, listResults.get(i).get(TemplateFile.NAME));
stm.setString(4, listResults.get(i).get(TemplateFile.SCHOOL_NAME));
stm.setInt(5, j);
It would look so much better and be easier to read as well.
Thanks in advance for any help!
Upvotes: 0
Views: 268
Reputation: 29349
you cannot do that. You can only bind column values on PreparedStatement. If you are not getting the table name from end user you can the following
String query = "UPDATE <tablename> SET score=? WHERE player_name_fkey=? AND school_name_fkey=? AND tournament_number=?";
query.replace("<tablename>", listResults.get(i).get(TemplateFile.TYPEOFPLAY).toLowerCase())
c.prepareStatement(query);
If you are getting the table name from enduser, then have a whitelist of table names and check your input with the whitelist
Upvotes: 1
Reputation: 73558
No, PreparedStatement
parametrizes only the column values, nothing else.
Setting the table name dynamically might be indicative of a design issue, since normally you would hardcode it just like the column names, joins etc.
Upvotes: 1
Reputation: 6450
This kind of coding is a bit dated now, albeit it "works". Have you considered using an ORM - Object/Relational Mapper - like iBatis or Hibernate? Appreciate it's a more "big commitment" change than you're perhaps looking to take on, but to use one of their own examples, with a bit of XML to contain the SQL, you get to look after fairly plain-text SQL:
<select id="getProduct" parameterClass="java.lang.Long" resultClass="com.example.Product">
select PROD_ID as id,
PROD_DESC as description
from PRODUCT
where PROD_ID = #value#
</select>
And invoke code to specify that "#value#" token:
Product resultProduct = (Product) sqlMapClient.queryForObject("getProduct", 123);
As I check links, the Java route here is maintained - actively - at:
but I'm leaving the original Wiki example as I think it's a clearer illustration.
FWIW I've been a big user of this, and found it excellent to work with. The ability to properly maintain clear, formatted, plain-text SQL is tremendous.
Taken from: https://en.wikipedia.org/wiki/IBATIS#Usage
Upvotes: 1