I'm in a migration process from javax to jakarta. Our project is build with Spring Boot (thus upgrade from 2.7 to 3.2) and Hibernate (5.6 to 6.3) and we use a PostgreSQL database (V14). One pitfall was the migration of a custom PostgreSQL dialect, but i suppose i solved satisfactory (-> implementation of a full text search condition)
The main issue arises when we perform a query:
SELECT o FROM Order o WHERE (o.createdAt between :from and :to) AND (:query is null OR function('pgTextSearch', :query, o) = true) AND (:createdBy is null OR LOWER(o.createdBy) = LOWER(:createdBy))
It says:
Caused by: org.postgresql.util.PSQLException: ERROR: function lower(bytea) does not exist
Hinweis: No function matches the given name and argument types. You might need to add explicit type casts.
So far as i know, this comes from an invocation of the lower() function with 'null' as parameter. :createdBy is declared as string (resp. varchar). In my scenarion :createdBy is null, but this should be intercepted by the first OR condition. What am i missing?
Additionally, i executed the query with replaced parameters through PostgreSQL-CLI without issues.
P.S. The query was modified for migration, but only within the custom function part.
P.P.S. I read the migration guides for spring boot and hibernate (SQM yikes!), but could not find any overlap to my use case.
P.P.P.S. I'm not setting the parameter by hand (e.g. .setParameter("createdBy", xyz)), the repository is a JpaRepository, thus parameter replacement is done by Spring Data
Short story
You are hitting, more than 10 years old bug:
Long story
I. Hibernate, since v6, does have an API which allows to overcome such issues, for example:
unfortunately, you are using
spring-data-jpa, and Spring team have not yet adopted new features of Hibernate v6 - here I would suggest to file a corresponding bug/cr.II. It seems the main problem for particular query is following:
:createdByparameter occurs two times in:createdBy is null OR LOWER(o.createdBy) = LOWER(:createdBy)clause, and there is definitely no option to infer correct sql type from:createdBy is nullexpression, however, technically, it should be possible to infervarcharsql type fromLOWER(o.createdBy) = LOWER(:createdBy)expression, the problem is Hibernate is trying to infer sql type of query parameter only once, so you are getting weirdbyteainstead ofvarchar(here I have no idea why do not set default to something more common instead ofbytea).Could you try to flip
:createdBy is nullandLOWER(o.createdBy) = LOWER(:createdBy)expressions? I suspect it may fix the issue.III. idiomatic way to write such "universal" queries is to use
SpELor JPA specifications, please check Hibernate randomly throws error: Cannot coerce value[][java.util.ArrayList] as Long