I have the following code snippet:
It generates this SQL string:
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
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.
Nothing says that a literal in HQL or JPQL or Criteria needs to be a literal in SQL. You are simply making an assumption - which is fine. But an assumption or interpretation != what the spec says. Using a parameter at the SQL level is better and we will continue to do that if/when we can.
That said, as I mentioned on I already have code in place to allow users to configure this behavior. To me that is the ideal solution.