mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-25 01:19:02 +00:00
SQL: Escaped wildcard (*) not accepted in LIKE (#63428)
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 (cherry picked from commit 190d9fe3deb31aed0d8f312007360625d4fff217)
This commit is contained in:
parent
f70391c6cc
commit
4aabc050a0
@ -33,8 +33,9 @@ with the `LIKE` operator:
|
||||
* The percent sign (%)
|
||||
* The underscore (_)
|
||||
|
||||
The percent sign represents zero, one or multiple characters. The underscore represents a single number or character. These symbols can be
|
||||
used in combinations.
|
||||
The percent sign represents zero, one or multiple characters. The underscore represents a single number or character. These symbols can be used in combinations.
|
||||
|
||||
NOTE: No other characters have special meaning or act as wildcard. Characters often used as wildcards in other languages (`*` or `?`) are treated as normal characters.
|
||||
|
||||
[source, sql]
|
||||
----
|
||||
|
@ -270,12 +270,6 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
|
||||
if (pattern == null) {
|
||||
throw new ParsingException(source(ctx.value), "Pattern must not be [null]");
|
||||
}
|
||||
int pos = pattern.indexOf('*');
|
||||
if (pos >= 0) {
|
||||
throw new ParsingException(source(ctx.value),
|
||||
"Invalid char [*] found in pattern [{}] at position {}; use [%] or [_] instead",
|
||||
pattern, pos);
|
||||
}
|
||||
|
||||
char escape = 0;
|
||||
PatternEscapeContext escapeCtx = ctx.patternEscape();
|
||||
@ -288,7 +282,7 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
|
||||
} else if (escapeString.length() == 1) {
|
||||
escape = escapeString.charAt(0);
|
||||
// these chars already have a meaning
|
||||
if (escape == '*' || escape == '%' || escape == '_') {
|
||||
if (escape == '%' || escape == '_') {
|
||||
throw new ParsingException(source(escapeCtx.escape), "Char [{}] cannot be used for escaping", escape);
|
||||
}
|
||||
// lastly validate that escape chars (if present) are followed by special chars
|
||||
@ -303,8 +297,8 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
|
||||
char next = pattern.charAt(i + 1);
|
||||
if (next != '%' && next != '_') {
|
||||
throw new ParsingException(source(ctx.value),
|
||||
"Pattern [{}] is invalid as escape char [{}] at position {} can only escape wildcard chars; found [{}]",
|
||||
pattern, escape, i, next);
|
||||
"Pattern [{}] is invalid as escape char [{}] at position {} can only escape "
|
||||
+ "wildcard chars [%_]; found [{}]", pattern, escape, i, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,12 @@ public class LikeEscapingParsingTests extends ESTestCase {
|
||||
|
||||
private final SqlParser parser = new SqlParser();
|
||||
|
||||
private static LikePattern patternOfLike(Expression exp) {
|
||||
assertThat(exp, instanceOf(Like.class));
|
||||
Like l = (Like) exp;
|
||||
return l.pattern();
|
||||
}
|
||||
|
||||
private String error(String pattern) {
|
||||
ParsingException ex = expectThrows(ParsingException.class,
|
||||
() -> parser.createExpression(format(null, "exp LIKE {}", pattern)));
|
||||
@ -36,9 +42,11 @@ public class LikeEscapingParsingTests extends ESTestCase {
|
||||
} else {
|
||||
exp = parser.createExpression(format(null, "exp LIKE '{}'", pattern));
|
||||
}
|
||||
assertThat(exp, instanceOf(Like.class));
|
||||
Like l = (Like) exp;
|
||||
return l.pattern();
|
||||
return patternOfLike(exp);
|
||||
}
|
||||
|
||||
private LikePattern like(String pattern, Character escapeChar) {
|
||||
return patternOfLike(parser.createExpression(format(null, "exp LIKE '{}' ESCAPE '{}'", pattern, escapeChar)));
|
||||
}
|
||||
|
||||
public void testNoEscaping() {
|
||||
@ -55,16 +63,34 @@ public class LikeEscapingParsingTests extends ESTestCase {
|
||||
|
||||
public void testEscapingWrongChar() {
|
||||
assertThat(error("'|string' ESCAPE '|'"),
|
||||
is("line 1:11: Pattern [|string] is invalid as escape char [|] at position 0 can only escape wildcard chars; found [s]"));
|
||||
is("line 1:11: Pattern [|string] is invalid as escape char [|] at position 0 can only escape "
|
||||
+ "wildcard chars [%_]; found [s]"));
|
||||
}
|
||||
|
||||
public void testInvalidChar() {
|
||||
assertThat(error("'%string' ESCAPE '%'"),
|
||||
is("line 1:28: Char [%] cannot be used for escaping"));
|
||||
public void testEscapingTheEscapeCharacter() {
|
||||
assertThat(error("'||string' ESCAPE '|'"),
|
||||
is("line 1:11: Pattern [||string] is invalid as escape char [|] at position 0 can only escape wildcard chars [%_]; found [|]"));
|
||||
}
|
||||
|
||||
public void testCannotUseStar() {
|
||||
assertThat(error("'|*string' ESCAPE '|'"),
|
||||
is("line 1:11: Invalid char [*] found in pattern [|*string] at position 1; use [%] or [_] instead"));
|
||||
public void testEscapingWildcards() {
|
||||
assertThat(error("'string' ESCAPE '%'"),
|
||||
is("line 1:27: Char [%] cannot be used for escaping"));
|
||||
assertThat(error("'string' ESCAPE '_'"),
|
||||
is("line 1:27: Char [_] cannot be used for escaping"));
|
||||
}
|
||||
|
||||
public void testCanUseStarWithoutEscaping() {
|
||||
LikePattern like = like("%string*");
|
||||
assertThat(like.pattern(), is("%string*"));
|
||||
assertThat(like.asJavaRegex(), is("^.*string\\*$"));
|
||||
assertThat(like.asLuceneWildcard(), is("*string\\*"));
|
||||
}
|
||||
|
||||
public void testEscapingWithStar() {
|
||||
LikePattern like = like("*%%*__string", '*');
|
||||
assertThat(like.pattern(), is("*%%*__string"));
|
||||
assertThat(like.asJavaRegex(), is("^%.*_.string$"));
|
||||
assertThat(like.asLuceneWildcard(), is("%*_?string"));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -81,6 +81,10 @@ public class LikeConversionTests extends ESTestCase {
|
||||
assertEquals("foo\\*bar*", wildcard("foo*bar%"));
|
||||
}
|
||||
|
||||
public void testStarLiteralWithWildcards() {
|
||||
assertEquals("\\**\\*?foo\\*\\*?*", wildcard("*%*_foo**_%"));
|
||||
}
|
||||
|
||||
public void testWildcardEscapedWildcard() {
|
||||
assertEquals("foo\\*bar%", wildcard("foo*bar|%"));
|
||||
}
|
||||
@ -129,4 +133,4 @@ public class LikeConversionTests extends ESTestCase {
|
||||
assertEquals("foo|_bar|", unescape("foo|||_bar||"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user