Merging upstream version 10.1.3.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
582b160275
commit
a5128ea109
57 changed files with 1542 additions and 529 deletions
|
@ -56,12 +56,12 @@ def _derived_table_values_to_unnest(self, expression):
|
|||
|
||||
|
||||
def _returnsproperty_sql(self, expression):
|
||||
value = expression.args.get("value")
|
||||
if isinstance(value, exp.Schema):
|
||||
value = f"{value.this} <{self.expressions(value)}>"
|
||||
this = expression.this
|
||||
if isinstance(this, exp.Schema):
|
||||
this = f"{this.this} <{self.expressions(this)}>"
|
||||
else:
|
||||
value = self.sql(value)
|
||||
return f"RETURNS {value}"
|
||||
this = self.sql(this)
|
||||
return f"RETURNS {this}"
|
||||
|
||||
|
||||
def _create_sql(self, expression):
|
||||
|
@ -142,6 +142,11 @@ class BigQuery(Dialect):
|
|||
),
|
||||
}
|
||||
|
||||
FUNCTION_PARSERS = {
|
||||
**parser.Parser.FUNCTION_PARSERS,
|
||||
}
|
||||
FUNCTION_PARSERS.pop("TRIM")
|
||||
|
||||
NO_PAREN_FUNCTIONS = {
|
||||
**parser.Parser.NO_PAREN_FUNCTIONS,
|
||||
TokenType.CURRENT_DATETIME: exp.CurrentDatetime,
|
||||
|
@ -174,6 +179,7 @@ class BigQuery(Dialect):
|
|||
exp.Values: _derived_table_values_to_unnest,
|
||||
exp.ReturnsProperty: _returnsproperty_sql,
|
||||
exp.Create: _create_sql,
|
||||
exp.Trim: lambda self, e: f"TRIM({self.format_args(e.this, e.expression)})",
|
||||
exp.VolatilityProperty: lambda self, e: f"DETERMINISTIC"
|
||||
if e.name == "IMMUTABLE"
|
||||
else "NOT DETERMINISTIC",
|
||||
|
@ -200,9 +206,7 @@ class BigQuery(Dialect):
|
|||
exp.VolatilityProperty,
|
||||
}
|
||||
|
||||
WITH_PROPERTIES = {
|
||||
exp.AnonymousProperty,
|
||||
}
|
||||
WITH_PROPERTIES = {exp.Property}
|
||||
|
||||
EXPLICIT_UNION = True
|
||||
|
||||
|
|
|
@ -21,14 +21,15 @@ class ClickHouse(Dialect):
|
|||
|
||||
KEYWORDS = {
|
||||
**tokens.Tokenizer.KEYWORDS,
|
||||
"FINAL": TokenType.FINAL,
|
||||
"ASOF": TokenType.ASOF,
|
||||
"DATETIME64": TokenType.DATETIME,
|
||||
"INT8": TokenType.TINYINT,
|
||||
"FINAL": TokenType.FINAL,
|
||||
"FLOAT32": TokenType.FLOAT,
|
||||
"FLOAT64": TokenType.DOUBLE,
|
||||
"INT16": TokenType.SMALLINT,
|
||||
"INT32": TokenType.INT,
|
||||
"INT64": TokenType.BIGINT,
|
||||
"FLOAT32": TokenType.FLOAT,
|
||||
"FLOAT64": TokenType.DOUBLE,
|
||||
"INT8": TokenType.TINYINT,
|
||||
"TUPLE": TokenType.STRUCT,
|
||||
}
|
||||
|
||||
|
@ -38,6 +39,10 @@ class ClickHouse(Dialect):
|
|||
"MAP": parse_var_map,
|
||||
}
|
||||
|
||||
JOIN_KINDS = {*parser.Parser.JOIN_KINDS, TokenType.ANY, TokenType.ASOF}
|
||||
|
||||
TABLE_ALIAS_TOKENS = {*parser.Parser.TABLE_ALIAS_TOKENS} - {TokenType.ANY}
|
||||
|
||||
def _parse_table(self, schema=False):
|
||||
this = super()._parse_table(schema)
|
||||
|
||||
|
|
|
@ -289,19 +289,19 @@ def struct_extract_sql(self, expression):
|
|||
return f"{this}.{struct_key}"
|
||||
|
||||
|
||||
def var_map_sql(self, expression):
|
||||
def var_map_sql(self, expression, map_func_name="MAP"):
|
||||
keys = expression.args["keys"]
|
||||
values = expression.args["values"]
|
||||
|
||||
if not isinstance(keys, exp.Array) or not isinstance(values, exp.Array):
|
||||
self.unsupported("Cannot convert array columns into map.")
|
||||
return f"MAP({self.format_args(keys, values)})"
|
||||
return f"{map_func_name}({self.format_args(keys, values)})"
|
||||
|
||||
args = []
|
||||
for key, value in zip(keys.expressions, values.expressions):
|
||||
args.append(self.sql(key))
|
||||
args.append(self.sql(value))
|
||||
return f"MAP({self.format_args(*args)})"
|
||||
return f"{map_func_name}({self.format_args(*args)})"
|
||||
|
||||
|
||||
def format_time_lambda(exp_class, dialect, default=None):
|
||||
|
@ -336,18 +336,13 @@ def create_with_partitions_sql(self, expression):
|
|||
if has_schema and is_partitionable:
|
||||
expression = expression.copy()
|
||||
prop = expression.find(exp.PartitionedByProperty)
|
||||
value = prop and prop.args.get("value")
|
||||
if prop and not isinstance(value, exp.Schema):
|
||||
this = prop and prop.this
|
||||
if prop and not isinstance(this, exp.Schema):
|
||||
schema = expression.this
|
||||
columns = {v.name.upper() for v in value.expressions}
|
||||
columns = {v.name.upper() for v in this.expressions}
|
||||
partitions = [col for col in schema.expressions if col.name.upper() in columns]
|
||||
schema.set(
|
||||
"expressions",
|
||||
[e for e in schema.expressions if e not in partitions],
|
||||
)
|
||||
prop.replace(
|
||||
exp.PartitionedByProperty(this=prop.this, value=exp.Schema(expressions=partitions))
|
||||
)
|
||||
schema.set("expressions", [e for e in schema.expressions if e not in partitions])
|
||||
prop.replace(exp.PartitionedByProperty(this=exp.Schema(expressions=partitions)))
|
||||
expression.set("this", schema)
|
||||
|
||||
return self.create_sql(expression)
|
||||
|
|
|
@ -153,7 +153,7 @@ class Drill(Dialect):
|
|||
exp.If: if_sql,
|
||||
exp.ILike: lambda self, e: f" {self.sql(e, 'this')} `ILIKE` {self.sql(e, 'expression')}",
|
||||
exp.Levenshtein: rename_func("LEVENSHTEIN_DISTANCE"),
|
||||
exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'value')}",
|
||||
exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}",
|
||||
exp.Pivot: no_pivot_sql,
|
||||
exp.RegexpLike: rename_func("REGEXP_MATCHES"),
|
||||
exp.StrPosition: str_position_sql,
|
||||
|
|
|
@ -61,9 +61,7 @@ def _array_sort(self, expression):
|
|||
|
||||
|
||||
def _property_sql(self, expression):
|
||||
key = expression.name
|
||||
value = self.sql(expression, "value")
|
||||
return f"'{key}'={value}"
|
||||
return f"'{expression.name}'={self.sql(expression, 'value')}"
|
||||
|
||||
|
||||
def _str_to_unix(self, expression):
|
||||
|
@ -250,7 +248,7 @@ class Hive(Dialect):
|
|||
TRANSFORMS = {
|
||||
**generator.Generator.TRANSFORMS,
|
||||
**transforms.UNALIAS_GROUP, # type: ignore
|
||||
exp.AnonymousProperty: _property_sql,
|
||||
exp.Property: _property_sql,
|
||||
exp.ApproxDistinct: approx_count_distinct_sql,
|
||||
exp.ArrayAgg: rename_func("COLLECT_LIST"),
|
||||
exp.ArrayConcat: rename_func("CONCAT"),
|
||||
|
@ -262,7 +260,7 @@ class Hive(Dialect):
|
|||
exp.DateStrToDate: rename_func("TO_DATE"),
|
||||
exp.DateToDi: lambda self, e: f"CAST(DATE_FORMAT({self.sql(e, 'this')}, {Hive.dateint_format}) AS INT)",
|
||||
exp.DiToDate: lambda self, e: f"TO_DATE(CAST({self.sql(e, 'this')} AS STRING), {Hive.dateint_format})",
|
||||
exp.FileFormatProperty: lambda self, e: f"STORED AS {e.text('value').upper()}",
|
||||
exp.FileFormatProperty: lambda self, e: f"STORED AS {e.name.upper()}",
|
||||
exp.If: if_sql,
|
||||
exp.Index: _index_sql,
|
||||
exp.ILike: no_ilike_sql,
|
||||
|
@ -285,7 +283,7 @@ class Hive(Dialect):
|
|||
exp.StrToTime: _str_to_time,
|
||||
exp.StrToUnix: _str_to_unix,
|
||||
exp.StructExtract: struct_extract_sql,
|
||||
exp.TableFormatProperty: lambda self, e: f"USING {self.sql(e, 'value')}",
|
||||
exp.TableFormatProperty: lambda self, e: f"USING {self.sql(e, 'this')}",
|
||||
exp.TimeStrToDate: rename_func("TO_DATE"),
|
||||
exp.TimeStrToTime: lambda self, e: f"CAST({self.sql(e, 'this')} AS TIMESTAMP)",
|
||||
exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"),
|
||||
|
@ -298,11 +296,11 @@ class Hive(Dialect):
|
|||
exp.UnixToStr: lambda self, e: f"FROM_UNIXTIME({self.format_args(e.this, _time_format(self, e))})",
|
||||
exp.UnixToTime: rename_func("FROM_UNIXTIME"),
|
||||
exp.UnixToTimeStr: rename_func("FROM_UNIXTIME"),
|
||||
exp.PartitionedByProperty: lambda self, e: f"PARTITIONED BY {self.sql(e, 'value')}",
|
||||
exp.PartitionedByProperty: lambda self, e: f"PARTITIONED BY {self.sql(e, 'this')}",
|
||||
exp.NumberToStr: rename_func("FORMAT_NUMBER"),
|
||||
}
|
||||
|
||||
WITH_PROPERTIES = {exp.AnonymousProperty}
|
||||
WITH_PROPERTIES = {exp.Property}
|
||||
|
||||
ROOT_PROPERTIES = {
|
||||
exp.PartitionedByProperty,
|
||||
|
|
|
@ -453,6 +453,7 @@ class MySQL(Dialect):
|
|||
exp.CharacterSetProperty,
|
||||
exp.CollateProperty,
|
||||
exp.SchemaCommentProperty,
|
||||
exp.LikeProperty,
|
||||
}
|
||||
|
||||
WITH_PROPERTIES: t.Set[t.Type[exp.Property]] = set()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from sqlglot import exp, generator, tokens, transforms
|
||||
from sqlglot.dialects.dialect import Dialect, no_ilike_sql
|
||||
from sqlglot import exp, generator, parser, tokens, transforms
|
||||
from sqlglot.dialects.dialect import Dialect, no_ilike_sql, rename_func
|
||||
from sqlglot.helper import csv
|
||||
from sqlglot.tokens import TokenType
|
||||
|
||||
|
@ -37,6 +37,12 @@ class Oracle(Dialect):
|
|||
"YYYY": "%Y", # 2015
|
||||
}
|
||||
|
||||
class Parser(parser.Parser):
|
||||
FUNCTIONS = {
|
||||
**parser.Parser.FUNCTIONS,
|
||||
"DECODE": exp.Matches.from_arg_list,
|
||||
}
|
||||
|
||||
class Generator(generator.Generator):
|
||||
TYPE_MAPPING = {
|
||||
**generator.Generator.TYPE_MAPPING,
|
||||
|
@ -58,6 +64,7 @@ class Oracle(Dialect):
|
|||
**transforms.UNALIAS_GROUP, # type: ignore
|
||||
exp.ILike: no_ilike_sql,
|
||||
exp.Limit: _limit_sql,
|
||||
exp.Matches: rename_func("DECODE"),
|
||||
exp.StrToTime: lambda self, e: f"TO_TIMESTAMP({self.sql(e, 'this')}, {self.format_time(e)})",
|
||||
exp.TimeToStr: lambda self, e: f"TO_CHAR({self.sql(e, 'this')}, {self.format_time(e)})",
|
||||
exp.UnixToTime: lambda self, e: f"TO_DATE('1970-01-01','YYYY-MM-DD') + ({self.sql(e, 'this')} / 86400)",
|
||||
|
|
|
@ -74,6 +74,27 @@ def _trim_sql(self, expression):
|
|||
return f"TRIM({trim_type}{remove_chars}{from_part}{target}{collation})"
|
||||
|
||||
|
||||
def _string_agg_sql(self, expression):
|
||||
expression = expression.copy()
|
||||
separator = expression.args.get("separator") or exp.Literal.string(",")
|
||||
|
||||
order = ""
|
||||
this = expression.this
|
||||
if isinstance(this, exp.Order):
|
||||
if this.this:
|
||||
this = this.this
|
||||
this.pop()
|
||||
order = self.sql(expression.this) # Order has a leading space
|
||||
|
||||
return f"STRING_AGG({self.format_args(this, separator)}{order})"
|
||||
|
||||
|
||||
def _datatype_sql(self, expression):
|
||||
if expression.this == exp.DataType.Type.ARRAY:
|
||||
return f"{self.expressions(expression, flat=True)}[]"
|
||||
return self.datatype_sql(expression)
|
||||
|
||||
|
||||
def _auto_increment_to_serial(expression):
|
||||
auto = expression.find(exp.AutoIncrementColumnConstraint)
|
||||
|
||||
|
@ -191,25 +212,27 @@ class Postgres(Dialect):
|
|||
KEYWORDS = {
|
||||
**tokens.Tokenizer.KEYWORDS,
|
||||
"ALWAYS": TokenType.ALWAYS,
|
||||
"BY DEFAULT": TokenType.BY_DEFAULT,
|
||||
"IDENTITY": TokenType.IDENTITY,
|
||||
"GENERATED": TokenType.GENERATED,
|
||||
"DOUBLE PRECISION": TokenType.DOUBLE,
|
||||
"BIGSERIAL": TokenType.BIGSERIAL,
|
||||
"SERIAL": TokenType.SERIAL,
|
||||
"SMALLSERIAL": TokenType.SMALLSERIAL,
|
||||
"UUID": TokenType.UUID,
|
||||
"TEMP": TokenType.TEMPORARY,
|
||||
"BEGIN TRANSACTION": TokenType.BEGIN,
|
||||
"BEGIN": TokenType.COMMAND,
|
||||
"BEGIN TRANSACTION": TokenType.BEGIN,
|
||||
"BIGSERIAL": TokenType.BIGSERIAL,
|
||||
"BY DEFAULT": TokenType.BY_DEFAULT,
|
||||
"COMMENT ON": TokenType.COMMAND,
|
||||
"DECLARE": TokenType.COMMAND,
|
||||
"DO": TokenType.COMMAND,
|
||||
"DOUBLE PRECISION": TokenType.DOUBLE,
|
||||
"GENERATED": TokenType.GENERATED,
|
||||
"GRANT": TokenType.COMMAND,
|
||||
"HSTORE": TokenType.HSTORE,
|
||||
"IDENTITY": TokenType.IDENTITY,
|
||||
"JSONB": TokenType.JSONB,
|
||||
"REFRESH": TokenType.COMMAND,
|
||||
"REINDEX": TokenType.COMMAND,
|
||||
"RESET": TokenType.COMMAND,
|
||||
"REVOKE": TokenType.COMMAND,
|
||||
"GRANT": TokenType.COMMAND,
|
||||
"SERIAL": TokenType.SERIAL,
|
||||
"SMALLSERIAL": TokenType.SMALLSERIAL,
|
||||
"TEMP": TokenType.TEMPORARY,
|
||||
"UUID": TokenType.UUID,
|
||||
**{f"CREATE {kind}": TokenType.COMMAND for kind in CREATABLES},
|
||||
**{f"DROP {kind}": TokenType.COMMAND for kind in CREATABLES},
|
||||
}
|
||||
|
@ -265,4 +288,7 @@ class Postgres(Dialect):
|
|||
exp.Trim: _trim_sql,
|
||||
exp.TryCast: no_trycast_sql,
|
||||
exp.UnixToTime: lambda self, e: f"TO_TIMESTAMP({self.sql(e, 'this')})",
|
||||
exp.DataType: _datatype_sql,
|
||||
exp.GroupConcat: _string_agg_sql,
|
||||
exp.Array: lambda self, e: f"ARRAY[{self.expressions(e, flat=True)}]",
|
||||
}
|
||||
|
|
|
@ -171,16 +171,7 @@ class Presto(Dialect):
|
|||
|
||||
STRUCT_DELIMITER = ("(", ")")
|
||||
|
||||
ROOT_PROPERTIES = {
|
||||
exp.SchemaCommentProperty,
|
||||
}
|
||||
|
||||
WITH_PROPERTIES = {
|
||||
exp.PartitionedByProperty,
|
||||
exp.FileFormatProperty,
|
||||
exp.AnonymousProperty,
|
||||
exp.TableFormatProperty,
|
||||
}
|
||||
ROOT_PROPERTIES = {exp.SchemaCommentProperty}
|
||||
|
||||
TYPE_MAPPING = {
|
||||
**generator.Generator.TYPE_MAPPING,
|
||||
|
@ -231,7 +222,8 @@ class Presto(Dialect):
|
|||
exp.StrToTime: _str_to_time_sql,
|
||||
exp.StrToUnix: lambda self, e: f"TO_UNIXTIME(DATE_PARSE({self.sql(e, 'this')}, {self.format_time(e)}))",
|
||||
exp.StructExtract: struct_extract_sql,
|
||||
exp.TableFormatProperty: lambda self, e: f"TABLE_FORMAT = '{e.text('value').upper()}'",
|
||||
exp.TableFormatProperty: lambda self, e: f"TABLE_FORMAT='{e.name.upper()}'",
|
||||
exp.FileFormatProperty: lambda self, e: f"FORMAT='{e.name.upper()}'",
|
||||
exp.TimeStrToDate: _date_parse_sql,
|
||||
exp.TimeStrToTime: _date_parse_sql,
|
||||
exp.TimeStrToUnix: lambda self, e: f"TO_UNIXTIME(DATE_PARSE({self.sql(e, 'this')}, {Presto.time_format}))",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from sqlglot import exp
|
||||
from sqlglot import exp, transforms
|
||||
from sqlglot.dialects.postgres import Postgres
|
||||
from sqlglot.tokens import TokenType
|
||||
|
||||
|
@ -18,12 +18,14 @@ class Redshift(Postgres):
|
|||
|
||||
KEYWORDS = {
|
||||
**Postgres.Tokenizer.KEYWORDS, # type: ignore
|
||||
"COPY": TokenType.COMMAND,
|
||||
"GEOMETRY": TokenType.GEOMETRY,
|
||||
"GEOGRAPHY": TokenType.GEOGRAPHY,
|
||||
"HLLSKETCH": TokenType.HLLSKETCH,
|
||||
"SUPER": TokenType.SUPER,
|
||||
"TIME": TokenType.TIMESTAMP,
|
||||
"TIMETZ": TokenType.TIMESTAMPTZ,
|
||||
"UNLOAD": TokenType.COMMAND,
|
||||
"VARBYTE": TokenType.VARBINARY,
|
||||
"SIMILAR TO": TokenType.SIMILAR_TO,
|
||||
}
|
||||
|
@ -35,3 +37,17 @@ class Redshift(Postgres):
|
|||
exp.DataType.Type.VARBINARY: "VARBYTE",
|
||||
exp.DataType.Type.INT: "INTEGER",
|
||||
}
|
||||
|
||||
ROOT_PROPERTIES = {
|
||||
exp.DistKeyProperty,
|
||||
exp.SortKeyProperty,
|
||||
exp.DistStyleProperty,
|
||||
}
|
||||
|
||||
TRANSFORMS = {
|
||||
**Postgres.Generator.TRANSFORMS, # type: ignore
|
||||
**transforms.ELIMINATE_DISTINCT_ON, # type: ignore
|
||||
exp.DistKeyProperty: lambda self, e: f"DISTKEY({e.name})",
|
||||
exp.SortKeyProperty: lambda self, e: f"{'COMPOUND ' if e.args['compound'] else ''}SORTKEY({self.format_args(*e.this)})",
|
||||
exp.DistStyleProperty: lambda self, e: self.naked_property(e),
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ from sqlglot.dialects.dialect import (
|
|||
format_time_lambda,
|
||||
inline_array_sql,
|
||||
rename_func,
|
||||
var_map_sql,
|
||||
)
|
||||
from sqlglot.expressions import Literal
|
||||
from sqlglot.helper import seq_get
|
||||
|
@ -100,6 +101,14 @@ def _parse_date_part(self):
|
|||
return self.expression(exp.Extract, this=this, expression=expression)
|
||||
|
||||
|
||||
def _datatype_sql(self, expression):
|
||||
if expression.this == exp.DataType.Type.ARRAY:
|
||||
return "ARRAY"
|
||||
elif expression.this == exp.DataType.Type.MAP:
|
||||
return "OBJECT"
|
||||
return self.datatype_sql(expression)
|
||||
|
||||
|
||||
class Snowflake(Dialect):
|
||||
null_ordering = "nulls_are_large"
|
||||
time_format = "'yyyy-mm-dd hh24:mi:ss'"
|
||||
|
@ -142,6 +151,8 @@ class Snowflake(Dialect):
|
|||
"TO_TIMESTAMP": _snowflake_to_timestamp,
|
||||
"ARRAY_CONSTRUCT": exp.Array.from_arg_list,
|
||||
"RLIKE": exp.RegexpLike.from_arg_list,
|
||||
"DECODE": exp.Matches.from_arg_list,
|
||||
"OBJECT_CONSTRUCT": parser.parse_var_map,
|
||||
}
|
||||
|
||||
FUNCTION_PARSERS = {
|
||||
|
@ -195,16 +206,20 @@ class Snowflake(Dialect):
|
|||
|
||||
TRANSFORMS = {
|
||||
**generator.Generator.TRANSFORMS,
|
||||
exp.ArrayConcat: rename_func("ARRAY_CAT"),
|
||||
exp.If: rename_func("IFF"),
|
||||
exp.StrToTime: lambda self, e: f"TO_TIMESTAMP({self.sql(e, 'this')}, {self.format_time(e)})",
|
||||
exp.UnixToTime: _unix_to_time_sql,
|
||||
exp.TimeToUnix: lambda self, e: f"EXTRACT(epoch_second FROM {self.sql(e, 'this')})",
|
||||
exp.Array: inline_array_sql,
|
||||
exp.StrPosition: rename_func("POSITION"),
|
||||
exp.ArrayConcat: rename_func("ARRAY_CAT"),
|
||||
exp.DataType: _datatype_sql,
|
||||
exp.If: rename_func("IFF"),
|
||||
exp.Map: lambda self, e: var_map_sql(self, e, "OBJECT_CONSTRUCT"),
|
||||
exp.VarMap: lambda self, e: var_map_sql(self, e, "OBJECT_CONSTRUCT"),
|
||||
exp.Parameter: lambda self, e: f"${self.sql(e, 'this')}",
|
||||
exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'value')}",
|
||||
exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}",
|
||||
exp.Matches: rename_func("DECODE"),
|
||||
exp.StrPosition: rename_func("POSITION"),
|
||||
exp.StrToTime: lambda self, e: f"TO_TIMESTAMP({self.sql(e, 'this')}, {self.format_time(e)})",
|
||||
exp.TimeToUnix: lambda self, e: f"EXTRACT(epoch_second FROM {self.sql(e, 'this')})",
|
||||
exp.Trim: lambda self, e: f"TRIM({self.format_args(e.this, e.expression)})",
|
||||
exp.UnixToTime: _unix_to_time_sql,
|
||||
}
|
||||
|
||||
TYPE_MAPPING = {
|
||||
|
|
|
@ -98,7 +98,7 @@ class Spark(Hive):
|
|||
TRANSFORMS = {
|
||||
**Hive.Generator.TRANSFORMS, # type: ignore
|
||||
exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"),
|
||||
exp.FileFormatProperty: lambda self, e: f"USING {e.text('value').upper()}",
|
||||
exp.FileFormatProperty: lambda self, e: f"USING {e.name.upper()}",
|
||||
exp.ArraySum: lambda self, e: f"AGGREGATE({self.sql(e, 'this')}, 0, (acc, x) -> acc + x, acc -> acc)",
|
||||
exp.BitwiseLeftShift: rename_func("SHIFTLEFT"),
|
||||
exp.BitwiseRightShift: rename_func("SHIFTRIGHT"),
|
||||
|
|
|
@ -13,6 +13,23 @@ from sqlglot.dialects.dialect import (
|
|||
from sqlglot.tokens import TokenType
|
||||
|
||||
|
||||
# https://www.sqlite.org/lang_aggfunc.html#group_concat
|
||||
def _group_concat_sql(self, expression):
|
||||
this = expression.this
|
||||
distinct = expression.find(exp.Distinct)
|
||||
if distinct:
|
||||
this = distinct.expressions[0]
|
||||
distinct = "DISTINCT "
|
||||
|
||||
if isinstance(expression.this, exp.Order):
|
||||
self.unsupported("SQLite GROUP_CONCAT doesn't support ORDER BY.")
|
||||
if expression.this.this and not distinct:
|
||||
this = expression.this.this
|
||||
|
||||
separator = expression.args.get("separator")
|
||||
return f"GROUP_CONCAT({distinct or ''}{self.format_args(this, separator)})"
|
||||
|
||||
|
||||
class SQLite(Dialect):
|
||||
class Tokenizer(tokens.Tokenizer):
|
||||
IDENTIFIERS = ['"', ("[", "]"), "`"]
|
||||
|
@ -62,6 +79,7 @@ class SQLite(Dialect):
|
|||
exp.Levenshtein: rename_func("EDITDIST3"),
|
||||
exp.TableSample: no_tablesample_sql,
|
||||
exp.TryCast: no_trycast_sql,
|
||||
exp.GroupConcat: _group_concat_sql,
|
||||
}
|
||||
|
||||
def transaction_sql(self, expression):
|
||||
|
|
|
@ -17,6 +17,7 @@ FULL_FORMAT_TIME_MAPPING = {
|
|||
"mm": "%B",
|
||||
"m": "%B",
|
||||
}
|
||||
|
||||
DATE_DELTA_INTERVAL = {
|
||||
"year": "year",
|
||||
"yyyy": "year",
|
||||
|
@ -37,11 +38,12 @@ DATE_DELTA_INTERVAL = {
|
|||
|
||||
|
||||
DATE_FMT_RE = re.compile("([dD]{1,2})|([mM]{1,2})|([yY]{1,4})|([hH]{1,2})|([sS]{1,2})")
|
||||
|
||||
# N = Numeric, C=Currency
|
||||
TRANSPILE_SAFE_NUMBER_FMT = {"N", "C"}
|
||||
|
||||
|
||||
def tsql_format_time_lambda(exp_class, full_format_mapping=None, default=None):
|
||||
def _format_time_lambda(exp_class, full_format_mapping=None, default=None):
|
||||
def _format_time(args):
|
||||
return exp_class(
|
||||
this=seq_get(args, 1),
|
||||
|
@ -58,7 +60,7 @@ def tsql_format_time_lambda(exp_class, full_format_mapping=None, default=None):
|
|||
return _format_time
|
||||
|
||||
|
||||
def parse_format(args):
|
||||
def _parse_format(args):
|
||||
fmt = seq_get(args, 1)
|
||||
number_fmt = fmt.name in TRANSPILE_SAFE_NUMBER_FMT or not DATE_FMT_RE.search(fmt.this)
|
||||
if number_fmt:
|
||||
|
@ -78,7 +80,7 @@ def generate_date_delta_with_unit_sql(self, e):
|
|||
return f"{func}({self.format_args(e.text('unit'), e.expression, e.this)})"
|
||||
|
||||
|
||||
def generate_format_sql(self, e):
|
||||
def _format_sql(self, e):
|
||||
fmt = (
|
||||
e.args["format"]
|
||||
if isinstance(e, exp.NumberToStr)
|
||||
|
@ -87,6 +89,28 @@ def generate_format_sql(self, e):
|
|||
return f"FORMAT({self.format_args(e.this, fmt)})"
|
||||
|
||||
|
||||
def _string_agg_sql(self, e):
|
||||
e = e.copy()
|
||||
|
||||
this = e.this
|
||||
distinct = e.find(exp.Distinct)
|
||||
if distinct:
|
||||
# exp.Distinct can appear below an exp.Order or an exp.GroupConcat expression
|
||||
self.unsupported("T-SQL STRING_AGG doesn't support DISTINCT.")
|
||||
this = distinct.expressions[0]
|
||||
distinct.pop()
|
||||
|
||||
order = ""
|
||||
if isinstance(e.this, exp.Order):
|
||||
if e.this.this:
|
||||
this = e.this.this
|
||||
e.this.this.pop()
|
||||
order = f" WITHIN GROUP ({self.sql(e.this)[1:]})" # Order has a leading space
|
||||
|
||||
separator = e.args.get("separator") or exp.Literal.string(",")
|
||||
return f"STRING_AGG({self.format_args(this, separator)}){order}"
|
||||
|
||||
|
||||
class TSQL(Dialect):
|
||||
null_ordering = "nulls_are_small"
|
||||
time_format = "'yyyy-mm-dd hh:mm:ss'"
|
||||
|
@ -228,14 +252,14 @@ class TSQL(Dialect):
|
|||
"ISNULL": exp.Coalesce.from_arg_list,
|
||||
"DATEADD": parse_date_delta(exp.DateAdd, unit_mapping=DATE_DELTA_INTERVAL),
|
||||
"DATEDIFF": parse_date_delta(exp.DateDiff, unit_mapping=DATE_DELTA_INTERVAL),
|
||||
"DATENAME": tsql_format_time_lambda(exp.TimeToStr, full_format_mapping=True),
|
||||
"DATEPART": tsql_format_time_lambda(exp.TimeToStr),
|
||||
"DATENAME": _format_time_lambda(exp.TimeToStr, full_format_mapping=True),
|
||||
"DATEPART": _format_time_lambda(exp.TimeToStr),
|
||||
"GETDATE": exp.CurrentDate.from_arg_list,
|
||||
"IIF": exp.If.from_arg_list,
|
||||
"LEN": exp.Length.from_arg_list,
|
||||
"REPLICATE": exp.Repeat.from_arg_list,
|
||||
"JSON_VALUE": exp.JSONExtractScalar.from_arg_list,
|
||||
"FORMAT": parse_format,
|
||||
"FORMAT": _parse_format,
|
||||
}
|
||||
|
||||
VAR_LENGTH_DATATYPES = {
|
||||
|
@ -298,6 +322,7 @@ class TSQL(Dialect):
|
|||
exp.DateDiff: generate_date_delta_with_unit_sql,
|
||||
exp.CurrentDate: rename_func("GETDATE"),
|
||||
exp.If: rename_func("IIF"),
|
||||
exp.NumberToStr: generate_format_sql,
|
||||
exp.TimeToStr: generate_format_sql,
|
||||
exp.NumberToStr: _format_sql,
|
||||
exp.TimeToStr: _format_sql,
|
||||
exp.GroupConcat: _string_agg_sql,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue