I have the following code snippet:
{{CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<String> q = cb.createQuery(String.class); Root<JPABook> from = q.from(JPABook.class); q.select(cb.<String>selectCase() .when(cb.equal(from.get("title"), cb.literal("Animal Farm")), cb.literal("Animal Farm")) .otherwise(cb.nullLiteral(String.class))); em.createQuery(q).getResultList();}}
It generates this SQL string:
{{ select case when jpabook0_.title=? then 'Animal Farm' else cast(null as varchar(255)) end as col_0_0_ from t_book jpabook0_ }}
As you can see, the literal in the CASE expression's predicate is sent to the server as a bind variable, whereas the literal in the THEN clause is sent as a literal.
I personally believe that the latter is correct because the intention of using {{CriteriaBuilder.literal()}} is for an actual literal to make it into the generated SQL string. Because if users wanted a parameter, they could have used {{CriteriaBuilder.parameter()}} instead. What's the point of {{literal()}} if it still generates a parameter.
I've already had this discussion with Vlad Mihalcea on Twitter: https://twitter.com/lukaseder/status/869209243282530304
Even if you might not agree with the above, I think the behaviour of all {{CriteriaBuilder.literal()}} calls should be consistent, so:
- Either generate only actual literals in generated SQL (properly escaping them of course!) - Or generate only bind variables in generated SQL
Side-note: try using a Java string containing an apostrophe instead in both places: {{"This isn't working"}} and see what happens...
Related issue: https://hibernate.atlassian.net/browse/HHH-9576 |
|