Hello guys I am having some problems with exact matches while doing a NamedQuery.
I am currently using something like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from Entry e where e.name =:"+ Entry.NAME )
...
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName());
It works for most cases, however I noticed that in case the user pass the file name with an space at the end, the namedQuery ignores that character. For example:
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName()+ " ");
Will return the same result as the query before. Bypassing my 'valid entry' validation. In other words I'd like the query to return no entry at all and treat the error later on.
One workaround I could think of, is to put single quotes surrounding my parameter in the namedQuery, like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from entry e where e.name =':"+ Entry.NAME "'")
However it will trash my code in case the String contains single quotes in it...
Any ideas guys?
I guess this happens because your database field is declared as CHAR(...), and therefore stored values are padded with whitespaces which are not taken into account by = operation.
So, you may either declare your database field as VARCHAR(...) or use a built-in trim function:
query = "select e from Entry e where trim(trailing from e.name) =:"+ Entry.NAME
I did some research in JPA and found out that it does some automatic trimming for CHARs, I am not sure if this behaves the same with Strings, but since it is happening to me... I believe so. The only way to bypass it is by setting some attribute within the session DatabaseLogin object (see http://www.eclipse.org/eclipselink/api/1.1/org/eclipse/persistence/sessions/DatabaseLogin.html#setShouldTrimStrings) .
Well I didn't want to be messing up with the session properties so I decided to make some sort of check and throwing the same exception as the NoResultException catch does in my code.
I basically took the result from the database and compared the field with the String I used:
query.setParameter(Entry.NAME, myEntry.getName());
...
if(!StringUtils.equals(result.getName(), myEntry.getName()){
do a cool throw just like NoResultException Catch
}
I also had to include the Trim function axtavt! This is just to make sure that if the database has a column with trailing spaces and it matches the parameter given by the user, it will be included as a valid answer. For example:
Database entry: Name = "Flavio " - Trimmed with Function = "Flavio".
Parameter passed: Name = "Flavio " - Trimmed by JPA automatic function = "Flavio".
If it isnt trimmed at all it will just Compare "Flavio " with "Flavio", returning NoResult when it was supposed to return that Entry.
Nasty workaround, but as long as there is no other way to stop the auto-trimming we will have to just make use of this sort of things.
Thanks for all the other answers!!
Related
I have a search functionality that is implemented on my current project, I am using HQL for the repo method - Everything is okay except searching for special characters for some reason HQL is not escaping it.
#Query("SELECT f FROM Item f WHERE f.id=:id AND f.itemNm LIKE %:itemNm %")
Item findByItemNm(#Param("itemNm ") String itemNm, #Param("id") Long id);
The String search I am sending is
abc_xyz(YYYYMM[t-2]-YYYYMM[t-1])_[xyz]HU.xlsx
Debugging Steps
Before sending to the Repo - I did replace all the special characters with the following -newsearchString is the one thatt is being passed to the repo
String newsearchString = searchString.replaceAll("(?=[]\\[+&|!(){}^\"~*?:\\\\_]) ", "/");
I have also tried it without replacing the special characters- It is not being returned
How do you escape characters in HQL?
Here is the solution for your problem...It should work for your need.
1) Find and replace all your escape characte, and replaced by "\\"
Example: [hi]_mysearch should be replaced like \\[hi\\]_mysearch
2) Change your repo query like below
#Query("SELECT f FROM Item f WHERE f.id=:id AND f.itemNm LIKE %:itemNm % escape '\\'")
Item findByItemNm(#Param("itemNm ") String itemNm, #Param("id") Long id);
HQL does not have regular expressions out of the box. You'd have to modify the Dialect for your specific database to add that functionality. (Oracle example)
If you're just trying use like with the % wildcard, then you can do the following:
String itemNm = "abc_xyz(YYYYMM[t-2]-YYYYMM[t-1])_[xyz]HU.xlsx";
Query q = session.createQuery("from Item where itemNm like :itemNm ";
q.setString("itemNm","%"+itemNm+"%");
I need to optimize a query that iterates over several objects and I wanted Spring Data to let the database handle it. I want to end up with a HashMap<String,String> that looks like
2134_9877, 9877
2134_2344, 2344
3298_9437, 9437
The SQL would be select convert(varchar,b.id)+'_'+convert(varchar,a.id)',a.id from t1 a join t2 b on a.jc = b.jc
So far, I've got Whatever-QL in the repository that looks like:
#Query("SELECT new map (a.bkey, a.akey) FROM mergeTable a WHERE a.discr= ?1")
The problem is, bkey is not unique, it is only unique when paired with akey and the monstrosity that I have to feed it to wants them combined with an underscore: 2345_2177.
I have tried a.bkey.toString and ''+a.bkey and new String(a.bkey) and just string(a.bkey) (that last gives a new exception but still doesn't work) but Spring doesn't like any of these. I can find no questions asking this and it seems I cannot use SQLServer's convert() function as this ain't SQL.
How can I concatenate the Integers as Strings with an underscore in this #Query?
PS: Using the native query that's been debugged in SQLServer throws some weird alias exception in Hibernate so I think 'going native' is predetermined to be a dead end.
If I have understood it right, the 'Whatever-QL' is called JPQL, and the operator CONCAT can be used. Only the use of it, as it accepts two or more parameters depends on the JPA version you are running.
Here is the answer.
JPA concat operator
You could add a getter to your entity like this:
public String getCombinedKey(){
return a.akey + "_" + a.bkey;
}
The advantage is you could handle here null's and other things if you want and it's more reusable in case you need this in another place. If you do it just in the repository you will have to copy it everytime.
Your query would then be:
#Query("SELECT new map (a.combinedKey, a.akey) FROM mergeTable a WHERE a.discr= ?1")
I'm having an issue with OpenJPA. I used it to persist values in MySQL DB. Amoung these values, there's a String value that has a spanish character (รก). The data was persisted correctly, with the special character being shown perfectly in the DB.
The problem comes when, within my Java program, I try to query the DB with one of the parameters having this special character. Here's an example:
private static final String getPerdiodoEstadoAfiliacionParaOS =
"SELECT x FROM PeriodoAfiliacion x WHERE " +
"x.obraSocial=?1 " +
"AND x.tipoPeriodoAfiliacion LIKE ?2";
public static List<PeriodoAfiliacion> getPerdiodoEstadoAfiliacionParaOS(EntityManager em, ObraSocial os, String periodoABuscar) {
if(os==null) return new ArrayList<PeriodoAfiliacion>();
Query query = em.createQuery(getPerdiodoEstadoAfiliacionParaOS);
query.setParameter(1, os);
query.setParameter(2, periodoABuscar);
return query.getResultList();
}
So, parameter number 2 (the one shown as ?2), it's a string with a special character in it.
The query comes back empty when there's actually data.
I know the problem is the special character, because if I pass as a parameter another String that doesn't have the special character in it, the query comes back with results as expected.
So, I don't know what the problem is really. I guess it has something to do with the way the parameter is passed from OpenJPA to the DB engine.
Do you guys have suggestions??
I just stumbled upon some SQL code of a colleague (we have a "dont fix it, if it aint broke policy"), for a login process.
The name variable is delivered by an input field from a JSP.
//BAD CODING ALERT: DONT USE THIS CRAPPY CODE, YOU NAUGHTY COPY PASTERS!
Query q = em.createQuery("select object(u) from User as u where u.name = '" + name + "'");
With no sanitation at all on the name variable except of server side validating on some Illegal characters: <>"'%;() (mind that that is single and double quotes)
Can this be exploited? And if yes, how so?
If it wasnt for the single and double quotes, one could do something like: blah' OR 'x'='x
You should NEVER EVER create query by string concatenation. use query.setParameter("paramName",paramValue);
so it would be something like that
Query q = em.createQuery("select object(u) from User as u where u.name =:name");
q.setParameter("name", "O'Reilly")
no SQLInjections possible because of escaping values;
Answering my own question... it is safe, however not practical as allready stated by myself.
Before downvoting this, READ the question. Or give an exploit example otherwise.
Given following Statment:
String query = "Select * from T_spareParts where SparePartPK IN (? )"
In my BackBean (JSF 2) I first iterate through all cars in table and build a String of all the cars currently selected (by picking each cars ID as primary key) so the final String before being passed to SQL could look like:
String finalString = " '1','2','3','4'";
And then :
this.prepareStatement= this.connection.prepareStatement(query);
this.prepareStatement.setString(1,finalString);
this.prepareStatement.executeQuery();
Exception thrown is:
Error converting data type nvarchar to bigint.
Now my understanding is that exception is due to SparePartPK is type bigint and we're passing a String .
But in SQL Server (2008) i can do :
Select * from T_spareParts where SparePartPK IN ('1','2','3','4')"
which returns results as expected. Why am i getting the exception and how can i correct the issue? (also feel free to comment if this isn't the best approach)
Update:
I've also tried to produce the finalString without single quotes which causes the same exception to be thrown :
String finalString = " 1,2,3,4";
You should put the numbers into an array (not a string), and use preparedStatement.setArray()
Thanks for the suggestions. Though as an alternative I created a StoredProcedure where it takes one parameter and inside the StoredProcedure i run the above Query in question formulating the IN section using the passed parameter .
So all above code still applies, The parameter passed to the storeDProcedure is one String separated by , without the single quotes.
Might not be the optimum answer but works quit well :) .