Skip to content

Commit

Permalink
feat(snowflake): FINAL/RUNNING keywords in MATCH_RECOGNIZE MEASURES (#…
Browse files Browse the repository at this point in the history
…3284)

* feat(snowflake): FINAL/RUNNING keywords in MATCH_RECOGNIZE MEASURES

* Refactor parse_match_recognize_measure

Co-authored-by: Jo <46752250+georgesittas@users.noreply.github.com>

* First iteration

---------

Co-authored-by: Jo <46752250+georgesittas@users.noreply.github.com>
  • Loading branch information
VaggelisD and georgesittas authored Apr 8, 2024
1 parent 46fbd8d commit 0690cbc
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 19 deletions.
7 changes: 7 additions & 0 deletions sqlglot/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2225,6 +2225,13 @@ class Lateral(UDTF):
}


class MatchRecognizeMeasure(Expression):
arg_types = {
"this": True,
"window_frame": False,
}


class MatchRecognize(Expression):
arg_types = {
"partition_by": False,
Expand Down
8 changes: 8 additions & 0 deletions sqlglot/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2111,6 +2111,14 @@ def ordered_sql(self, expression: exp.Ordered) -> str:

return f"{this}{sort_order}{nulls_sort_change}{with_fill}"

def matchrecognizemeasure_sql(self, expression: exp.MatchRecognizeMeasure) -> str:
window_frame = self.sql(expression, "window_frame")
window_frame = f"{window_frame} " if window_frame else ""

this = self.sql(expression, "this")

return f"{window_frame}{this}"

def matchrecognize_sql(self, expression: exp.MatchRecognize) -> str:
partition = self.partition_by_sql(expression)
order = self.sql(expression, "order")
Expand Down
14 changes: 13 additions & 1 deletion sqlglot/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2738,6 +2738,13 @@ def _parse_from(
exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
)

def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
return self.expression(
exp.MatchRecognizeMeasure,
window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
this=self._parse_expression(),
)

def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
if not self._match(TokenType.MATCH_RECOGNIZE):
return None
Expand All @@ -2746,7 +2753,12 @@ def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:

partition = self._parse_partition_by()
order = self._parse_order()
measures = self._parse_expressions() if self._match_text_seq("MEASURES") else None

measures = (
self._parse_csv(self._parse_match_recognize_measure)
if self._match_text_seq("MEASURES")
else None
)

if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
rows = exp.var("ONE ROW PER MATCH")
Expand Down
40 changes: 22 additions & 18 deletions tests/dialects/test_snowflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -1575,38 +1575,42 @@ def test_regexp_replace(self, logger):
)

def test_match_recognize(self):
for row in (
"ONE ROW PER MATCH",
"ALL ROWS PER MATCH",
"ALL ROWS PER MATCH SHOW EMPTY MATCHES",
"ALL ROWS PER MATCH OMIT EMPTY MATCHES",
"ALL ROWS PER MATCH WITH UNMATCHED ROWS",
):
for after in (
"AFTER MATCH SKIP",
"AFTER MATCH SKIP PAST LAST ROW",
"AFTER MATCH SKIP TO NEXT ROW",
"AFTER MATCH SKIP TO FIRST x",
"AFTER MATCH SKIP TO LAST x",
for window_frame in ("", "FINAL ", "RUNNING "):
for row in (
"ONE ROW PER MATCH",
"ALL ROWS PER MATCH",
"ALL ROWS PER MATCH SHOW EMPTY MATCHES",
"ALL ROWS PER MATCH OMIT EMPTY MATCHES",
"ALL ROWS PER MATCH WITH UNMATCHED ROWS",
):
self.validate_identity(
f"""SELECT
for after in (
"AFTER MATCH SKIP",
"AFTER MATCH SKIP PAST LAST ROW",
"AFTER MATCH SKIP TO NEXT ROW",
"AFTER MATCH SKIP TO FIRST x",
"AFTER MATCH SKIP TO LAST x",
):
with self.subTest(
f"MATCH_RECOGNIZE with window frame {window_frame}, rows {row}, after {after}: "
):
self.validate_identity(
f"""SELECT
*
FROM x
MATCH_RECOGNIZE (
PARTITION BY a, b
ORDER BY
x DESC
MEASURES
y AS b
{window_frame}y AS b
{row}
{after}
PATTERN (^ S1 S2*? ( {{- S3 -}} S4 )+ | PERMUTE(S1, S2){{1,2}} $)
DEFINE
x AS y
)""",
pretty=True,
)
pretty=True,
)

def test_show_users(self):
self.validate_identity("SHOW USERS")
Expand Down

0 comments on commit 0690cbc

Please sign in to comment.