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??
Related
I have this column in a MySQL table which has a JSON string and I'm trying to pull records using regex.
For example, the column 'paylod' (datatype long text) holds this value
{
"type":"assignment",
"location":"12345"
}
I'm using RLIKE to fetch records based on location.
select * from table where payload RLIKE '"location":"[[:<:]]12345[[:>:]]"';
When using this query in java, I'm using prepared statement.
String pattern = "\"location\":\"[[:<:]]12345[[:>:]]\""
And when I use preparedStatement.setString(payload, pattern), I'm not getting any results back. But when I execute the query in workbench, I see the rows fetched.
I'm guessing it's because I'm using setString, it is wrapping pattern with double quotes and MySQL is not able to parse it.
So is there a way forward? My requirement is to get records based on key-value pair in the JSOn payload column.
Alright, adding escape character in string helped.
String pattern = "'\"location'\":'\"[[:<:]]12345[[:>:]]'\"";
String patternValue = pattern.replaceAll("'","\\\\");
So the string becomes \"location\":\"[[:<:]]12345[[:>:]]\" where \ serves as escape character for " in mysql, when string is wrapped inside ""
I have a code that should retrieve some data from a view on Oracle Database (using mybatis).
It's a dynamic query which receives one parameter
silly code example:
//Repo Class
#Select("select surname, name from vw_example where name=#{name}")
#Results({
#Result(property = "surname", column = "surname"),
#Result(property = "name", column = "name"),
})
public List<Result> getSurname(#Param("name") String id)
//Test Class
#Autowired RepoClass repo;
#Test
public void testGetSurname(){
List<Result> result = repo.getSurname("Danilo");
AssertThat(result.size(),is(2));
}
Important thing (In the database I'm working on, the column for name is a CHAR[40] (Please don't ask why.. but I can't change it).
Considering that there are 2 records which contains "Danilo" as value for column "Name" in the Database, it should return 2 rows for me and Map to object "Result".
However, it's not happening. The Assert comes with actual: 0
Now, the crazy thing...
If I change this:
#Select("select surname, name from vw_example where name=#{name}")
to this:
#Select("select surname, name from vw_example where name='Danilo'")
It works like a charm!!
Info:
(I already tried passing the jdbcType (#{name,jdbcType=CHAR))
(It seems the parameter is being replaced, because I replaced the Select statement for a Insert with the parameter value and it goes fine)
Could someone help with this crazy thing?
Thank you
As the column is declared as CHAR(40), the data in the DB is padded with spaces.
Option 1 : add spaces in Java code.
List<Result> result = repo.getSurname(String.format("%-40s", "Danilo"));
Option 2 : cast the parameter in the query.
select surname, name from vw_example where name = cast(#{name} as char(40))
The literal version of the query works because blank-padded comparison semantics is used, I guess.
With blank-padded semantics, if the two values have different lengths, then Oracle first adds blanks to the end of the shorter one so their lengths are equal. (snip) If two values have no differing characters, then they are considered equal. This rule means that two values are equal if they differ only in the number of trailing blanks. Oracle uses blank-padded comparison semantics only when both values in the comparison are either expressions of datatype CHAR, NCHAR, text literals, or values returned by the USER function.
I want remove upper function used in hql and make in upper at java side. following is the query:-
String hql = "SELECT addType FROM addrDO WHERE **UPPER**(id.address) = **UPPER**('"+ address +"')";
I want use toUpperCase() java funtion instead of using UPPER in query, like "id.address".toUpperCase() and address.toUpperCase() at java side and now query should be like
String hql = "SELECT addType FROM addrDO WHERE id.address = address;
Will above work any side effect.
The first query uses the UPPER function to implement a case insensitive comparison in the WHERE clause, the second uses case sensitive comparison.
Because the comparison has to be done in the database, you cannot replace it with Java's toUpperCase in the application layer.
You are trying to generate a dynamic query, which would finally be executed by a database server and not in JVM, thus you need to abide by the grammar of database server.
If you want to use java's toUpperCase method, better break your query and have something like
String idAddress = "id.address";
String address = "'\"+ address +\"'";
String hql = "SELECT addType FROM addrDO WHERE "+ idAddress.toUpperCase() +" = " + address.toUpperCase() + ";";
which is not suggestible, as you are unnecessarily using up jvm's memory
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 :) .
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!!