OpenJpa how to find length of string in JPQL - jpa

I am using
length(ze.string)>2 in openJpa query. but i am getting
SQLCODE=-440, SQLSTATE=42884, SQLERRMC=CHAR_LENGTH;FUNCTION, DRIVER=3.53.95 {prepstmnt 1776269692 SELECT t0.f1, t0.f2, t0.f3, t0.f4, t0.f5, t0.f6, t0.f7, t0.f8, t0.f9, t0.f10, t0.f11, t0.f12, t0.f13, t0.f14, t0.f15, t0.f16, t0.f17 FROM table t0 WHERE (t0.f1 = ? AND CHAR_LENGTH(?) > ? AND .....
In plain query when i do length operation i am getting record but using jpa its not working. I looked Here used size it doesn't work. and the field is varchar and db2. trying from past 1 hour.

DB2 requires use of the SQL function LENGTH, yet OpenJPA seems to be incorrectly converting your JPQL to use SQL function CHAR_LENGTH (hence the error message - not that DB2 gives out clear messages saying what is wrong, who knows what SQLCODE=-440 is without having to search!!).
Raise a bug on your JPA provider.
See https://www.ibm.com/support/knowledgecenter/SSEPGG_9.7.0/com.ibm.db2.luw.sql.ref.doc/doc/r0000818.html

You would need to give more details about your entity, persistence.xml, and query to get to the bottom or this. However, I do not see how OpenJPA would use CHAR_LENGTH instead of LENGTH for DB2. Let me explain. If you look at DBDictionary here:
https://svn.apache.org/viewvc/openjpa/branches/2.2.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?view=markup
You can see it defines something called "stringLengthFunction" as follows:
public String stringLengthFunction = "CHAR_LENGTH({0})";
This is the string length function which should be used for each individual dictionary (i.e. Database config). However, for DB2, the AbstractDB2Dictionary, see here:
https://svn.apache.org/viewvc/openjpa/branches/2.2.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java?view=markup
overrides this as follows:
stringLengthFunction = "LENGTH({0})";
Given this, for DB2, LENGTH should be used. I took the following simple query:
"select me.id from MyEntity me where length(me.name)>2"
And executed it on OpenJPA using DB2, and I got this:
SELECT t0.ID FROM MYENTITY t0 WHERE (CAST(LENGTH(t0.ID) AS BIGINT) > CAST(? AS BIGINT)) [params=(long) 2]
Thanks,
Heath Thomann

Related

Why does Spring JPA #Query return an error when I omit the table alias?

I'm querying a PostgreSQL table with a very simple query using Spring Data JPA:
#Query(value = "SELECT id FROM location l", nativeQuery = true)
This works fine. However, if I omit the table alias and use:
#Query(value = "SELECT id FROM location", nativeQuery = true)
I get an error saying No Dialect mapping for JDBC type: 1111. ID is a UUID in both PostgreSQL and the DTO.
Why does this happen? As far as I can tell, that's a perfectly valid query, and I'm not even using the table alias in the working version. Adding #Type and #TypeMappings made no difference. I checked the data I'm querying, and all the IDs are valid.
I'm happy to use an alias now that I've figured this out, but I'm curious about what's happening behind the scenes that causes this to fail.
Spring Data JPA tries to parse your query in order to derive a count query or add/modify and ORDER BY clause.
This to some extend relies on having an alias for the main table/entity of the query.
It should give you a proper error that it can't find an alias instead of the weird error you are seeing.

Postgres JSONB Check if JSON contains string using JPA

I have a jsonb column in my posgtgres table the json is of structure : {'alias':["name1","name2","name"....]}
I have written the Postgres query to check if the array in the JSON object contains the name.
select * from public.table t where json_col->'alias' ? 'name'
this works on pgAdmin
But same doesn't work in JPA
My code
#Query(value = "select * from public.table t where json_col->'alias' ? :name" ,nativeQuery = true)
Table findUsingName(#Param("name") String name);
This throws an error : 'Mixing of ? parameters and other forms like ?1 is not supported!'
I understand this error is due to the fact ? is also used by JPA is different sense...
Can anyone help me in the JPA Query
I don't know what the ? operator does, but you should use the named variant of the operator as a ? in JDBC is used to define a parameter.
Found the postgres function for '?' i.e. jsonb_exists_any(company_alias->'alias',ARRAY[:name])

Replace-function via EclipseLink on DB2 z/OS

I am migrating an application from JPA 2.0 with OpenJPA on WebSphere 8.5 to JPA 2.1 with EclipseLink on WebSphere 9.0, using DB2 12 on z/OS. Generally it is working, but one rather complex query is failing. I could localize the problem to the usage of a custom DB2-function call within a criteria-query. The call looks something like this:
criteriaBuilder.function("REPLACE", String.class, fromMyEntity.get("myField"), criteriaBuilder.literal("a"), criteriaBuilder.literal("b"));
This produces the following error (had to translate some error texts, since WebSphere localizes them, and anonymize my field/table names, so labels/names might not be 100% exact):
Error: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.3.WAS-v20160414-bd51c70): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.ibm.websphere.ce.cm.StaleConnectionException: DB2 SQL Error: SQLCODE=-171, SQLSTATE=42815, SQLERRMC=2;REPLACE, DRIVER=3.72.44
Errorcode: -171
Call: SELECT COUNT(ID) FROM MY_TABLE WHERE REPLACE(MYFIELD, ?, ?) LIKE ?
bind => [abc, def, %g%]
Query: ReportQuery(referenceClass=MyEntity sql="SELECT COUNT(ID) FROM MY_TABLE WHERE REPLACE(MYFIELD, ?, ?) LIKE ?").
What really confuses me, if I take the generated query, replace the placeholders with the given bound parameters, and execute that in a database client myself, it works without error.
The documentation states, the first parameter must not be empty (https://www.ibm.com/support/knowledgecenter/en/SSEPEK_12.0.0/sqlref/src/tpc/db2z_bif_replace.html), and indeed if I use an empty string either as a literal in the query or in my database client, it will produce the above error. But none of the rows in the database contain an empty value. There are checks in place to prevent this in the old environment, but they don't appear to work with the new environment, so I disabled them while searching for the problem, and made sure myself no empty values exist. I can even use the primary key as the first parameter, and it will still fail, and that can't even contain an empty/null value.
Using other functions (like TRANSLATE) works, I also tried using "SYSIBM.REPLACE" as name, and different combinations of parameters, but as soon as I use a real column to replace data in, it fails. Anybody got any ideas what I am doing wrong here?
This is my table definition:
CREATE TABLE "MY_TABLE" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (NO MINVALUE NO MAXVALUE NO CYCLE CACHE 20 NO ORDER ),
"MYFIELD" VARCHAR(160) FOR MIXED DATA WITH DEFAULT NULL,
[....]
) IN "<Database>"."<Tablespace>" PARTITION BY SIZE EVERY 4 G AUDIT NONE DATA CAPTURE NONE CCSID UNICODE;

Casting Integer to String in JPQL

I want to have a JPQL query that may look like:
entityManager.createQuery("Select a.* from A a WHERE CAST(a.num AS TEXT) LIKE '%345%' ", A.class);
where a.num is an integer. I want to cast this to String to use the LIKE criteria.
However above casting doesnt work in JPQL. Any idea about how can I implement this?
Could you be more specific, what your problem is? Do you have some kind of error or it the result of the query is just wrong?
Because this code works fine for me:
session.createQuery("from MyObject where CAST(id as text) like :id").setParameter("id", "%1").getResultList();
I am using Hibernate 5.2 and Postgresql 9.5.
Also, if you are having trouble understanding what goes wrong, you could try editing hibernate.cfg.xml or whatever configuration file you are using to make Hibernate show queries it sends, by doing something like this:
<property name="hibernate.show_sql">true</property>
I also have the same need. This should work with JPA 2.0 and Hibernate 5.0.2:
entityManager.createQuery(
"Select a.* from A a WHERE CONCAT(a.num, '') LIKE '%345%' ", A.class);
From hibernate document, "cast(... as ...)", where the second argument is the name of a Hibernate type. According list of Hibernate Types it should be string (case sensitive!).
So request should be:
entityManager.createQuery("select a.* from A a WHERE CAST(a.num AS string) LIKE '%345%' ", A.class);
Was taken and checked from Caused by: org.hibernate.QueryException: Could not resolve requested type for CAST : INT answer.
You can simply use CAST(num as string). It worked for me
Well you can use to_char() function in the select clause but, you will need to select all the a.num field separately and not with *.
And in postgresql you will need to specify a mask for to_char()function, so it would be to_char(field, mask), for example we can supply 'FM999999999999999999' as a mask to accept the maximum possible digits.
Your query would be something like this:
Select *, to_char(a.num, 'FM999999999999999999') as num from A a WHERE num LIKE '%345%'
You can take a look at Postgresql Data Type Formatting Functions for further details.
To write the query in your code with EntityManager you can create a native query using .createNativeQuery() method, this is how should be your code:
em.createNativeQuery("Select *, to_char(a.num, 'FM999999999999999999') as num from A a WHERE num LIKE '%345%'");
The correct query is :
entityManager.createQuery("Select a.* from A a WHERE CAST(a.num AS String) LIKE '%345%' ", A.class);

PostgreSQL function round and JPA/Hibernate

I have a query which is executed from java application like this:
Query query = getEntityManager().createQuery(hql);
The query looks like this:
String hql = "select * from table a where round(column1, 3) = round(parameter, 3)";
Here column1 is of type Double. The value it holds is like 143.02856666. I need to retain the value as it is, but for some business logic just need to round and compare.
The initial database configured was H2 and this worked fine. Now the database has been changed to Postgres and this query now errors out.
ERROR: function round(double precision, integer) does not exist Hint: No function matches the given name and argument types. You might
need to add explicit type casts.
The round() function in Postgres takes a numeric datatype and needs a cast.
The below query works fine if executed directly in Postgres console.
select * from table a where round(cast(column1 as numeric), 3) = round(cast(parameter as numeric), 3);
The same from java application errors out.
java.lang.IllegalArgumentException: org.hibernate.QueryException: Could not resolve requested type for CAST : numeric
Also tried Query query = getEntityManager().createNativeQuery(hql);
This results in a new error.
org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ERROR: syntax error at or near "where"
If I debug, this errors out when the below line is executed.
List resultList = query.getResultList();
How do I rewrite the query so that it works against Postgres ?
What you are doing with Query query = getEntityManager().createQuery(hql); is calling a jpql-query, which does not support all db-functions like round(v numeric, s integer).
Two Suggestions:
Use BETWEEN and maintain jpql-mapping
Write a NativeQuery -> Query query = em.createNativeQuery(queryString);
Your queryString just has to be altered by your parameters.