简体   繁体   中英

hibernate with ltree native named query

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

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

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 technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM