Skip to content

Commit 4548b0f

Browse files
committed
Support 'like any' and 'like all' operators
1 parent a4912ce commit 4548b0f

6 files changed

Lines changed: 320 additions & 8 deletions

File tree

sql/catalyst/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBase.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,7 @@ predicate
748748
| NOT? kind=IN '(' expression (',' expression)* ')'
749749
| NOT? kind=IN '(' query ')'
750750
| NOT? kind=RLIKE pattern=valueExpression
751+
| NOT? kind=LIKE operator=(ANY | ALL) '(' expression (',' expression)* ')'
751752
| NOT? kind=LIKE pattern=valueExpression (ESCAPE escapeChar=STRING)?
752753
| IS NOT? kind=NULL
753754
| IS NOT? kind=(TRUE | FALSE | UNKNOWN)

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,14 +1387,23 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging
13871387
case SqlBaseParser.IN =>
13881388
invertIfNotDefined(In(e, ctx.expression.asScala.map(expression)))
13891389
case SqlBaseParser.LIKE =>
1390-
val escapeChar = Option(ctx.escapeChar).map(string).map { str =>
1391-
if (str.length != 1) {
1392-
throw new ParseException("Invalid escape string." +
1393-
"Escape string must contains only one character.", ctx)
1394-
}
1395-
str
1396-
}.getOrElse('\\')
1397-
invertIfNotDefined(Like(e, expression(ctx.pattern), Literal(escapeChar)))
1390+
Option(ctx.operator).map(_.getType) match {
1391+
case Some(SqlBaseParser.ANY) if !ctx.expression.isEmpty =>
1392+
ctx.expression.asScala.map(expression).map(p => invertIfNotDefined(new Like(e, p)))
1393+
.reduceLeft(Or)
1394+
case Some(SqlBaseParser.ALL) if !ctx.expression.isEmpty =>
1395+
ctx.expression.asScala.map(expression).map(p => invertIfNotDefined(new Like(e, p)))
1396+
.reduceLeft(And)
1397+
case _ =>
1398+
val escapeChar = Option(ctx.escapeChar).map(string).map { str =>
1399+
if (str.length != 1) {
1400+
throw new ParseException("Invalid escape string." +
1401+
"Escape string must contains only one character.", ctx)
1402+
}
1403+
str
1404+
}.getOrElse('\\')
1405+
invertIfNotDefined(Like(e, expression(ctx.pattern), Literal(escapeChar)))
1406+
}
13981407
case SqlBaseParser.RLIKE =>
13991408
invertIfNotDefined(RLike(e, expression(ctx.pattern)))
14001409
case SqlBaseParser.NULL if ctx.NOT != null =>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
CREATE OR REPLACE TEMPORARY VIEW like_all_table AS SELECT * FROM (VALUES
2+
('google', '%oo%'),
3+
('facebook', '%oo%'),
4+
('linkedin', '%in'))
5+
as t1(company, pat);
6+
7+
select company from like_all_table where company like all ('%oo%','%go%') ;
8+
9+
select company from like_all_table where company like all ('microsoft','%yoo%') ;
10+
11+
select
12+
company,
13+
CASE
14+
WHEN company like all ('%oo%','%go%') THEN 'Y'
15+
ELSE 'N'
16+
END AS is_available,
17+
CASE
18+
WHEN company like all ('%oo%','go%') OR company like all ('%in','ms%') THEN 'Y'
19+
ELSE 'N'
20+
END AS mix
21+
From like_all_table ;
22+
23+
--Mix test with constant pattern and column value
24+
select company from like_all_table where company like all ('%oo%',pat) ;
25+
26+
-- not like all test
27+
28+
select company from like_all_table where company not like all ('%oo%','%in','fa%') ;
29+
select company from like_all_table where company not like all ('microsoft','%yoo%') ;
30+
31+
-- null test
32+
33+
select company from like_all_table where company like all ('%oo%',null) ;
34+
35+
select company from like_all_table where company not like all ('%oo%',null) ;
36+
37+
select company from like_all_table where company not like all (null,null) ;
38+
39+
select company from like_all_table where company not like all (null,null) ;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
CREATE OR REPLACE TEMPORARY VIEW like_any_table AS SELECT * FROM (VALUES
2+
('google', '%oo%'),
3+
('facebook', '%oo%'),
4+
('linkedin', '%in'))
5+
as t1(company, pat);
6+
7+
select company from like_any_table where company like any ('%oo%','%in','fa%') ;
8+
9+
select company from like_any_table where company like any ('microsoft','%yoo%') ;
10+
11+
select
12+
company,
13+
CASE
14+
WHEN company like any ('%oo%','%in','fa%') THEN 'Y'
15+
ELSE 'N'
16+
END AS is_available,
17+
CASE
18+
WHEN company like any ('%oo%','fa%') OR company like any ('%in','ms%') THEN 'Y'
19+
ELSE 'N'
20+
END AS mix
21+
From like_any_table;
22+
23+
--Mix test with constant pattern and column value
24+
select company from like_any_table where company like any ('%zz%',pat) ;
25+
26+
-- not like any test
27+
28+
select company from like_any_table where company not like any ('%oo%','%in','fa%') ;
29+
select company from like_any_table where company not like any ('microsoft','%yoo%') ;
30+
31+
-- null test
32+
33+
select company from like_any_table where company like any ('%oo%',null) ;
34+
35+
select company from like_any_table where company not like any ('%oo%',null) ;
36+
37+
select company from like_any_table where company like any (null,null) ;
38+
39+
select company from like_any_table where company not like any (null,null) ;
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
-- Automatically generated by SQLQueryTestSuite
2+
-- Number of queries: 11
3+
4+
5+
-- !query
6+
CREATE OR REPLACE TEMPORARY VIEW like_all_table AS SELECT * FROM (VALUES
7+
('google', '%oo%'),
8+
('facebook', '%oo%'),
9+
('linkedin', '%in'))
10+
as t1(company, pat)
11+
-- !query schema
12+
struct<>
13+
-- !query output
14+
15+
16+
17+
-- !query
18+
select company from like_all_table where company like all ('%oo%','%go%')
19+
-- !query schema
20+
struct<company:string>
21+
-- !query output
22+
google
23+
24+
25+
-- !query
26+
select company from like_all_table where company like all ('microsoft','%yoo%')
27+
-- !query schema
28+
struct<company:string>
29+
-- !query output
30+
31+
32+
33+
-- !query
34+
select
35+
company,
36+
CASE
37+
WHEN company like all ('%oo%','%go%') THEN 'Y'
38+
ELSE 'N'
39+
END AS is_available,
40+
CASE
41+
WHEN company like all ('%oo%','go%') OR company like all ('%in','ms%') THEN 'Y'
42+
ELSE 'N'
43+
END AS mix
44+
From like_all_table
45+
-- !query schema
46+
struct<company:string,is_available:string,mix:string>
47+
-- !query output
48+
facebook N N
49+
google Y Y
50+
linkedin N N
51+
52+
53+
-- !query
54+
select company from like_all_table where company like all ('%oo%',pat)
55+
-- !query schema
56+
struct<company:string>
57+
-- !query output
58+
facebook
59+
google
60+
61+
62+
-- !query
63+
select company from like_all_table where company not like all ('%oo%','%in','fa%')
64+
-- !query schema
65+
struct<company:string>
66+
-- !query output
67+
68+
69+
70+
-- !query
71+
select company from like_all_table where company not like all ('microsoft','%yoo%')
72+
-- !query schema
73+
struct<company:string>
74+
-- !query output
75+
facebook
76+
google
77+
linkedin
78+
79+
80+
-- !query
81+
select company from like_all_table where company like all ('%oo%',null)
82+
-- !query schema
83+
struct<company:string>
84+
-- !query output
85+
86+
87+
88+
-- !query
89+
select company from like_all_table where company not like all ('%oo%',null)
90+
-- !query schema
91+
struct<company:string>
92+
-- !query output
93+
94+
95+
96+
-- !query
97+
select company from like_all_table where company not like all (null,null)
98+
-- !query schema
99+
struct<company:string>
100+
-- !query output
101+
102+
103+
104+
-- !query
105+
select company from like_all_table where company not like all (null,null)
106+
-- !query schema
107+
struct<company:string>
108+
-- !query output
109+
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
-- Automatically generated by SQLQueryTestSuite
2+
-- Number of queries: 11
3+
4+
5+
-- !query
6+
CREATE OR REPLACE TEMPORARY VIEW like_any_table AS SELECT * FROM (VALUES
7+
('google', '%oo%'),
8+
('facebook', '%oo%'),
9+
('linkedin', '%in'))
10+
as t1(company, pat)
11+
-- !query schema
12+
struct<>
13+
-- !query output
14+
15+
16+
17+
-- !query
18+
select company from like_any_table where company like any ('%oo%','%in','fa%')
19+
-- !query schema
20+
struct<company:string>
21+
-- !query output
22+
facebook
23+
google
24+
linkedin
25+
26+
27+
-- !query
28+
select company from like_any_table where company like any ('microsoft','%yoo%')
29+
-- !query schema
30+
struct<company:string>
31+
-- !query output
32+
33+
34+
35+
-- !query
36+
select
37+
company,
38+
CASE
39+
WHEN company like any ('%oo%','%in','fa%') THEN 'Y'
40+
ELSE 'N'
41+
END AS is_available,
42+
CASE
43+
WHEN company like any ('%oo%','fa%') OR company like any ('%in','ms%') THEN 'Y'
44+
ELSE 'N'
45+
END AS mix
46+
From like_any_table
47+
-- !query schema
48+
struct<company:string,is_available:string,mix:string>
49+
-- !query output
50+
facebook Y Y
51+
google Y Y
52+
linkedin Y Y
53+
54+
55+
-- !query
56+
select company from like_any_table where company like any ('%zz%',pat)
57+
-- !query schema
58+
struct<company:string>
59+
-- !query output
60+
facebook
61+
google
62+
linkedin
63+
64+
65+
-- !query
66+
select company from like_any_table where company not like any ('%oo%','%in','fa%')
67+
-- !query schema
68+
struct<company:string>
69+
-- !query output
70+
facebook
71+
google
72+
linkedin
73+
74+
75+
-- !query
76+
select company from like_any_table where company not like any ('microsoft','%yoo%')
77+
-- !query schema
78+
struct<company:string>
79+
-- !query output
80+
facebook
81+
google
82+
linkedin
83+
84+
85+
-- !query
86+
select company from like_any_table where company like any ('%oo%',null)
87+
-- !query schema
88+
struct<company:string>
89+
-- !query output
90+
facebook
91+
google
92+
93+
94+
-- !query
95+
select company from like_any_table where company not like any ('%oo%',null)
96+
-- !query schema
97+
struct<company:string>
98+
-- !query output
99+
linkedin
100+
101+
102+
-- !query
103+
select company from like_any_table where company like any (null,null)
104+
-- !query schema
105+
struct<company:string>
106+
-- !query output
107+
108+
109+
110+
-- !query
111+
select company from like_any_table where company not like any (null,null)
112+
-- !query schema
113+
struct<company:string>
114+
-- !query output
115+

0 commit comments

Comments
 (0)