Skip to content

Commit c368506

Browse files
author
Andras Palinkas
committed
SQL: Escaped wildcard (*) not accepted in LIKE
For a query like `SELECT name FROM test WHERE name LIKE ''%c*'` ES SQL generates an error. `*` is not a special character in a `LIKE` construct and it's expected to not needing to be escaped, so the previous query should work as is. In the LIKE pattern any `*` character was treated as invalid character and the usage of `%` or `_` was suggested instead. But `*` is a valid, acceptable non-wildcard on the right side of the `LIKE` operator. Fix: #55108
1 parent 2f1bc84 commit c368506

File tree

4 files changed

+44
-21
lines changed

4 files changed

+44
-21
lines changed

docs/reference/sql/functions/like-rlike.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ with the `LIKE` operator:
3333
* The percent sign (%)
3434
* The underscore (_)
3535

36-
The percent sign represents zero, one or multiple characters. The underscore represents a single number or character. These symbols can be
37-
used in combinations.
36+
No other characters have special meaning or act as wildcard. The percent sign represents zero, one or multiple characters.
37+
The underscore represents a single number or character. These symbols can be used in combinations.
3838

3939
[source, sql]
4040
----

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -270,12 +270,6 @@ public LikePattern visitPattern(PatternContext ctx) {
270270
if (pattern == null) {
271271
throw new ParsingException(source(ctx.value), "Pattern must not be [null]");
272272
}
273-
int pos = pattern.indexOf('*');
274-
if (pos >= 0) {
275-
throw new ParsingException(source(ctx.value),
276-
"Invalid char [*] found in pattern [{}] at position {}; use [%] or [_] instead",
277-
pattern, pos);
278-
}
279273

280274
char escape = 0;
281275
PatternEscapeContext escapeCtx = ctx.patternEscape();
@@ -288,7 +282,7 @@ public LikePattern visitPattern(PatternContext ctx) {
288282
} else if (escapeString.length() == 1) {
289283
escape = escapeString.charAt(0);
290284
// these chars already have a meaning
291-
if (escape == '*' || escape == '%' || escape == '_') {
285+
if (escape == '%' || escape == '_') {
292286
throw new ParsingException(source(escapeCtx.escape), "Char [{}] cannot be used for escaping", escape);
293287
}
294288
// lastly validate that escape chars (if present) are followed by special chars
@@ -303,7 +297,7 @@ public LikePattern visitPattern(PatternContext ctx) {
303297
char next = pattern.charAt(i + 1);
304298
if (next != '%' && next != '_') {
305299
throw new ParsingException(source(ctx.value),
306-
"Pattern [{}] is invalid as escape char [{}] at position {} can only escape wildcard chars; found [{}]",
300+
"Pattern [{}] is invalid as escape char [{}] at position {} can only escape wildcard chars [%_]; found [{}]",
307301
pattern, escape, i, next);
308302
}
309303
}

x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/LikeEscapingParsingTests.java

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ public class LikeEscapingParsingTests extends ESTestCase {
2121

2222
private final SqlParser parser = new SqlParser();
2323

24+
private static LikePattern patternOfLike(Expression exp) {
25+
assertThat(exp, instanceOf(Like.class));
26+
Like l = (Like) exp;
27+
return l.pattern();
28+
}
29+
2430
private String error(String pattern) {
2531
ParsingException ex = expectThrows(ParsingException.class,
2632
() -> parser.createExpression(format(null, "exp LIKE {}", pattern)));
@@ -36,9 +42,11 @@ private LikePattern like(String pattern) {
3642
} else {
3743
exp = parser.createExpression(format(null, "exp LIKE '{}'", pattern));
3844
}
39-
assertThat(exp, instanceOf(Like.class));
40-
Like l = (Like) exp;
41-
return l.pattern();
45+
return patternOfLike(exp);
46+
}
47+
48+
private LikePattern like(String pattern, Character escapeChar) {
49+
return patternOfLike(parser.createExpression(format(null, "exp LIKE '{}' ESCAPE '{}'", pattern, escapeChar)));
4250
}
4351

4452
public void testNoEscaping() {
@@ -55,16 +63,33 @@ public void testEscapingLastChar() {
5563

5664
public void testEscapingWrongChar() {
5765
assertThat(error("'|string' ESCAPE '|'"),
58-
is("line 1:11: Pattern [|string] is invalid as escape char [|] at position 0 can only escape wildcard chars; found [s]"));
66+
is("line 1:11: Pattern [|string] is invalid as escape char [|] at position 0 can only escape wildcard chars [%_]; found [s]"));
67+
}
68+
69+
public void testEscapingTheEscapeCharacter() {
70+
assertThat(error("'||string' ESCAPE '|'"),
71+
is("line 1:11: Pattern [||string] is invalid as escape char [|] at position 0 can only escape wildcard chars [%_]; found [|]"));
5972
}
6073

61-
public void testInvalidChar() {
62-
assertThat(error("'%string' ESCAPE '%'"),
63-
is("line 1:28: Char [%] cannot be used for escaping"));
74+
public void testEscapingWildcards() {
75+
assertThat(error("'string' ESCAPE '%'"),
76+
is("line 1:27: Char [%] cannot be used for escaping"));
77+
assertThat(error("'string' ESCAPE '_'"),
78+
is("line 1:27: Char [_] cannot be used for escaping"));
6479
}
6580

66-
public void testCannotUseStar() {
67-
assertThat(error("'|*string' ESCAPE '|'"),
68-
is("line 1:11: Invalid char [*] found in pattern [|*string] at position 1; use [%] or [_] instead"));
81+
public void testCanUseStarWithoutEscaping() {
82+
LikePattern like = like("%string*");
83+
assertThat(like.pattern(), is("%string*"));
84+
assertThat(like.asJavaRegex(), is("^.*string\\*$"));
85+
assertThat(like.asLuceneWildcard(), is("*string\\*"));
6986
}
87+
88+
public void testEscapingWithStar() {
89+
LikePattern like = like("*%%*__string", '*');
90+
assertThat(like.pattern(), is("*%%*__string"));
91+
assertThat(like.asJavaRegex(), is("^%.*_.string$"));
92+
assertThat(like.asLuceneWildcard(), is("%*_?string"));
93+
}
94+
7095
}

x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/util/LikeConversionTests.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ public void testWildcardEscapeLuceneWildcard() {
8181
assertEquals("foo\\*bar*", wildcard("foo*bar%"));
8282
}
8383

84+
public void testStarLiteralWithWildcards() {
85+
assertEquals("\\**\\*?foo\\*\\*?*", wildcard("*%*_foo**_%"));
86+
}
87+
8488
public void testWildcardEscapedWildcard() {
8589
assertEquals("foo\\*bar%", wildcard("foo*bar|%"));
8690
}
@@ -129,4 +133,4 @@ public void testUnescapeMultipleEscapes() {
129133
assertEquals("foo|_bar|", unescape("foo|||_bar||"));
130134
}
131135

132-
}
136+
}

0 commit comments

Comments
 (0)