For this question, we want to avoid having to write a special query since the query would have to be different across multiple databases. Using only hibernate criteria, we want to be able to escape special characters.
This situation is the reason for needing the ability to escape special characters:
Assume that we have table ‘foo’ in the database. Table ‘foo’ contains only 1 field, called ‘name’. The ‘name’ field can contain characters that may be considered special in a database. Two examples of such a name are ‘name_1’ and ‘name%1’. Both the ‘_’ and ‘%’ are special characters, at least in Oracle. If a user wants to search for one of these examples after they are entered in the database, problems may occur.
criterion = Restrictions.ilike("name", searchValue, MatchMode.ANYWHERE);
return findByCriteria(null, criterion);
In this code, ‘searchValue’ is the value that the user has given the application to use for its search. If the user wants to search for ‘%’, the user is going to be returned with every ‘foo’ entry in the database. This is because the ‘%’ character represents the “any number of characters” wildcard for string matching and the SQL code that hibernate produces will look like:
select * from foo where name like '%'
Is there a way to tell hibernate to escape certain characters, or to create a workaround that is not database type specific?
LikeExpression’s constructors are all protected, so it’s not a viable option. Also, it has problems of its own.
A colleague and I created a patch which works pretty well. The gist of the patch is that for the LikeExpression constructor which consumes a MatchMode, we escape the special characters. For the constructor which consumes a Character (the escape character), we assume the user escapes the special characters on their own.
We also parameterized the escape character to ensure that it can’t corrupt the SQL query if they use something like \ or a quote character.
If you’re wondering what the lhs and typedValue methods are for, the new IlikeExpression should answer those questions.
After this, the only thing left is to make Restrictions use these new classes:
Edit: Oh yeah. This works for Oracle. We’re not sure about other databases though.