Skip to content

Commit

Permalink
Fix(clickhouse): USING allows unwrapped col list (#1615)
Browse files Browse the repository at this point in the history
I.e. both `USING a, b, c` and `USING (a, b, c)` are allowed
Although the wrapped variant is a canonical one (see docs)

Co-authored-by: Toby Mao <[email protected]>
  • Loading branch information
pkit and tobymao authored May 14, 2023
1 parent a67b2de commit 6875d07
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 7 deletions.
5 changes: 5 additions & 0 deletions sqlglot/dialects/clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ def _parse_quantile(self) -> exp.Quantile:
return self.expression(exp.Quantile, this=params[0], quantile=this)
return self.expression(exp.Quantile, this=this, quantile=exp.Literal.number(0.5))

def _parse_wrapped_id_vars(
self, optional: bool = False
) -> t.List[t.Optional[exp.Expression]]:
return super()._parse_wrapped_id_vars(optional=True)

class Generator(generator.Generator):
STRUCT_DELIMITER = ("(", ")")

Expand Down
19 changes: 12 additions & 7 deletions sqlglot/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4070,18 +4070,23 @@ def _parse_tokens(

return this

def _parse_wrapped_id_vars(self) -> t.List[t.Optional[exp.Expression]]:
return self._parse_wrapped_csv(self._parse_id_var)
def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[t.Optional[exp.Expression]]:
return self._parse_wrapped_csv(self._parse_id_var, optional=optional)

def _parse_wrapped_csv(
self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
) -> t.List[t.Optional[exp.Expression]]:
return self._parse_wrapped(lambda: self._parse_csv(parse_method, sep=sep))
return self._parse_wrapped(
lambda: self._parse_csv(parse_method, sep=sep), optional=optional
)

def _parse_wrapped(self, parse_method: t.Callable) -> t.Any:
self._match_l_paren()
def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
wrapped = self._match(TokenType.L_PAREN)
if not wrapped and not optional:
self.raise_error("Expecting (")
parse_result = parse_method()
self._match_r_paren()
if wrapped:
self._match_r_paren()
return parse_result

def _parse_select_or_expression(self) -> t.Optional[exp.Expression]:
Expand Down
4 changes: 4 additions & 0 deletions tests/dialects/test_clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ def test_clickhouse(self):
self.validate_identity(
"SELECT * FROM x LIMIT 10 SETTINGS max_results = 100, result_ FORMAT PrettyCompact"
)
self.validate_all(
"SELECT * FROM foo JOIN bar USING id, name",
write={"clickhouse": "SELECT * FROM foo JOIN bar USING (id, name)"},
)
self.validate_all(
"SELECT * FROM foo ANY LEFT JOIN bla ON foo.c1 = bla.c2",
write={"clickhouse": "SELECT * FROM foo LEFT ANY JOIN bla ON foo.c1 = bla.c2"},
Expand Down

0 comments on commit 6875d07

Please sign in to comment.