Skip to content

Commit 9694999

Browse files
authored
feat: Add support for CONTAINS(...) (#4399)
1 parent 79f6783 commit 9694999

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed

sqlglot/dialects/bigquery.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,18 @@ def _builder(args: t.List) -> exp.TimeToStr:
312312
return _builder
313313

314314

315+
def _build_contains_substring(args: t.List) -> exp.Contains | exp.Anonymous:
316+
if len(args) == 3:
317+
return exp.Anonymous(this="CONTAINS_SUBSTRING", expressions=args)
318+
319+
# Lowercase the operands in case of transpilation, as exp.Contains
320+
# is case-sensitive on other dialects
321+
this = exp.Lower(this=seq_get(args, 0))
322+
expr = exp.Lower(this=seq_get(args, 1))
323+
324+
return exp.Contains(this=this, expression=expr)
325+
326+
315327
class BigQuery(Dialect):
316328
WEEK_OFFSET = -1
317329
UNNEST_COLUMN_ONLY = True
@@ -457,6 +469,7 @@ class Parser(parser.Parser):
457469

458470
FUNCTIONS = {
459471
**parser.Parser.FUNCTIONS,
472+
"CONTAINS_SUBSTRING": _build_contains_substring,
460473
"DATE": _build_date,
461474
"DATE_ADD": build_date_delta_with_interval(exp.DateAdd),
462475
"DATE_SUB": build_date_delta_with_interval(exp.DateSub),
@@ -1153,3 +1166,13 @@ def version_sql(self, expression: exp.Version) -> str:
11531166
if expression.name == "TIMESTAMP":
11541167
expression.set("this", "SYSTEM_TIME")
11551168
return super().version_sql(expression)
1169+
1170+
def contains_sql(self, expression: exp.Contains) -> str:
1171+
this = expression.this
1172+
expr = expression.expression
1173+
1174+
if isinstance(this, exp.Lower) and isinstance(expr, exp.Lower):
1175+
this = this.this
1176+
expr = expr.this
1177+
1178+
return self.func("CONTAINS_SUBSTRING", this, expr)

sqlglot/expressions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5460,6 +5460,10 @@ class ConcatWs(Concat):
54605460
_sql_names = ["CONCAT_WS"]
54615461

54625462

5463+
class Contains(Func):
5464+
arg_types = {"this": True, "expression": True}
5465+
5466+
54635467
# https://docs.oracle.com/cd/B13789_01/server.101/b10759/operators004.htm#i1035022
54645468
class ConnectByRoot(Func):
54655469
pass

tests/dialects/test_bigquery.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,6 +1615,31 @@ def test_bigquery(self):
16151615
},
16161616
)
16171617

1618+
self.validate_identity(
1619+
"CONTAINS_SUBSTRING(a, b, json_scope => 'JSON_KEYS_AND_VALUES')"
1620+
).assert_is(exp.Anonymous)
1621+
1622+
self.validate_all(
1623+
"""CONTAINS_SUBSTRING(a, b)""",
1624+
read={
1625+
"": "CONTAINS(a, b)",
1626+
"spark": "CONTAINS(a, b)",
1627+
"databricks": "CONTAINS(a, b)",
1628+
"snowflake": "CONTAINS(a, b)",
1629+
"duckdb": "CONTAINS(a, b)",
1630+
"oracle": "CONTAINS(a, b)",
1631+
},
1632+
write={
1633+
"": "CONTAINS(LOWER(a), LOWER(b))",
1634+
"spark": "CONTAINS(LOWER(a), LOWER(b))",
1635+
"databricks": "CONTAINS(LOWER(a), LOWER(b))",
1636+
"snowflake": "CONTAINS(LOWER(a), LOWER(b))",
1637+
"duckdb": "CONTAINS(LOWER(a), LOWER(b))",
1638+
"oracle": "CONTAINS(LOWER(a), LOWER(b))",
1639+
"bigquery": "CONTAINS_SUBSTRING(a, b)",
1640+
},
1641+
)
1642+
16181643
def test_errors(self):
16191644
with self.assertRaises(TokenError):
16201645
transpile("'\\'", read="bigquery")

0 commit comments

Comments
 (0)