summaryrefslogtreecommitdiffstats
path: root/sqlglot/dialects/clickhouse.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 05:35:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 05:35:55 +0000
commitfe979e8421c04c038353a0a2d07d81779516186a (patch)
treeefb70a52261e5cf4862a7eb69e1d7cd16356fcba /sqlglot/dialects/clickhouse.py
parentReleasing debian version 23.13.7-1. (diff)
downloadsqlglot-fe979e8421c04c038353a0a2d07d81779516186a.tar.xz
sqlglot-fe979e8421c04c038353a0a2d07d81779516186a.zip
Merging upstream version 23.16.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sqlglot/dialects/clickhouse.py')
-rw-r--r--sqlglot/dialects/clickhouse.py92
1 files changed, 92 insertions, 0 deletions
diff --git a/sqlglot/dialects/clickhouse.py b/sqlglot/dialects/clickhouse.py
index 67e28d0..7615203 100644
--- a/sqlglot/dialects/clickhouse.py
+++ b/sqlglot/dialects/clickhouse.py
@@ -15,6 +15,7 @@ from sqlglot.dialects.dialect import (
build_json_extract_path,
rename_func,
var_map_sql,
+ timestamptrunc_sql,
)
from sqlglot.helper import is_int, seq_get
from sqlglot.tokens import Token, TokenType
@@ -30,6 +31,27 @@ def _build_date_format(args: t.List) -> exp.TimeToStr:
return expr
+def _unix_to_time_sql(self: ClickHouse.Generator, expression: exp.UnixToTime) -> str:
+ scale = expression.args.get("scale")
+ timestamp = expression.this
+
+ if scale in (None, exp.UnixToTime.SECONDS):
+ return self.func("fromUnixTimestamp", exp.cast(timestamp, exp.DataType.Type.BIGINT))
+ if scale == exp.UnixToTime.MILLIS:
+ return self.func("fromUnixTimestamp64Milli", exp.cast(timestamp, exp.DataType.Type.BIGINT))
+ if scale == exp.UnixToTime.MICROS:
+ return self.func("fromUnixTimestamp64Micro", exp.cast(timestamp, exp.DataType.Type.BIGINT))
+ if scale == exp.UnixToTime.NANOS:
+ return self.func("fromUnixTimestamp64Nano", exp.cast(timestamp, exp.DataType.Type.BIGINT))
+
+ return self.func(
+ "fromUnixTimestamp",
+ exp.cast(
+ exp.Div(this=timestamp, expression=exp.func("POW", 10, scale)), exp.DataType.Type.BIGINT
+ ),
+ )
+
+
def _lower_func(sql: str) -> str:
index = sql.index("(")
return sql[:index].lower() + sql[index:]
@@ -146,6 +168,9 @@ class ClickHouse(Dialect):
"TUPLE": exp.Struct.from_arg_list,
"UNIQ": exp.ApproxDistinct.from_arg_list,
"XOR": lambda args: exp.Xor(expressions=args),
+ "MD5": exp.MD5Digest.from_arg_list,
+ "SHA256": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(256)),
+ "SHA512": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(512)),
}
AGG_FUNCTIONS = {
@@ -353,6 +378,11 @@ class ClickHouse(Dialect):
"CODEC": lambda self: self._parse_compress(),
}
+ ALTER_PARSERS = {
+ **parser.Parser.ALTER_PARSERS,
+ "REPLACE": lambda self: self._parse_alter_table_replace(),
+ }
+
SCHEMA_UNNAMED_CONSTRAINTS = {
*parser.Parser.SCHEMA_UNNAMED_CONSTRAINTS,
"INDEX",
@@ -578,6 +608,44 @@ class ClickHouse(Dialect):
granularity=granularity,
)
+ def _parse_partition(self) -> t.Optional[exp.Partition]:
+ # https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#how-to-set-partition-expression
+ if not self._match(TokenType.PARTITION):
+ return None
+
+ if self._match_text_seq("ID"):
+ # Corresponds to the PARTITION ID <string_value> syntax
+ expressions: t.List[exp.Expression] = [
+ self.expression(exp.PartitionId, this=self._parse_string())
+ ]
+ else:
+ expressions = self._parse_expressions()
+
+ return self.expression(exp.Partition, expressions=expressions)
+
+ def _parse_alter_table_replace(self) -> t.Optional[exp.Expression]:
+ partition = self._parse_partition()
+
+ if not partition or not self._match(TokenType.FROM):
+ return None
+
+ return self.expression(
+ exp.ReplacePartition, expression=partition, source=self._parse_table_parts()
+ )
+
+ def _parse_projection_def(self) -> t.Optional[exp.ProjectionDef]:
+ if not self._match_text_seq("PROJECTION"):
+ return None
+
+ return self.expression(
+ exp.ProjectionDef,
+ this=self._parse_id_var(),
+ expression=self._parse_wrapped(self._parse_statement),
+ )
+
+ def _parse_constraint(self) -> t.Optional[exp.Expression]:
+ return super()._parse_constraint() or self._parse_projection_def()
+
class Generator(generator.Generator):
QUERY_HINTS = False
STRUCT_DELIMITER = ("(", ")")
@@ -687,6 +755,16 @@ class ClickHouse(Dialect):
),
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),
+ exp.MD5Digest: rename_func("MD5"),
+ exp.MD5: lambda self, e: self.func("LOWER", self.func("HEX", self.func("MD5", e.this))),
+ exp.SHA: rename_func("SHA1"),
+ exp.SHA2: lambda self, e: self.func(
+ "SHA256" if e.text("length") == "256" else "SHA512", e.this
+ ),
+ exp.UnixToTime: _unix_to_time_sql,
+ exp.TimestampTrunc: timestamptrunc_sql(zone=True),
+ exp.Variance: rename_func("varSamp"),
+ exp.Stddev: rename_func("stddevSamp"),
}
PROPERTIES_LOCATION = {
@@ -828,3 +906,17 @@ class ClickHouse(Dialect):
granularity = f" GRANULARITY {granularity}" if granularity else ""
return f"INDEX{this}{expr}{index_type}{granularity}"
+
+ def partition_sql(self, expression: exp.Partition) -> str:
+ return f"PARTITION {self.expressions(expression, flat=True)}"
+
+ def partitionid_sql(self, expression: exp.PartitionId) -> str:
+ return f"ID {self.sql(expression.this)}"
+
+ def replacepartition_sql(self, expression: exp.ReplacePartition) -> str:
+ return (
+ f"REPLACE {self.sql(expression.expression)} FROM {self.sql(expression, 'source')}"
+ )
+
+ def projectiondef_sql(self, expression: exp.ProjectionDef) -> str:
+ return f"PROJECTION {self.sql(expression.this)} {self.wrap(expression.expression)}"