Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SPARK-28083][SQL] Support LIKE ... ESCAPE syntax #25001

Closed
wants to merge 62 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
4f5016a
add like escape.
beliefer Jun 28, 2019
8609a46
Fix scala style.
beliefer Jun 28, 2019
8992b5a
Supplement ESCAPE in g4.
beliefer Jun 28, 2019
c9d7dfe
adjust code.
beliefer Jun 28, 2019
b5be74a
adjust code.
beliefer Jun 28, 2019
6ac3f21
Fix UT.
beliefer Jul 2, 2019
5303564
Add ESCAPE to reserved in SQL-2011.
beliefer Jul 3, 2019
aef7dcb
Optimize code and update TableIdentifierParserSuite.
beliefer Jul 4, 2019
77f2d98
Optimize code and update TableIdentifierParserSuite.
beliefer Jul 4, 2019
caef102
Optimize code and update TableIdentifierParserSuite.
beliefer Jul 4, 2019
a0ceae1
Optimize code and update TableIdentifierParserSuite.
beliefer Jul 4, 2019
28a566d
code optimize.
beliefer Jul 4, 2019
f360f43
Optimize code.
beliefer Jul 5, 2019
be0c1d9
Optimize code.
beliefer Jul 5, 2019
aa81a56
Optimize code.
beliefer Jul 5, 2019
4b1fed8
Optimize code.
beliefer Jul 5, 2019
3e3f2b6
Optimize code.
beliefer Jul 5, 2019
9509c73
Merge branch 'ansi-sql-like-test2' into ansi-sql-like
beliefer Jul 5, 2019
0bcb027
optimize code.
beliefer Jul 5, 2019
b5a3cc7
optimize code.
beliefer Jul 5, 2019
56f5f8a
change Option to Some
beliefer Jul 7, 2019
64963ca
add blank
beliefer Jul 7, 2019
7fd5a7f
length() -> length
beliefer Jul 7, 2019
0650ef8
update the description for escape and the usage.
beliefer Jul 7, 2019
479e24a
update description of Like
beliefer Jul 7, 2019
103203f
update description
beliefer Jul 7, 2019
5990545
try to unify escapeChar
beliefer Jul 11, 2019
31f1c7c
try to unify escapeChar
beliefer Jul 11, 2019
1c0440e
try to unify escapeChar
beliefer Jul 11, 2019
dbc4388
split test case.
beliefer Jul 11, 2019
8a89f92
split test case.
beliefer Jul 11, 2019
410dd85
split test case.
beliefer Jul 11, 2019
33c7ad4
supplement comment.
beliefer Jul 11, 2019
a57e25c
Hide ESCAPE section without escape char.
beliefer Jul 11, 2019
99bbc2f
Merge branch 'ansi-sql-like-test3' into ansi-sql-like
beliefer Jul 11, 2019
bcda7d1
Add tests in SQLQueryTestSuite.
beliefer Jul 17, 2019
9901924
Adjust UT.
beliefer Jul 17, 2019
f5490c6
Fix bug.
beliefer Jul 18, 2019
7f6e3d1
Fix scala style.
beliefer Jul 18, 2019
856242c
Merge branch 'ansi-sql-like-test3' into ansi-sql-like
beliefer Jul 18, 2019
3d01650
Optimize code.
beliefer Jul 22, 2019
420f1b9
Fix bug of escape
beliefer Jul 23, 2019
2b4c59a
Fix bug of escape
beliefer Jul 23, 2019
9f7707b
Optimize code.
beliefer Jul 23, 2019
24a796e
Supplement comment.
beliefer Jul 23, 2019
6b60360
Optimize code.
beliefer Jul 30, 2019
aa6c785
Forbid empty string as escape char.
beliefer Aug 2, 2019
aa0f2f7
Optimize code.
beliefer Aug 2, 2019
bb0be67
Supplement comment.
beliefer Aug 23, 2019
10f42f4
Remove like escape in Column.
beliefer Aug 23, 2019
738ca18
Fix CONFLICT.
beliefer Oct 8, 2019
134fd1f
Fix conflict.
beliefer Oct 8, 2019
24c4be7
Fix check outputs of expression examples.
beliefer Oct 8, 2019
3964414
Add comment for double escape \ and "
beliefer Oct 24, 2019
88a4e3e
Improve code
beliefer Dec 4, 2019
f539524
Adjust UT
beliefer Dec 4, 2019
a891139
Adjust UT
beliefer Dec 4, 2019
fd8c5a7
Restore escape to reserved.
beliefer Dec 4, 2019
0a51849
Adjust parameter.
beliefer Dec 5, 2019
64e49b7
Adjust parameter.
beliefer Dec 5, 2019
9feb25d
Update comment
beliefer Dec 5, 2019
4cc9e0a
Optimize code
beliefer Dec 6, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/sql-keywords.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Below is a list of all the keywords in Spark SQL.
<tr><td>DROP</td><td>non-reserved</td><td>non-reserved</td><td>reserved</td></tr>
<tr><td>ELSE</td><td>reserved</td><td>non-reserved</td><td>reserved</td></tr>
<tr><td>END</td><td>reserved</td><td>non-reserved</td><td>reserved</td></tr>
<tr><td>ESCAPE</td><td>reserved</td><td>non-reserved</td><td>reserved</td></tr>
<tr><td>ESCAPED</td><td>non-reserved</td><td>non-reserved</td><td>non-reserved</td></tr>
<tr><td>EXCEPT</td><td>reserved</td><td>strict-non-reserved</td><td>reserved</td></tr>
<tr><td>EXCHANGE</td><td>non-reserved</td><td>non-reserved</td><td>non-reserved</td></tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,8 @@ predicate
: NOT? kind=BETWEEN lower=valueExpression AND upper=valueExpression
| NOT? kind=IN '(' expression (',' expression)* ')'
| NOT? kind=IN '(' query ')'
| NOT? kind=(RLIKE | LIKE) pattern=valueExpression
| NOT? kind=RLIKE pattern=valueExpression
| NOT? kind=LIKE pattern=valueExpression (ESCAPE escapeChar=STRING)?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't apply to RLIKE?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

