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 |