summaryrefslogtreecommitdiffstats
path: root/sqlglot/dialects/clickhouse.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 02:50:25 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 02:50:25 +0000
commitcf49728f719975144a958f23ba5f3336fb81ae55 (patch)
tree78aa5446e86cc5623808508ee167c9a476754939 /sqlglot/dialects/clickhouse.py
parentReleasing debian version 23.10.0-1. (diff)
downloadsqlglot-cf49728f719975144a958f23ba5f3336fb81ae55.tar.xz
sqlglot-cf49728f719975144a958f23ba5f3336fb81ae55.zip
Merging upstream version 23.12.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sqlglot/dialects/clickhouse.py')
-rw-r--r--sqlglot/dialects/clickhouse.py100
1 files changed, 66 insertions, 34 deletions
diff --git a/sqlglot/dialects/clickhouse.py b/sqlglot/dialects/clickhouse.py
index 34ee529..67e28d0 100644
--- a/sqlglot/dialects/clickhouse.py
+++ b/sqlglot/dialects/clickhouse.py
@@ -6,6 +6,7 @@ from sqlglot import exp, generator, parser, tokens, transforms
from sqlglot.dialects.dialect import (
Dialect,
arg_max_or_min_no_count,
+ build_formatted_time,
date_delta_sql,
inline_array_sql,
json_extract_segments,
@@ -19,6 +20,16 @@ from sqlglot.helper import is_int, seq_get
from sqlglot.tokens import Token, TokenType
+def _build_date_format(args: t.List) -> exp.TimeToStr:
+ expr = build_formatted_time(exp.TimeToStr, "clickhouse")(args)
+
+ timezone = seq_get(args, 2)
+ if timezone:
+ expr.set("timezone", timezone)
+
+ return expr
+
+
def _lower_func(sql: str) -> str:
index = sql.index("(")
return sql[:index].lower() + sql[index:]
@@ -124,6 +135,8 @@ class ClickHouse(Dialect):
"DATEDIFF": lambda args: exp.DateDiff(
this=seq_get(args, 2), expression=seq_get(args, 1), unit=seq_get(args, 0)
),
+ "DATE_FORMAT": _build_date_format,
+ "FORMATDATETIME": _build_date_format,
"JSONEXTRACTSTRING": build_json_extract_path(
exp.JSONExtractScalar, zero_based_indexing=False
),
@@ -241,6 +254,14 @@ class ClickHouse(Dialect):
"sparkBar",
"sumCount",
"largestTriangleThreeBuckets",
+ "histogram",
+ "sequenceMatch",
+ "sequenceCount",
+ "windowFunnel",
+ "retention",
+ "uniqUpTo",
+ "sequenceNextNode",
+ "exponentialTimeDecayedAvg",
}
AGG_FUNCTIONS_SUFFIXES = [
@@ -383,6 +404,7 @@ class ClickHouse(Dialect):
alias_tokens: t.Optional[t.Collection[TokenType]] = None,
parse_bracket: bool = False,
is_db_reference: bool = False,
+ parse_partition: bool = False,
) -> t.Optional[exp.Expression]:
this = super()._parse_table(
schema=schema,
@@ -447,46 +469,53 @@ class ClickHouse(Dialect):
functions: t.Optional[t.Dict[str, t.Callable]] = None,
anonymous: bool = False,
optional_parens: bool = True,
+ any_token: bool = False,
) -> t.Optional[exp.Expression]:
- func = super()._parse_function(
- functions=functions, anonymous=anonymous, optional_parens=optional_parens
+ expr = super()._parse_function(
+ functions=functions,
+ anonymous=anonymous,
+ optional_parens=optional_parens,
+ any_token=any_token,
+ )
+
+ func = expr.this if isinstance(expr, exp.Window) else expr
+
+ # Aggregate functions can be split in 2 parts: <func_name><suffix>
+ parts = (
+ self.AGG_FUNC_MAPPING.get(func.this) if isinstance(func, exp.Anonymous) else None
)
- if isinstance(func, exp.Anonymous):
- parts = self.AGG_FUNC_MAPPING.get(func.this)
+ if parts:
params = self._parse_func_params(func)
+ kwargs = {
+ "this": func.this,
+ "expressions": func.expressions,
+ }
+ if parts[1]:
+ kwargs["parts"] = parts
+ exp_class = exp.CombinedParameterizedAgg if params else exp.CombinedAggFunc
+ else:
+ exp_class = exp.ParameterizedAgg if params else exp.AnonymousAggFunc
+
+ kwargs["exp_class"] = exp_class
if params:
- if parts and parts[1]:
- return self.expression(
- exp.CombinedParameterizedAgg,
- this=func.this,
- expressions=func.expressions,
- params=params,
- parts=parts,
- )
- return self.expression(
- exp.ParameterizedAgg,
- this=func.this,
- expressions=func.expressions,
- params=params,
- )
-
- if parts:
- if parts[1]:
- return self.expression(
- exp.CombinedAggFunc,
- this=func.this,
- expressions=func.expressions,
- parts=parts,
- )
- return self.expression(
- exp.AnonymousAggFunc,
- this=func.this,
- expressions=func.expressions,
- )
-
- return func
+ kwargs["params"] = params
+
+ func = self.expression(**kwargs)
+
+ if isinstance(expr, exp.Window):
+ # The window's func was parsed as Anonymous in base parser, fix its
+ # type to be CH style CombinedAnonymousAggFunc / AnonymousAggFunc
+ expr.set("this", func)
+ elif params:
+ # Params have blocked super()._parse_function() from parsing the following window
+ # (if that exists) as they're standing between the function call and the window spec
+ expr = self._parse_window(func)
+ else:
+ expr = func
+
+ return expr
def _parse_func_params(
self, this: t.Optional[exp.Func] = None
@@ -653,6 +682,9 @@ class ClickHouse(Dialect):
exp.StrPosition: lambda self, e: self.func(
"position", e.this, e.args.get("substr"), e.args.get("position")
),
+ exp.TimeToStr: lambda self, e: self.func(
+ "DATE_FORMAT", e.this, self.format_time(e), e.args.get("timezone")
+ ),
exp.VarMap: lambda self, e: _lower_func(var_map_sql(self, e)),
exp.Xor: lambda self, e: self.func("xor", e.this, e.expression, *e.expressions),
}