Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(How) can I use "LIKE" in SQL queries with MyBatis safely and DB-agnostic?

Tags:

In MyBatis, you mark the places where parameters should be inserted into your SQL like so:

SELECT * FROM Person WHERE id = #{id}

This syntax activates proper escaping etc to avoid, among other things, SQL injection attacks. If you have trusted input and want to skip escaping, you can insert the parameters verbatim:

SELECT * FROM {tableName} WHERE id = #{id}

Now, I want to do a LIKE search on unsafe input, so what I want to do is this:

SELECT * FROM Person WHERE name LIKE #{beginningOfName} || '%'

Unfortunately, however, important DB servers don't support the || syntax for concatenation:

MSSQL - Breaks the standard by using the '+' operator instead of '||'.

...

MySQL - Badly breaks the standard by redefining || to mean OR.

So, I could do either

SELECT * FROM Person WHERE name LIKE CONCAT(#{beginningOfName}, '%')

and be confined to, in this case, MySQL, or I could do

SELECT * FROM Person WHERE name LIKE '{beginningOfName}%'

and would have to sanitize input myself.

Is there a more elegant solution?

like image 592
Hanno Fietz Avatar asked Sep 20 '11 20:09

Hanno Fietz


People also ask

How do you use like in a query?

In an expression, you can use the Like operator to compare a field value to a string expression. For example, if you enter Like “C*” in an SQL query, the query returns all field values beginning with the letter C. In a parameter query, you can prompt the user for a pattern to search for.

When should I use like or SQL?

The SQL LIKE Operator The LIKE operator is used in a WHERE clause to search for a specified pattern in a column. There are two wildcards often used in conjunction with the LIKE operator: The percent sign (%) represents zero, one, or multiple characters. The underscore sign (_) represents one, single character.

Where is my tag in MyBatis?

Method two Here are two features of the Where tag: First, the where clause is inserted only if the if tag has content. Second, if the opening of the clause is and or or , the where tag will replace it and remove it.


2 Answers

You could use bind syntax

Quoting Official documentation

The bind element lets you create a variable out of an OGNL expression and bind it to the context. For example:

<select id="selectBlogsLike" resultType="Blog">
  <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
  SELECT * FROM BLOG
  WHERE title LIKE #{pattern}
</select>
like image 114
Bartosz Bilicki Avatar answered Sep 20 '22 16:09

Bartosz Bilicki


Typically this is done by adding the % to the parameter itself before passing it in, in whatever language you're using outside of SQL. However note that either way you might still need to do an escaping step if your search term may have _ or % in it. See eg this question for background.)

To fix the concatenation problem in general, put MySQL into ANSI sql_mode and you get proper support for the || operator, as well as correct handling of double quotes for schema names rather than string literals.

(If you can't do that you'd have to build a function to build the statement out of either || or CONCAT(), abstracting away the difference.)

like image 40
bobince Avatar answered Sep 18 '22 16:09

bobince