A predicate with a String literal criteriaBuilder.equal(from.get("name"), "horse"); creates a bind parameter: name=aram. Fine!
A predicate with a numeric literal criteriaBuilder.equal(from.get("age"), Integer.valueOf(42)); does not create a bind parameter: age=42. Not fine!
The concern here is that the fact that literals are used in the JDBC query rather than bind variables (parameters) a PreparedStatement cannot be effectively cached.
I think caused this issue.
I think that SQLi is not really related to this discussion. It is very easy for a SQL builder to correctly escape all sorts of literals, so it can handle this transparently. I mean, you're handling it just the same when using cb.literal(). Btw, using a String literal in a predicate generates a bind variable: cb.equal(from.get("title"), cb.literal("abc")...
A configuration option would definitely be a pragmatic way forward.
Side-note: I misunderstood the working of cb.literal(). Apparently, the burden of escaping input lies with the API user. That's unfortunate and does complicate things...
I had actually already tackled this in 6.0. What I have there so far is:
We can add your AUTO here I guess, although I am not sure of the usefulness of it.
The special AS_PARAM_OUTSIDE_SELECT is to account for databases (DB2 for sure) that do not like parameters in the SELECT clause. In such cases we have 2 options:
render the literal directly.
render as a param, but wrap in a cast
We could also offer that as a distinction: AS_PARAM_OUTSIDE_SELECT + AS_PARAM_WRAPPED_IN_SELECT. Or alternatively we could simply interpret AS_PARAM + Dialect#requiresCastingOfParametersInSelectClause == true as "AS_PARAM_WRAPPED_IN_SELECT". I think the second option is the best option.
Applied PR upstream.