Repository: tobymao/sqlglot

Issue:
Calling `match` as a function fails to parse
In ibis, our ClickHouse backend uses [the `match` function](https://clickhouse.com/docs/en/sql-reference/functions/string-search-functions#matchhaystack-pattern-haystack-regexp-pattern-operator) for regular expression searching.

In 11.5.1 this function now fails to parse (it worked in 11.4.x):

```
In [4]: import sqlglot as sg

In [5]: sg.__version__
Out[5]: '11.5.1'

In [6]: sg.parse_one("select match('abc', '([a-z]+)')", read="clickhouse")
...
ParseError: Required keyword: 'this' missing for <class 'sqlglot.expressions.MatchAgainst'>. Line 1, Col: 31.
  select match('abc', '([a-z]+)')
```

Unfortunately, switching to using `a REGEXP b` also doesn't work because that gets turned into a call to `REGEXP_LIKE` which isn't a function in ClickHouse so we can't upgrade our sqlglot version to pick up the fix to #1377 because it breaks our ClickHouse backend.


Discussion:
I guess there are two issues here:

1. `match` doesn't parse
2. `a REGEXP b` should be turned into a `match` function call, and not a `REGEXP_LIKE` call for the ClickHouse dialect.
We can work around this problem in ibis for now by using [`multiMatchAny(arg, [pattern])`](https://clickhouse.com/docs/en/sql-reference/functions/string-search-functions#multimatchanyhaystack-pattern1-pattern2--patternn).
Thanks for reporting this, the parser fail is related to https://github.com/tobymao/sqlglot/commit/dc494fc650950d02cb35801d7811f30e032c2d13 (before it was parsed as anonymous). I'll try to fix both issues.
@cpcloud I'm trying to run a query that uses `REGEXP`, but it doesn't seem to work as expected:

```sql
select 'abc' regexp '([a-z]+)'
```
> Code: 62. DB::Exception: Syntax error: failed at position 21 (''([a-z]+)''): '([a-z]+)'. Expected one of: token, Comma, FROM, PREWHERE, WHERE, GROUP BY, WITH, HAVING, WINDOW, ORDER BY, LIMIT, OFFSET, SETTINGS, UNION, EXCEPT, INTERSECT, INTO OUTFILE, FORMAT, end of query. (SYNTAX_ERROR) (version 23.3.1.1731 (official build))

Am I using this correctly? If yes, can you please check it too? I ran the above query in play.clickhouse.com

Note: `select match('abc', '([a-z]+)')` works as expected.

Resolving patch:
diff --git a/sqlglot/dialects/clickhouse.py b/sqlglot/dialects/clickhouse.py
--- a/sqlglot/dialects/clickhouse.py
+++ b/sqlglot/dialects/clickhouse.py
@@ -46,18 +46,22 @@ class Parser(parser.Parser):
                 time=seq_get(args, 1),
                 decay=seq_get(params, 0),
             ),
-            "MAP": parse_var_map,
-            "HISTOGRAM": lambda params, args: exp.Histogram(
-                this=seq_get(args, 0), bins=seq_get(params, 0)
-            ),
             "GROUPUNIQARRAY": lambda params, args: exp.GroupUniqArray(
                 this=seq_get(args, 0), size=seq_get(params, 0)
             ),
+            "HISTOGRAM": lambda params, args: exp.Histogram(
+                this=seq_get(args, 0), bins=seq_get(params, 0)
+            ),
+            "MAP": parse_var_map,
+            "MATCH": exp.RegexpLike.from_arg_list,
             "QUANTILE": lambda params, args: exp.Quantile(this=args, quantile=params),
             "QUANTILES": lambda params, args: exp.Quantiles(parameters=params, expressions=args),
             "QUANTILEIF": lambda params, args: exp.QuantileIf(parameters=params, expressions=args),
         }
 
+        FUNCTION_PARSERS = parser.Parser.FUNCTION_PARSERS.copy()
+        FUNCTION_PARSERS.pop("MATCH")
+
         RANGE_PARSERS = {
             **parser.Parser.RANGE_PARSERS,
             TokenType.GLOBAL: lambda self, this: self._match(TokenType.IN)
@@ -135,6 +139,7 @@ class Generator(generator.Generator):
             exp.Quantile: lambda self, e: f"quantile{self._param_args_sql(e, 'quantile', 'this')}",
             exp.Quantiles: lambda self, e: f"quantiles{self._param_args_sql(e, 'parameters', 'expressions')}",
             exp.QuantileIf: lambda self, e: f"quantileIf{self._param_args_sql(e, 'parameters', 'expressions')}",
+            exp.RegexpLike: lambda self, e: f"match({self.format_args(e.this, e.expression)})",
             exp.StrPosition: lambda self, e: f"position({self.format_args(e.this, e.args.get('substr'), e.args.get('position'))})",
             exp.VarMap: lambda self, e: _lower_func(var_map_sql(self, e)),
         }


Test patch:
diff --git a/tests/dialects/test_clickhouse.py b/tests/dialects/test_clickhouse.py
--- a/tests/dialects/test_clickhouse.py
+++ b/tests/dialects/test_clickhouse.py
@@ -5,6 +5,7 @@ class TestClickhouse(Validator):
     dialect = "clickhouse"
 
     def test_clickhouse(self):
+        self.validate_identity("SELECT match('abc', '([a-z]+)')")
         self.validate_identity("dictGet(x, 'y')")
         self.validate_identity("SELECT * FROM x FINAL")
         self.validate_identity("SELECT * FROM x AS y FINAL")