diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 05:35:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 05:35:55 +0000 |
commit | fe979e8421c04c038353a0a2d07d81779516186a (patch) | |
tree | efb70a52261e5cf4862a7eb69e1d7cd16356fcba /sqlglot/dialects/clickhouse.py | |
parent | Releasing debian version 23.13.7-1. (diff) | |
download | sqlglot-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.py | 92 |
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)}" |