hibernate with ltree native named query - java

I am trying to run PostgreSQL native query that contains ltree functions and operators.
Here's the definition:
#NamedNativeQuery(
name = "pathSegmentQuery",
query = "select ltree2text(okm_path) as okm_path, " +
" index(okm_path, text2ltree(:lastSegment)) + 2 <> nlevel(okm_path) as haschild, " +
" case " +
" when index(okm_path, text2ltree(:lastSegment)) + 1 <> nlevel(okm_path) " +
" then ltree2text(subpath(okm_path, index(okm_path, text2ltree(:lastSegment)) + 1, 1)) " +
" end as child " +
"from document " +
"where okm_path ~ :pathLike " +
"and " +
"index(okm_path, text2ltree(:path)) + 1 <> nlevel(okm_path) ",
resultSetMapping = "pathSegmentQueryRSMapping")
invoked like:
public List<PathSegment> getPathChildren(String path, String lastSegment) {
Query query = entityManager.createNamedQuery("pathSegmentQuery");
String pathLike = "'*." + path + ".*'";
query.setParameter("path", path);
query.setParameter("pathLike", pathLike);
query.setParameter("lastSegment", lastSegment);
return query.getResultList();
}
result is error ERROR: operator does not exist: ltree ~ character varying.
when I try to run the query directly against database it runs ok:
select ltree2text(okm_path) as okm_path,
index(okm_path, text2ltree('_root_')) + 2 <> nlevel(okm_path) as haschild,
case
when index(okm_path, text2ltree('_root_')) + 1 <> nlevel(okm_path)
then ltree2text(subpath(okm_path, index(okm_path, text2ltree('_root_')) + 1, 1))
end as child
from document
where
okm_path ~ '*._root_.*'
and
index(okm_path, text2ltree('_root_')) + 1 <> nlevel(okm_path)
from the error it's obvious that hibernate(?) dislikes the type on the right side of th ~ operator, but as you can see, I am using the string in the later query and works fine.
So what do I need to do with hibernate query to run the query successfully?
EDIT:
when I replace okm_path ~ :pathLike for "where okm_path ~ '*._root_.*' " I will be given:
org.postgresql.util.PSQLException: ERROR: syntax error at position 0 error
hibernate: 5.2.9.Final
postgresql: 9.2.23

it turned out that there is lquery() function that needs to be called when you do operations against lquery.
so my query translates to
...
where okm_path ~ lquery(:pathLike)
...
and this solves the problem

The error
operator does not exist: ltree ~ character varying
should be read as
operator does not exist: <left_data_type> <operator> <right_data_type> varying
Which means the operator is not defined for these data types. This happens when, for example, the left side of the operator is a integer and the right side a varchar, the error that time would be ERROR: operator does not exist: integer = character varying.
The problem here is when you set the value for right side,
query.setParameter("pathLike", pathLike)
pathLike is a string. So Postgres sees this as comparing a ltree to a string. When you execute the SQL directly the right hand side is taken as a ltree expression than a string.
I am not sure if this will work but can you try ltree can be directly cast to a varchar, but can you try this?:
query.setParameter("pathLike", pathLike, Hibernate.OBJECT)
See also Java type in JDBC to Postgres ltree

Related

Hibernate ERROR: operator does not exist: integer = bytea No operator matches the given name and argument types might need to add explicit type casts

While executing the following native query I am getting the above mentioned error.
I am using hibernate with postgresql database.
String query = "SELECT requester_id,operator_id,date(qr_gen_date_time) as date, sum(ticket_fare) as total_amount, count(*) as ticket_count "
+ "FROM ticket_info tktInfo INNER JOIN operator_info op on tktInfo.operator_info_id = op.id" + "INNER JOIN ticket tkt on op.ticket_id = tkt.id "
+ "WHERE (requester_id = :requesterId or :requesterId isNull) "
+ " AND (operator_id = :operatorId or :operatorId isNull) "
+ " AND (date(qr_gen_date_time) >= :dateFrom or :dateFrom isNull) "
+ " AND (date(qr_gen_date_time) <= :dateTo or :dateTo isNull) "
+ "GROUP BY date(qr_gen_date_time),requester_id,operator_id "
+ "ORDER BY date(qr_gen_date_time) DESC "
+ "LIMIT 10 OFFSET ( :pageNum -1 ) * 10 ";
List<Tuple> result= entityManager.createNativeQuery(query, Tuple.class)
.setParameter("requesterId", requesterId)
.setParameter("operatorId", operatorId)
.setParameter("dateFrom", dateFrom)
.setParameter("dateTo", dateTo)
.setParameter("pageNum", pageNum).getResultList();
Exception :
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: integer = bytea
Hint: No operator matches the given name and argument types. You might need to add explicit type casts.
Position: 282
When passing null for a parameter, Hibernate usually relies on inference in HQL to determine the type of the parameter. Since this is a native query though, Hibernate does not know the type of the parameter and in 5.6 by default chooses to bind such nulls with PreparedStatement#setBytes. The JDBC driver then assumes that this is of the type bytea and a predicate like operator_id = ? will compare an integer against a bytea in case you bind null.
In your particular case, the only way you can make this work is by specifying the type during parameter binding. You can do that through the org.hibernate.query.Query API which allows you to specify an optional third argument in setParameter/setParameterList, which represents the type of the value. Use StandardBasicTypes.INTEGER as argument and the query should work as intended.

