I am trying to select some data using Hibernate
The query ends up as follows
"select mystuff from mytable where upper(mystuff)=upper('a''c')"
( a'c is comming from user input escaped by StringEscapeUtils.escapeSql())
Hibernate is giving me a SQLGrammarException. Did I escape that single quote wrong?
I think '' to escape ' is good. I suppose that Hibernate + some RDBMS can have some mistakes with those quotes escaping. You should try to use preparedStatement or Query interface of Hibernate. To inject you data with method like this :
String selectSQL = "select mystuff from mytable where upper(mystuff)=upper(?)";
PreparedStatement preparedStatement = dbConnection.prepareStatement(selectSQL);
preparedStatement.setString(1, "a'c");
ResultSet rs = preparedStatement.executeQuery(selectSQL);
while (rs.next()) {
String mystuff = rs.getString("mystuff");
}
Or like this :
Query query = session.createQuery("from mytable where upper(mystuff)=upper(:mystuff)");
query.setString("mystuff", "a'c");
List<?> list = query.list();
So hibernate will be able to handle it.
Hope it helps :)
Related
Am I missing an error with the following to insert into a table with four columns, message_id (auto-incremented) message_sender, message_reciever, message_body. I have checked similar questions and haven't found the solution.
'''
<% String sender_id = request.getParameter("message_sender");
String reciever_id = request.getParameter("message_reciever");
String message = request.getParameter("message_body");
try{
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/fyp", "root", "Kmd116352323!");
Statement st = con.createStatement();
st.executeUpdate("INSERT INTO messages(message_sender,message_reciever,message_body) VALUES('"+sender_id+", "+reciever_id+" , "+message+" ')");
out.println("Your request has been noted."
+ " Please return to your user profile or log out");
} catch(Exception e){
out.println(e);
}
%>
You should not concatenate values into a query string. It makes your code vulnerable to SQL injection, or mistakes like forgetting quotes around values. The specific problem in your case is that you have a quote before the first value and a quote after the last value, which makes it a single value instead of three separate values.
However, instead of fixing the immediate problem by adding those missing quotes, you should switch to using a prepared statement:
try (PreparedStatement pstmt = connection.prepareStatement(
"INSERT INTO messages(message_sender,message_reciever,message_body) VALUES(?, ?, ?)") {
pstmt.setString(1, sender_id);
pstmt.setString(2, reciever_id);
pstmt.setString(3, message);
pstmt.executeUpdate();
}
As an aside, you really should not put data access in a JSP. It belongs in a DAO or service class.
This is incorrect:
VALUES('"+sender_id+", "+reciever_id+" , "+message+" ')
You have a ' wrapping the all the values... Which means sql will think you are only sending 1 value. If they are all text values it should be like this:
VALUES('"+sender_id+"', '"+reciever_id+"' , '"+message+"')
If you know some of the values are of INT type then you do not need the ' for that value:
VALUES("+sender_id+", "+reciever_id+" , '"+message+"')
Text values need to be wrapped with a '
I've read Give me Parameterized SQL or give me death numerous times.
The advantage of Parameterized SQL for Strings, Dates, and floating-point numbers is very obvious and indisputable.
My question is: what about ints?
I ask because, oftentimes, if I'm writing a query or update and the only parameter is an int, I'll just write an inline sql and append the int as a shortcut ("select * from table where id = " + id).
My question: Are there any advantages to using Parameterized SQL for ints alone?
To illustrate with Java:
Are there any advantage to this:
Connection conn;
int id;
String sql = "select * from table where id = ?";
try (PreparedStatement p_stmt = conn.prepareStatement(sql)) {
p_stmt.setInt(1, id);
ResultSet results = p_stmt.executeQuery();
// ...
} catch (SQLException e) {
// ...
}
over this:
Connection conn;
int id;
String sql = "select * from table where id = " + id;
try (Statement stmt = conn.createStatement()) {
ResultSet results = stmt.executeQuery(sql);
// ...
} catch (SQLException e) {
// ...
}
I would say the biggest advantage would be consistency. If you decide that all SQL built by string concatenation is "wrong", it's easier to verify that your code is "right", compared to a rule like "All SQL built by string concatenation is wrong, except that which deals with ints as parameters".
Another case, say: down the line, you want to introduce sorting or grouping to the query, suddenly, your line turns into something like this:
String sql = "select * from table where id = " + id + " order by somecolumn";
And hopefully you remembered the space before order. And that everyone after you does also.
There is much to be said for doing things only one way, especially when that one way is the right thing most of the time.
I am trying to create a generalized UPDATE-statement like this, where only the table-name is fixed.
updateValueQuery = conn.prepareStatement("UPDATE TABLENAME SET (?)=(?)");
That fails with an SQLException complaining about syntax. As soon as I specify the column-name like this:
updateValueQuery = conn.prepareStatement("UPDATE TABLENAME SET COL_NAME=(?)");
SQL happily compiles. Is there any way to make the columnname anonymous as well?
I am using Apache derby.
No, PreparedStatement has holders for values only.
I resolved similar problem in following way:
private final String FIND_STRING = "select * from TABLENANE where {0} = ?";
.
.
.
private final Map<String, PreparedStatement> statements = new HashMap<String, PreparedStatement>();
private PreparedStatement prepareStatement(String field, String toFind) throws SQLException{
PreparedStatement statement = null;
if (statements.contains(field)){
statement = statements.get(field);
}else{
String findInHelpDefinition = MessageFormat.format(FIND_STRING, field));
statement = connection.prepareStatement(findInHelpDefinition);
statemnts.put(field, statement);
}
statement.setString(1, toFind);
return statement;
}
I have below a segment of the code I have. Please see:
Workload workload;
ArrayList<Workload> workList = null;
System.out.print("first");
try{
System.out.print("first");
ConnectionFactory myFactory = ConnectionFactory.getFactory();
Connection conn = myFactory.getConnection();
int i = 0;
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM WORKLOAD WHERE datestart LIKE '? %'");
PreparedStatement pstmtMember = conn.prepareStatement("SELECT * FROM MEMBER WHERE memberid = ? and deletestatus = 0");
PreparedStatement pstmtLeader = conn.prepareStatement("SELECT * FROM LEADER WHERE leaderid = ? and deletestatus = 0");
pstmt.setString(i++, startdate);
ResultSet rs = pstmt.executeQuery();
workList = new ArrayList<Workload>();
My problem with the code is that it "goes out" once it reaches the pstmt.setString part.
The reason why i put a LIKE '? %' is because I needed to get only the date in from the query. Not the whole time stamp. Basically it disregards what comes after putting a date like '2012-04-05'.
You can't put the single quotes around it like that you can only treat the ? like it was a variable written in a procedure
Like '#yourVar %'
That is the equivalent of what you wrote.
The following will only work if the date is stored in a character field
String startDateWithPercent = startdate + " %"
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM WORKLOAD WHERE datestart LIKE ?");
pstmt.setString(i++, startDateWithPercent);
If the datatype on datestart in the database is datetime you will need to do something like this respective to your database platform (this is sql server). Only replacing that individual prepareStatement line.
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM WORKLOAD WHERE CONVERT(datestart,DATE) LIKE ?");
I have the following parametrised JPA, or Hibernate, query:
SELECT entity FROM Entity entity WHERE name IN (?)
I want to pass the parameter as an ArrayList<String>, is this possible? Hibernate current tells me, that
java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String
Is this possible at all?
ANSWER: Collections as parameters only work with named parameters like ":name", not with JDBC style parameters like "?".
Are you using Hibernate's Query object, or JPA? For JPA, it should work fine:
String jpql = "from A where name in (:names)";
Query q = em.createQuery(jpql);
q.setParameter("names", l);
For Hibernate's, you'll need to use the setParameterList:
String hql = "from A where name in (:names)";
Query q = s.createQuery(hql);
q.setParameterList("names", l);
in HQL you can use query parameter and set Collection with setParameterList method.
Query q = session.createQuery("SELECT entity FROM Entity entity WHERE name IN (:names)");
q.setParameterList("names", names);
Leaving out the parenthesis and simply calling 'setParameter' now works with at least Hibernate.
String jpql = "from A where name in :names";
Query q = em.createQuery(jpql);
q.setParameter("names", l);
Using pure JPA with Hibernate 5.0.2.Final as the actual provider the following seems to work with positional parameters as well:
Entity.java:
#Entity
#NamedQueries({
#NamedQuery(name = "byAttributes", query = "select e from Entity e where e.attribute in (?1)") })
public class Entity {
#Column(name = "attribute")
private String attribute;
}
Dao.java:
public class Dao {
public List<Entity> findByAttributes(Set<String> attributes) {
Query query = em.createNamedQuery("byAttributes");
query.setParameter(1, attributes);
List<Entity> entities = query.getResultList();
return entities;
}
}
query.setParameterList("name", new String[] { "Ron", "Som", "Roxi"}); fixed my issue