| IS NOT? kind=NULL
| IS NOT? kind=(TRUE | FALSE | UNKNOWN)
| IS NOT? kind=DISTINCT FROM right=valueExpression
Expand Down Expand Up @@ -1202,6 +1203,7 @@ nonReserved
| DROP
| ELSE
| END
| ESCAPE
cloud-fan marked this conversation as resolved.
Show resolved Hide resolved
| ESCAPED
| EXCHANGE
| EXISTS
Expand Down Expand Up @@ -1459,6 +1461,7 @@ DISTRIBUTE: 'DISTRIBUTE';
DROP: 'DROP';
ELSE: 'ELSE';
END: 'END';
ESCAPE: 'ESCAPE';
ESCAPED: 'ESCAPED';
EXCEPT: 'EXCEPT';
EXCHANGE: 'EXCHANGE';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ package object dsl {
case _ => In(expr, list)
}

def like(other: Expression): Expression = Like(expr, other)
def like(other: Expression, escapeChar: Char = '\\'): Expression =
Like(expr, other, escapeChar)
def rlike(other: Expression): Expression = RLike(expr, other)
def contains(other: Expression): Expression = Contains(expr, other)
def startsWith(other: Expression): Expression = StartsWith(expr, other)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ abstract class StringRegexExpression extends BinaryExpression
* Simple RegEx pattern matching function
*/
@ExpressionDescription(
usage = "str _FUNC_ pattern - Returns true if str matches pattern, " +
"null if any arguments are null, false otherwise.",
usage = "str _FUNC_ pattern[ ESCAPE escape] - Returns true if str matches `pattern` with " +
"`escape`, null if any arguments are null, false otherwise.",
arguments = """
Arguments:
* str - a string expression
Expand All @@ -83,16 +83,15 @@ abstract class StringRegexExpression extends BinaryExpression
% matches zero or more characters in the input (similar to .* in posix regular
expressions)

The escape character is '\'. If an escape character precedes a special symbol or another
escape character, the following character is matched literally. It is invalid to escape
any other character.

Since Spark 2.0, string literals are unescaped in our SQL parser. For example, in order
to match "\abc", the pattern should be "\\abc".

When SQL config 'spark.sql.parser.escapedStringLiterals' is enabled, it fallbacks
to Spark 1.6 behavior regarding string literal parsing. For example, if the config is
enabled, the pattern to match "\abc" should be "\abc".
* escape - an character added since Spark 3.0. The default escape character is the '\'.
If an escape character precedes a special symbol or another escape character, the
following character is matched literally. It is invalid to escape any other character.
""",
examples = """
Examples:
Expand All @@ -104,19 +103,25 @@ abstract class StringRegexExpression extends BinaryExpression
spark.sql.parser.escapedStringLiterals false
> SELECT '%SystemDrive%\\Users\\John' _FUNC_ '\%SystemDrive\%\\\\Users%';
true
> SELECT '%SystemDrive%/Users/John' _FUNC_ '/%SystemDrive/%//Users%' ESCAPE '/';
true
""",
note = """
Use RLIKE to match with standard regular expressions.
""",
since = "1.0.0")
// scalastyle:on line.contains.tab
case class Like(left: Expression, right: Expression) extends StringRegexExpression {
case class Like(left: Expression, right: Expression, escapeChar: Char = '\\')
extends StringRegexExpression {

override def escape(v: String): String = StringUtils.escapeLikeRegex(v)
override def escape(v: String): String = StringUtils.escapeLikeRegex(v, escapeChar)

override def matches(regex: Pattern, str: String): Boolean = regex.matcher(str).matches()

override def toString: String = s"$left LIKE $right"
override def toString: String = escapeChar match {
case '\\' => s"$left LIKE $right"
case c => s"$left LIKE $right ESCAPE '$c'"
}

override protected def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = {
val patternClass = classOf[Pattern].getName
Expand Down Expand Up @@ -149,10 +154,18 @@ case class Like(left: Expression, right: Expression) extends StringRegexExpressi
} else {
val pattern = ctx.freshName("pattern")
val rightStr = ctx.freshName("rightStr")
// We need double escape to avoid org.codehaus.commons.compiler.CompileException.
// '\\' will cause exception 'Single quote must be backslash-escaped in character literal'.
// '\"' will cause exception 'Line break in literal not allowed'.
val newEscapeChar = if (escapeChar == '\"' || escapeChar == '\\') {
s"""\\\\\\$escapeChar"""
} else {
escapeChar
}
nullSafeCodeGen(ctx, ev, (eval1, eval2) => {
s"""
String $rightStr = $eval2.toString();
$patternClass $pattern = $patternClass.compile($escapeFunc($rightStr));
$patternClass $pattern = $patternClass.compile($escapeFunc($rightStr, '$newEscapeChar'));
${ev.value} = $pattern.matcher($eval1.toString()).matches();
"""
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ object LikeSimplification extends Rule[LogicalPlan] {
private val equalTo = "([^_%]*)".r

def apply(plan: LogicalPlan): LogicalPlan = plan transformAllExpressions {
case Like(input, Literal(pattern, StringType)) =>
case Like(input, Literal(pattern, StringType), escapeChar) =>
if (pattern == null) {
// If pattern is null, return null value directly, since "col like null" == null.
Literal(null, BooleanType)
Expand All @@ -503,8 +503,7 @@ object LikeSimplification extends Rule[LogicalPlan] {
Contains(input, Literal(infix))
case equalTo(str) =>
EqualTo(input, Literal(str))
case _ =>
Like(input, Literal.create(pattern, StringType))
case _ => Like(input, Literal.create(pattern, StringType), escapeChar)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1309,7 +1309,14 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging
case SqlBaseParser.IN =>
invertIfNotDefined(In(e, ctx.expression.asScala.map(expression)))
case SqlBaseParser.LIKE =>
invertIfNotDefined(Like(e, expression(ctx.pattern)))
val escapeChar = Option(ctx.escapeChar).map(string).map { str =>
if (str.length != 1) {
throw new ParseException("Invalid escape string." +
"Escape string must contains only one character.", ctx)
}
str.charAt(0)
}.getOrElse('\\')
invertIfNotDefined(Like(e, expression(ctx.pattern), escapeChar))
case SqlBaseParser.RLIKE =>
invertIfNotDefined(RLike(e, expression(ctx.pattern)))
case SqlBaseParser.NULL if ctx.NOT != null =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ object StringUtils extends Logging {
* throw an [[AnalysisException]].
*
* @param pattern the SQL pattern to convert
* @param escapeStr the escape string contains one character.
* @return the equivalent Java regular expression of the pattern
*/
def escapeLikeRegex(pattern: String): String = {
def escapeLikeRegex(pattern: String, escapeChar: Char): String = {
val in = pattern.toIterator
val out = new StringBuilder()

Expand All @@ -50,13 +51,14 @@ object StringUtils extends Logging {

while (in.hasNext) {
in.next match {
case '\\' if in.hasNext =>
case c1 if c1 == escapeChar && in.hasNext =>
val c = in.next
c match {
case '_' | '%' | '\\' => out ++= Pattern.quote(Character.toString(c))
case '_' | '%' => out ++= Pattern.quote(Character.toString(c))
case c if c == escapeChar => out ++= Pattern.quote(Character.toString(c))
case _ => fail(s"the escape character is not allowed to precede '$c'")
}
case '\\' => fail("it is not allowed to end with the escape character")
case c if c == escapeChar => fail("it is not allowed to end with the escape character")
case '_' => out ++= "."
case '%' => out ++= ".*"
case c => out ++= Pattern.quote(Character.toString(c))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,84 @@ class RegexpExpressionsSuite extends SparkFunSuite with ExpressionEvalHelper {
checkLiteralRow("""%SystemDrive%\Users\John""" like _, """\%SystemDrive\%\\Users%""", true)
}

Seq('/', '#', '\"').foreach { escapeChar =>
test(s"LIKE Pattern ESCAPE '$escapeChar'") {
// null handling
checkLiteralRow(Literal.create(null, StringType).like(_, escapeChar), "a", null)
checkEvaluation(
Literal.create("a", StringType).like(Literal.create(null, StringType), escapeChar), null)
checkEvaluation(
Literal.create(null, StringType).like(Literal.create(null, StringType), escapeChar), null)
checkEvaluation(Literal.create("a", StringType).like(
NonFoldableLiteral.create("a", StringType), escapeChar), true)
checkEvaluation(Literal.create("a", StringType).like(
NonFoldableLiteral.create(null, StringType), escapeChar), null)
checkEvaluation(Literal.create(null, StringType).like(
NonFoldableLiteral.create("a", StringType), escapeChar), null)
checkEvaluation(Literal.create(null, StringType).like(
NonFoldableLiteral.create(null, StringType), escapeChar), null)

// simple patterns
checkLiteralRow("abdef" like(_, escapeChar), "abdef", true)
checkLiteralRow("a_%b" like(_, escapeChar), s"a${escapeChar}__b", true)
checkLiteralRow("addb" like(_, escapeChar), "a_%b", true)
checkLiteralRow("addb" like(_, escapeChar), s"a${escapeChar}__b", false)
checkLiteralRow("addb" like(_, escapeChar), s"a%$escapeChar%b", false)
checkLiteralRow("a_%b" like(_, escapeChar), s"a%$escapeChar%b", true)
checkLiteralRow("addb" like(_, escapeChar), "a%", true)
checkLiteralRow("addb" like(_, escapeChar), "**", false)
checkLiteralRow("abc" like(_, escapeChar), "a%", true)
checkLiteralRow("abc" like(_, escapeChar), "b%", false)
checkLiteralRow("abc" like(_, escapeChar), "bc%", false)
checkLiteralRow("a\nb" like(_, escapeChar), "a_b", true)
checkLiteralRow("ab" like(_, escapeChar), "a%b", true)
checkLiteralRow("a\nb" like(_, escapeChar), "a%b", true)

// empty input
checkLiteralRow("" like(_, escapeChar), "", true)
checkLiteralRow("a" like(_, escapeChar), "", false)
checkLiteralRow("" like(_, escapeChar), "a", false)

// SI-17647 double-escaping backslash
checkLiteralRow(s"""$escapeChar$escapeChar$escapeChar$escapeChar""" like(_, escapeChar),
s"""%$escapeChar$escapeChar%""", true)
checkLiteralRow("""%%""" like(_, escapeChar), """%%""", true)
checkLiteralRow(s"""${escapeChar}__""" like(_, escapeChar),
s"""$escapeChar$escapeChar${escapeChar}__""", true)
checkLiteralRow(s"""$escapeChar$escapeChar${escapeChar}__""" like(_, escapeChar),
s"""%$escapeChar$escapeChar%$escapeChar%""", false)
checkLiteralRow(s"""_$escapeChar$escapeChar$escapeChar%""" like(_, escapeChar),
s"""%$escapeChar${escapeChar}""", false)

// unicode
// scalastyle:off nonascii
checkLiteralRow("a\u20ACa" like(_, escapeChar), "_\u20AC_", true)
checkLiteralRow("a€a" like(_, escapeChar), "_€_", true)
checkLiteralRow("a€a" like(_, escapeChar), "_\u20AC_", true)
checkLiteralRow("a\u20ACa" like(_, escapeChar), "_€_", true)
// scalastyle:on nonascii

// invalid escaping
val invalidEscape = intercept[AnalysisException] {
evaluateWithoutCodegen("""a""" like(s"""${escapeChar}a""", escapeChar))
}
assert(invalidEscape.getMessage.contains("pattern"))
val endEscape = intercept[AnalysisException] {
evaluateWithoutCodegen("""a""" like(s"""a$escapeChar""", escapeChar))
}
assert(endEscape.getMessage.contains("pattern"))

// case
checkLiteralRow("A" like(_, escapeChar), "a%", false)
checkLiteralRow("a" like(_, escapeChar), "A%", false)
checkLiteralRow("AaA" like(_, escapeChar), "_a_", true)

// example
checkLiteralRow(s"""%SystemDrive%${escapeChar}Users${escapeChar}John""" like(_, escapeChar),
s"""$escapeChar%SystemDrive$escapeChar%$escapeChar${escapeChar}Users%""", true)
}
}

test("RLIKE Regular Expression") {
checkLiteralRow(Literal.create(null, StringType) rlike _, "abdef", null)
checkEvaluation("abdef" rlike Literal.create(null, StringType), null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,18 @@ class ExpressionParserSuite extends AnalysisTest {
assertEqual("a not regexp 'pattern%'", !('a rlike "pattern%"))
}

test("like escape expressions") {
val message = "Escape string must contains only one character."
assertEqual("a like 'pattern%' escape '#'", 'a.like("pattern%", '#'))
assertEqual("a like 'pattern%' escape '\"'", 'a.like("pattern%", '\"'))
intercept("a like 'pattern%' escape '##'", message)
intercept("a like 'pattern%' escape ''", message)
assertEqual("a not like 'pattern%' escape '#'", !('a.like("pattern%", '#')))
assertEqual("a not like 'pattern%' escape '\"'", !('a.like("pattern%", '\"')))
intercept("a not like 'pattern%' escape '\"/'", message)
intercept("a not like 'pattern%' escape ''", message)
}

test("like expressions with ESCAPED_STRING_LITERALS = true") {
val conf = new SQLConf()
conf.setConfString(SQLConf.ESCAPED_STRING_LITERALS.key, "true")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ class TableIdentifierParserSuite extends SparkFunSuite with SQLHelper {
"drop",
"else",
"end",
"escape",
"escaped",
"except",
"exchange",
Expand Down Expand Up @@ -581,6 +582,7 @@ class TableIdentifierParserSuite extends SparkFunSuite with SQLHelper {
"distinct",
"else",
"end",
"escape",
"except",
"false",
"fetch",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,34 @@ import org.apache.spark.sql.catalyst.util.StringUtils._
class StringUtilsSuite extends SparkFunSuite {

test("escapeLikeRegex") {
assert(escapeLikeRegex("abdef") === "(?s)\\Qa\\E\\Qb\\E\\Qd\\E\\Qe\\E\\Qf\\E")
assert(escapeLikeRegex("a\\__b") === "(?s)\\Qa\\E\\Q_\\E.\\Qb\\E")
assert(escapeLikeRegex("a_%b") === "(?s)\\Qa\\E..*\\Qb\\E")
assert(escapeLikeRegex("a%\\%b") === "(?s)\\Qa\\E.*\\Q%\\E\\Qb\\E")
assert(escapeLikeRegex("a%") === "(?s)\\Qa\\E.*")
assert(escapeLikeRegex("**") === "(?s)\\Q*\\E\\Q*\\E")
assert(escapeLikeRegex("a_b") === "(?s)\\Qa\\E.\\Qb\\E")
val expectedEscapedStrOne = "(?s)\\Qa\\E\\Qb\\E\\Qd\\E\\Qe\\E\\Qf\\E"
val expectedEscapedStrTwo = "(?s)\\Qa\\E\\Q_\\E.\\Qb\\E"
val expectedEscapedStrThree = "(?s)\\Qa\\E..*\\Qb\\E"
val expectedEscapedStrFour = "(?s)\\Qa\\E.*\\Q%\\E\\Qb\\E"
val expectedEscapedStrFive = "(?s)\\Qa\\E.*"
val expectedEscapedStrSix = "(?s)\\Q*\\E\\Q*\\E"
val expectedEscapedStrSeven = "(?s)\\Qa\\E.\\Qb\\E"
assert(escapeLikeRegex("abdef", '\\') === expectedEscapedStrOne)
assert(escapeLikeRegex("abdef", '/') === expectedEscapedStrOne)
assert(escapeLikeRegex("abdef", '\"') === expectedEscapedStrOne)
assert(escapeLikeRegex("a\\__b", '\\') === expectedEscapedStrTwo)
assert(escapeLikeRegex("a/__b", '/') === expectedEscapedStrTwo)
assert(escapeLikeRegex("a\"__b", '\"') === expectedEscapedStrTwo)
assert(escapeLikeRegex("a_%b", '\\') === expectedEscapedStrThree)
assert(escapeLikeRegex("a_%b", '/') === expectedEscapedStrThree)
assert(escapeLikeRegex("a_%b", '\"') === expectedEscapedStrThree)
assert(escapeLikeRegex("a%\\%b", '\\') === expectedEscapedStrFour)
assert(escapeLikeRegex("a%/%b", '/') === expectedEscapedStrFour)
assert(escapeLikeRegex("a%\"%b", '\"') === expectedEscapedStrFour)
assert(escapeLikeRegex("a%", '\\') === expectedEscapedStrFive)
assert(escapeLikeRegex("a%", '/') === expectedEscapedStrFive)
assert(escapeLikeRegex("a%", '\"') === expectedEscapedStrFive)
assert(escapeLikeRegex("**", '\\') === expectedEscapedStrSix)
assert(escapeLikeRegex("**", '/') === expectedEscapedStrSix)
assert(escapeLikeRegex("**", '\"') === expectedEscapedStrSix)
assert(escapeLikeRegex("a_b", '\\') === expectedEscapedStrSeven)
assert(escapeLikeRegex("a_b", '/') === expectedEscapedStrSeven)
assert(escapeLikeRegex("a_b", '\"') === expectedEscapedStrSeven)
}

test("filter pattern") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ object PartitionPruning extends Rule[LogicalPlan] with PredicateHelper {
case Not(expr) => isLikelySelective(expr)
case And(l, r) => isLikelySelective(l) || isLikelySelective(r)
case Or(l, r) => isLikelySelective(l) && isLikelySelective(r)
case Like(_, _) => true
case Like(_, _, _) => true
case _: BinaryComparison => true
case _: In | _: InSet => true
case _: StringPredicate => true
Expand Down