JDBI query fails when <> is used

I have a JDBI query that is as simple as it can be
#Override
#SqlQuery("SELECT COUNT(*) FROM " + TABLE_NAME + " WHERE (" + COLUMN_MODERATOR_CATEGORY_ID
+ " in (<categories>) OR " + COLUMN_EXPERT_CATEGORY_ID
+ " in (<categories>)) AND (" + COLUMN_STATUS + " <> 0)")
long getIdeasCountInCategories(#BindIn("categories") List<Long> categories);
The <> 0 fails with a syntax error at the end of input.... It works as soon as I change it to > 0 (which also serves the purpose).
Using Java 1.8.0 and Postgres 9.6. Please let me know if any more info is needed.
If you absolutely can't change the SQL query (e.g. switch operator to != or >) then you need to escape < with preceding \\.

Creating function in MySQL version 5.7 through Java

This is my function:
query = "CREATE FUNCTION CheckSex(personID INT, G CHAR) " +
"RETURNS BIT " +
"BEGIN " +
"DECLARE Flag BIT; " +
"SET Flag = 1; " +
"If (G NOT IN (SELECT Sex FROM PERSONS WHERE ID = personID)) " +
"THEN SET Flag = 0; " +
"RETURN Flag; " +
"END";
pState = conn.prepareStatement(query);
pState.executeUpdate();
This is the error code:
check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
I have tried putting it into the mysql command line manually and I get an error after DECLARE Flag BIT;, also I have tried to change the delimiter which gave an error.
I have switched to an online compiler for now and this function works fine in MySql 2014 express written as follows
CREATE FUNCTION CheckSex(#personID AS INT, #G as CHAR)
RETURNS BIT
AS
BEGIN
DECLARE #Flag BIT = 1
If (#G NOT IN (SELECT Sex FROM PERSONS WHERE ID = #personID))
SET #Flag = 0
RETURN #FLAG
END;
Thank you for any feedback.

Spring data jpa failed to pass named parameters in native subquery for db2

Unable to pass named parameters in #NamedNativeQuery in spring data jpa
my repo:
#Query(value = "select stat.desc as desc," +
" stat.priority as priority," +
" (case when sum(activeUser) is null then 0 else sum(activeUser) end) as activeUser," +
" (case when sum(totalUser) is null then 0 else sum(totalUser) end) as totalUser" +
" from lookup.user stat left outer join" +
" (" +
" select user.role as role, " +
" sum (case when user.STATUS = 'ACTIVE' then 1 else 0 end) as activeUser," +
" count(*) as totalUser," +
" user.group as group" +
" from Ctrl.user user" +
" where user.group =:userGroup " +
" and user.branch_code =:branchCode " +
" group by user.role,user.group" +
" ) as tbl on stat.role = tbl.role and stat.group = tbl.group" +
" where stat.group =:userGroup " +
" group by stat.desc, stat.priority" +
"", nativeQuery = true)
public List<com.cimb.dto.UserStatusSummary> getSummaryReport(#Param(value = "userGroup") String userGroup, #Param(value = "branchCode") String branchCode);
The underlying database is DB2
When I tried to access that method I am hitting following error.
DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.25.13
if I hard code those named parameters with values then it's working.
I can not use jpql as real queries have some subqueries in it, so I cant use JPQL
Edit Update
After some digging, I have found out that, the parameters I am passing are in the subquery, since JPA don't have subquery concept it's not injecting into named parameters which resulting in a syntax error.
Now how to work with Subqueries in JPA
Please help.

Can I have multiple statements in a native query in JPA 2

I want to execute the following query to conditionally drop a temporary table.
String dropSql = "BEGIN EXECUTE IMMEDIATE 'DROP TABLE " + tmpTblName + "';" +
" EXCEPTION" +
" WHEN OTHERS THEN" +
" IF SQLCODE!=-942 THEN" +
" RAISE;" +
" END IF;" +
" END";
And then execute it as a native query like this:
JPA.em().createNativeQuery(dropSql)
.executeUpdate();
However, JPA will not let me or rather, the oracle db won't. Apparently the ; get escaped or misinterpreted somehow.
Caused by: java.sql.SQLException: ORA-06550: line 1, column 120:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
; <an identifier> <a double-quoted delimited-identifier>
The symbol ";" was substituted for "end-of-file" to continue.
Will I have to live with using separate queries to achieve my goal or is there some trick to this?
You missed a semicolon after the END block finally.
String dropSql = "BEGIN EXECUTE IMMEDIATE 'DROP TABLE " + tmpTblName + "';" +
" EXCEPTION" +
" WHEN OTHERS THEN" +
" IF SQLCODE!=-942 THEN" +
" RAISE;" +
" END IF;" +
" END;";

Categories