Skip to content

Commit

Permalink
feat(clickhouse): Add support for APPLY query modifier
Browse files Browse the repository at this point in the history
  • Loading branch information
VaggelisD committed Sep 20, 2024
1 parent 77a514d commit f4d01f9
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 1 deletion.
10 changes: 10 additions & 0 deletions sqlglot/dialects/clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,16 @@ def _parse_projection_def(self) -> t.Optional[exp.ProjectionDef]:
def _parse_constraint(self) -> t.Optional[exp.Expression]:
return super()._parse_constraint() or self._parse_projection_def()

def _parse_alias(
self, this: t.Optional[exp.Expression], explicit: bool = False
) -> t.Optional[exp.Expression]:
# In clickhouse "SELECT <expr> APPLY(...)" is a query modifier,
# so "APPLY" shouldn't be parsed as <expr>'s alias. However, "SELECT <expr> apply" is a valid alias
if self._match_pair(TokenType.APPLY, TokenType.L_PAREN, advance=False):
return this

return super()._parse_alias(this=this, explicit=explicit)

class Generator(generator.Generator):
QUERY_HINTS = False
STRUCT_DELIMITER = ("(", ")")
Expand Down
1 change: 1 addition & 0 deletions sqlglot/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3103,6 +3103,7 @@ def isin(
"settings": False,
"format": False,
"options": False,
"apply": False,
}


Expand Down
5 changes: 4 additions & 1 deletion sqlglot/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2491,9 +2491,12 @@ def select_sql(self, expression: exp.Select) -> str:
# are the only dialects that use LIMIT_IS_TOP and both place DISTINCT first.
top_distinct = f"{distinct}{hint}{top}" if self.LIMIT_IS_TOP else f"{top}{hint}{distinct}"
expressions = f"{self.sep()}{expressions}" if expressions else expressions
apply = self.expressions(expression, key="apply", sep=" ")
apply = f"{self.sep()}{apply}" if apply else ""

sql = self.query_modifiers(
expression,
f"SELECT{top_distinct}{kind}{expressions}",
f"SELECT{top_distinct}{kind}{expressions}{apply}",
self.sql(expression, "into", comment=False),
self.sql(expression, "from", comment=False),
)
Expand Down
4 changes: 4 additions & 0 deletions sqlglot/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ class Parser(metaclass=_Parser):
TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}

FUNC_TOKENS = {
TokenType.APPLY,
TokenType.COLLATE,
TokenType.COMMAND,
TokenType.CURRENT_DATE,
Expand Down Expand Up @@ -2960,6 +2961,9 @@ def _parse_select(
)
this.comments = comments

while self._match_pair(TokenType.APPLY, TokenType.L_PAREN, advance=False):
this.append("apply", self._parse_function())

into = self._parse_into()
if into:
this.set("into", into)
Expand Down
6 changes: 6 additions & 0 deletions tests/dialects/test_clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,12 @@ def test_clickhouse(self):
self.validate_identity("SELECT TRIM(LEADING '(' FROM '( Hello, world! )')")
self.validate_identity("current_timestamp").assert_is(exp.Column)

self.validate_identity("SELECT * APPLY(sum) FROM columns_transformers")
self.validate_identity("SELECT COLUMNS('[jk]') APPLY(toString) FROM columns_transformers")
self.validate_identity(
"SELECT COLUMNS('[jk]') APPLY(toString) APPLY(length) APPLY(max) FROM columns_transformers"
)

def test_clickhouse_values(self):
values = exp.select("*").from_(
exp.values([exp.tuple_(1, 2, 3)], alias="subq", columns=["a", "b", "c"])
Expand Down

0 comments on commit f4d01f9

Please sign in to comment.