1
0
Fork 0

Adding upstream version 22.2.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-13 21:29:15 +01:00
parent b01402dc30
commit f1aa09959c
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
148 changed files with 68457 additions and 63176 deletions

View file

@ -73,17 +73,16 @@ class Generator(metaclass=_Generator):
TRANSFORMS: t.Dict[t.Type[exp.Expression], t.Callable[..., str]] = {
**JSON_PATH_PART_TRANSFORMS,
exp.AutoRefreshProperty: lambda self, e: f"AUTO REFRESH {self.sql(e, 'this')}",
exp.CaseSpecificColumnConstraint: lambda self,
exp.CaseSpecificColumnConstraint: lambda _,
e: f"{'NOT ' if e.args.get('not_') else ''}CASESPECIFIC",
exp.CharacterSetColumnConstraint: lambda self, e: f"CHARACTER SET {self.sql(e, 'this')}",
exp.CharacterSetProperty: lambda self,
e: f"{'DEFAULT ' if e.args.get('default') else ''}CHARACTER SET={self.sql(e, 'this')}",
exp.CheckColumnConstraint: lambda self, e: f"CHECK ({self.sql(e, 'this')})",
exp.ClusteredColumnConstraint: lambda self,
e: f"CLUSTERED ({self.expressions(e, 'this', indent=False)})",
exp.CollateColumnConstraint: lambda self, e: f"COLLATE {self.sql(e, 'this')}",
exp.CommentColumnConstraint: lambda self, e: f"COMMENT {self.sql(e, 'this')}",
exp.CopyGrantsProperty: lambda self, e: "COPY GRANTS",
exp.CopyGrantsProperty: lambda *_: "COPY GRANTS",
exp.DateAdd: lambda self, e: self.func(
"DATE_ADD", e.this, e.expression, exp.Literal.string(e.text("unit"))
),
@ -91,8 +90,8 @@ class Generator(metaclass=_Generator):
exp.DefaultColumnConstraint: lambda self, e: f"DEFAULT {self.sql(e, 'this')}",
exp.EncodeColumnConstraint: lambda self, e: f"ENCODE {self.sql(e, 'this')}",
exp.ExecuteAsProperty: lambda self, e: self.naked_property(e),
exp.ExternalProperty: lambda self, e: "EXTERNAL",
exp.HeapProperty: lambda self, e: "HEAP",
exp.ExternalProperty: lambda *_: "EXTERNAL",
exp.HeapProperty: lambda *_: "HEAP",
exp.InheritsProperty: lambda self, e: f"INHERITS ({self.expressions(e, flat=True)})",
exp.InlineLengthColumnConstraint: lambda self, e: f"INLINE LENGTH {self.sql(e, 'this')}",
exp.InputModelProperty: lambda self, e: f"INPUT{self.sql(e, 'this')}",
@ -105,13 +104,13 @@ class Generator(metaclass=_Generator):
),
exp.LanguageProperty: lambda self, e: self.naked_property(e),
exp.LocationProperty: lambda self, e: self.naked_property(e),
exp.LogProperty: lambda self, e: f"{'NO ' if e.args.get('no') else ''}LOG",
exp.MaterializedProperty: lambda self, e: "MATERIALIZED",
exp.LogProperty: lambda _, e: f"{'NO ' if e.args.get('no') else ''}LOG",
exp.MaterializedProperty: lambda *_: "MATERIALIZED",
exp.NonClusteredColumnConstraint: lambda self,
e: f"NONCLUSTERED ({self.expressions(e, 'this', indent=False)})",
exp.NoPrimaryIndexProperty: lambda self, e: "NO PRIMARY INDEX",
exp.NotForReplicationColumnConstraint: lambda self, e: "NOT FOR REPLICATION",
exp.OnCommitProperty: lambda self,
exp.NoPrimaryIndexProperty: lambda *_: "NO PRIMARY INDEX",
exp.NotForReplicationColumnConstraint: lambda *_: "NOT FOR REPLICATION",
exp.OnCommitProperty: lambda _,
e: f"ON COMMIT {'DELETE' if e.args.get('delete') else 'PRESERVE'} ROWS",
exp.OnProperty: lambda self, e: f"ON {self.sql(e, 'this')}",
exp.OnUpdateColumnConstraint: lambda self, e: f"ON UPDATE {self.sql(e, 'this')}",
@ -122,21 +121,21 @@ class Generator(metaclass=_Generator):
exp.ReturnsProperty: lambda self, e: self.naked_property(e),
exp.SampleProperty: lambda self, e: f"SAMPLE BY {self.sql(e, 'this')}",
exp.SetConfigProperty: lambda self, e: self.sql(e, "this"),
exp.SetProperty: lambda self, e: f"{'MULTI' if e.args.get('multi') else ''}SET",
exp.SetProperty: lambda _, e: f"{'MULTI' if e.args.get('multi') else ''}SET",
exp.SettingsProperty: lambda self, e: f"SETTINGS{self.seg('')}{(self.expressions(e))}",
exp.SqlReadWriteProperty: lambda self, e: e.name,
exp.SqlSecurityProperty: lambda self,
exp.SqlReadWriteProperty: lambda _, e: e.name,
exp.SqlSecurityProperty: lambda _,
e: f"SQL SECURITY {'DEFINER' if e.args.get('definer') else 'INVOKER'}",
exp.StabilityProperty: lambda self, e: e.name,
exp.TemporaryProperty: lambda self, e: "TEMPORARY",
exp.StabilityProperty: lambda _, e: e.name,
exp.TemporaryProperty: lambda *_: "TEMPORARY",
exp.TitleColumnConstraint: lambda self, e: f"TITLE {self.sql(e, 'this')}",
exp.Timestamp: lambda self, e: self.func("TIMESTAMP", e.this, e.expression),
exp.ToTableProperty: lambda self, e: f"TO {self.sql(e.this)}",
exp.TransformModelProperty: lambda self, e: self.func("TRANSFORM", *e.expressions),
exp.TransientProperty: lambda self, e: "TRANSIENT",
exp.UppercaseColumnConstraint: lambda self, e: "UPPERCASE",
exp.TransientProperty: lambda *_: "TRANSIENT",
exp.UppercaseColumnConstraint: lambda *_: "UPPERCASE",
exp.VarMap: lambda self, e: self.func("MAP", e.args["keys"], e.args["values"]),
exp.VolatileProperty: lambda self, e: "VOLATILE",
exp.VolatileProperty: lambda *_: "VOLATILE",
exp.WithJournalTableProperty: lambda self, e: f"WITH JOURNAL TABLE={self.sql(e, 'this')}",
}
@ -356,6 +355,7 @@ class Generator(metaclass=_Generator):
STRUCT_DELIMITER = ("<", ">")
PARAMETER_TOKEN = "@"
NAMED_PLACEHOLDER_TOKEN = ":"
PROPERTIES_LOCATION = {
exp.AlgorithmProperty: exp.Properties.Location.POST_CREATE,
@ -388,6 +388,7 @@ class Generator(metaclass=_Generator):
exp.LanguageProperty: exp.Properties.Location.POST_SCHEMA,
exp.LikeProperty: exp.Properties.Location.POST_SCHEMA,
exp.LocationProperty: exp.Properties.Location.POST_SCHEMA,
exp.LockProperty: exp.Properties.Location.POST_SCHEMA,
exp.LockingProperty: exp.Properties.Location.POST_ALIAS,
exp.LogProperty: exp.Properties.Location.POST_NAME,
exp.MaterializedProperty: exp.Properties.Location.POST_CREATE,
@ -459,11 +460,16 @@ class Generator(metaclass=_Generator):
exp.Paren,
)
PARAMETERIZABLE_TEXT_TYPES = {
exp.DataType.Type.NVARCHAR,
exp.DataType.Type.VARCHAR,
exp.DataType.Type.CHAR,
exp.DataType.Type.NCHAR,
}
# Expressions that need to have all CTEs under them bubbled up to them
EXPRESSIONS_WITHOUT_NESTED_CTES: t.Set[t.Type[exp.Expression]] = set()
KEY_VALUE_DEFINITIONS = (exp.EQ, exp.PropertyEQ, exp.Slice)
SENTINEL_LINE_BREAK = "__SQLGLOT__LB__"
__slots__ = (
@ -630,7 +636,7 @@ class Generator(metaclass=_Generator):
this_sql = self.indent(
(
self.sql(expression)
if isinstance(expression, (exp.Select, exp.Union))
if isinstance(expression, exp.UNWRAPPED_QUERIES)
else self.sql(expression, "this")
),
level=1,
@ -1535,8 +1541,8 @@ class Generator(metaclass=_Generator):
expr = self.sql(expression, "expression")
return f"{this} ({kind} => {expr})"
def table_sql(self, expression: exp.Table, sep: str = " AS ") -> str:
table = ".".join(
def table_parts(self, expression: exp.Table) -> str:
return ".".join(
self.sql(part)
for part in (
expression.args.get("catalog"),
@ -1546,6 +1552,9 @@ class Generator(metaclass=_Generator):
if part is not None
)
def table_sql(self, expression: exp.Table, sep: str = " AS ") -> str:
table = self.table_parts(expression)
only = "ONLY " if expression.args.get("only") else ""
version = self.sql(expression, "version")
version = f" {version}" if version else ""
alias = self.sql(expression, "alias")
@ -1572,7 +1581,7 @@ class Generator(metaclass=_Generator):
if when:
table = f"{table} {when}"
return f"{table}{version}{file_format}{alias}{hints}{pivots}{joins}{laterals}{ordinality}"
return f"{only}{table}{version}{file_format}{alias}{hints}{pivots}{joins}{laterals}{ordinality}"
def tablesample_sql(
self,
@ -1681,7 +1690,7 @@ class Generator(metaclass=_Generator):
alias_node = expression.args.get("alias")
column_names = alias_node and alias_node.columns
selects: t.List[exp.Subqueryable] = []
selects: t.List[exp.Query] = []
for i, tup in enumerate(expression.expressions):
row = tup.expressions
@ -1697,10 +1706,8 @@ class Generator(metaclass=_Generator):
# This may result in poor performance for large-cardinality `VALUES` tables, due to
# the deep nesting of the resulting exp.Unions. If this is a problem, either increase
# `sys.setrecursionlimit` to avoid RecursionErrors, or don't set `pretty`.
subqueryable = reduce(lambda x, y: exp.union(x, y, distinct=False, copy=False), selects)
return self.subquery_sql(
subqueryable.subquery(alias_node and alias_node.this, copy=False)
)
query = reduce(lambda x, y: exp.union(x, y, distinct=False, copy=False), selects)
return self.subquery_sql(query.subquery(alias_node and alias_node.this, copy=False))
alias = f" AS {self.sql(alias_node, 'this')}" if alias_node else ""
unions = " UNION ALL ".join(self.sql(select) for select in selects)
@ -1854,7 +1861,7 @@ class Generator(metaclass=_Generator):
]
args_sql = ", ".join(self.sql(e) for e in args)
args_sql = f"({args_sql})" if any(top and not e.is_number for e in args) else args_sql
args_sql = f"({args_sql})" if top and any(not e.is_number for e in args) else args_sql
expressions = self.expressions(expression, flat=True)
expressions = f" BY {expressions}" if expressions else ""
@ -2070,12 +2077,17 @@ class Generator(metaclass=_Generator):
else []
)
options = self.expressions(expression, key="options")
if options:
options = f" OPTION{self.wrap(options)}"
return csv(
*sqls,
*[self.sql(join) for join in expression.args.get("joins") or []],
self.sql(expression, "connect"),
self.sql(expression, "match"),
*[self.sql(lateral) for lateral in expression.args.get("laterals") or []],
self.sql(expression, "prewhere"),
self.sql(expression, "where"),
self.sql(expression, "group"),
self.sql(expression, "having"),
@ -2083,9 +2095,13 @@ class Generator(metaclass=_Generator):
self.sql(expression, "order"),
*offset_limit_modifiers,
*self.after_limit_modifiers(expression),
options,
sep="",
)
def queryoption_sql(self, expression: exp.QueryOption) -> str:
return ""
def offset_limit_modifiers(
self, expression: exp.Expression, fetch: bool, limit: t.Optional[exp.Fetch | exp.Limit]
) -> t.List[str]:
@ -2140,9 +2156,9 @@ class Generator(metaclass=_Generator):
self.sql(
exp.Struct(
expressions=[
exp.column(e.output_name).eq(
e.this if isinstance(e, exp.Alias) else e
)
exp.PropertyEQ(this=e.args.get("alias"), expression=e.this)
if isinstance(e, exp.Alias)
else e
for e in expression.expressions
]
)
@ -2204,7 +2220,7 @@ class Generator(metaclass=_Generator):
return f"@@{kind}{this}"
def placeholder_sql(self, expression: exp.Placeholder) -> str:
return f":{expression.name}" if expression.name else "?"
return f"{self.NAMED_PLACEHOLDER_TOKEN}{expression.name}" if expression.name else "?"
def subquery_sql(self, expression: exp.Subquery, sep: str = " AS ") -> str:
alias = self.sql(expression, "alias")
@ -2261,6 +2277,9 @@ class Generator(metaclass=_Generator):
return f"UNNEST({args}){suffix}"
def prewhere_sql(self, expression: exp.PreWhere) -> str:
return ""
def where_sql(self, expression: exp.Where) -> str:
this = self.indent(self.sql(expression, "this"))
return f"{self.seg('WHERE')}{self.sep()}{this}"
@ -2326,7 +2345,7 @@ class Generator(metaclass=_Generator):
def any_sql(self, expression: exp.Any) -> str:
this = self.sql(expression, "this")
if isinstance(expression.this, exp.Subqueryable):
if isinstance(expression.this, exp.UNWRAPPED_QUERIES):
this = self.wrap(this)
return f"ANY {this}"
@ -2568,7 +2587,7 @@ class Generator(metaclass=_Generator):
is_global = " GLOBAL" if expression.args.get("is_global") else ""
if query:
in_sql = self.wrap(query)
in_sql = self.wrap(self.sql(query))
elif unnest:
in_sql = self.in_unnest_op(unnest)
elif field:
@ -2610,7 +2629,7 @@ class Generator(metaclass=_Generator):
return f"REFERENCES {this}{expressions}{options}"
def anonymous_sql(self, expression: exp.Anonymous) -> str:
return self.func(expression.name, *expression.expressions)
return self.func(self.sql(expression, "this"), *expression.expressions)
def paren_sql(self, expression: exp.Paren) -> str:
if isinstance(expression.unnest(), exp.Select):
@ -2822,7 +2841,9 @@ class Generator(metaclass=_Generator):
exists = " IF EXISTS" if expression.args.get("exists") else ""
only = " ONLY" if expression.args.get("only") else ""
return f"ALTER TABLE{exists}{only} {self.sql(expression, 'this')} {actions}"
options = self.expressions(expression, key="options")
options = f", {options}" if options else ""
return f"ALTER TABLE{exists}{only} {self.sql(expression, 'this')} {actions}{options}"
def add_column_sql(self, expression: exp.AlterTable) -> str:
if self.ALTER_TABLE_INCLUDE_COLUMN_KEYWORD:
@ -2839,15 +2860,7 @@ class Generator(metaclass=_Generator):
return f"DROP{exists}{expressions}"
def addconstraint_sql(self, expression: exp.AddConstraint) -> str:
this = self.sql(expression, "this")
expression_ = self.sql(expression, "expression")
add_constraint = f"ADD CONSTRAINT {this}" if this else "ADD"
enforced = expression.args.get("enforced")
if enforced is not None:
return f"{add_constraint} CHECK ({expression_}){' ENFORCED' if enforced else ''}"
return f"{add_constraint} {expression_}"
return f"ADD {self.expressions(expression)}"
def distinct_sql(self, expression: exp.Distinct) -> str:
this = self.expressions(expression, flat=True)
@ -3296,6 +3309,10 @@ class Generator(metaclass=_Generator):
self.unsupported("Unsupported index constraint option.")
return ""
def checkcolumnconstraint_sql(self, expression: exp.CheckColumnConstraint) -> str:
enforced = " ENFORCED" if expression.args.get("enforced") else ""
return f"CHECK ({self.sql(expression, 'this')}){enforced}"
def indexcolumnconstraint_sql(self, expression: exp.IndexColumnConstraint) -> str:
kind = self.sql(expression, "kind")
kind = f"{kind} INDEX" if kind else "INDEX"
@ -3452,9 +3469,87 @@ class Generator(metaclass=_Generator):
return expression
def _ensure_string_if_null(self, values: t.List[exp.Expression]) -> t.List[exp.Expression]:
return [
exp.func("COALESCE", exp.cast(value, "text"), exp.Literal.string(""))
for value in values
if value
]
def generateseries_sql(self, expression: exp.GenerateSeries) -> str:
expression.set("is_end_exclusive", None)
return self.function_fallback_sql(expression)
def struct_sql(self, expression: exp.Struct) -> str:
expression.set(
"expressions",
[
exp.alias_(e.expression, e.this) if isinstance(e, exp.PropertyEQ) else e
for e in expression.expressions
],
)
return self.function_fallback_sql(expression)
def partitionrange_sql(self, expression: exp.PartitionRange) -> str:
low = self.sql(expression, "this")
high = self.sql(expression, "expression")
return f"{low} TO {high}"
def truncatetable_sql(self, expression: exp.TruncateTable) -> str:
target = "DATABASE" if expression.args.get("is_database") else "TABLE"
tables = f" {self.expressions(expression)}"
exists = " IF EXISTS" if expression.args.get("exists") else ""
on_cluster = self.sql(expression, "cluster")
on_cluster = f" {on_cluster}" if on_cluster else ""
identity = self.sql(expression, "identity")
identity = f" {identity} IDENTITY" if identity else ""
option = self.sql(expression, "option")
option = f" {option}" if option else ""
partition = self.sql(expression, "partition")
partition = f" {partition}" if partition else ""
return f"TRUNCATE {target}{exists}{tables}{on_cluster}{identity}{option}{partition}"
# This transpiles T-SQL's CONVERT function
# https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver16
def convert_sql(self, expression: exp.Convert) -> str:
to = expression.this
value = expression.expression
style = expression.args.get("style")
safe = expression.args.get("safe")
strict = expression.args.get("strict")
if not to or not value:
return ""
# Retrieve length of datatype and override to default if not specified
if not seq_get(to.expressions, 0) and to.this in self.PARAMETERIZABLE_TEXT_TYPES:
to = exp.DataType.build(to.this, expressions=[exp.Literal.number(30)], nested=False)
transformed: t.Optional[exp.Expression] = None
cast = exp.Cast if strict else exp.TryCast
# Check whether a conversion with format (T-SQL calls this 'style') is applicable
if isinstance(style, exp.Literal) and style.is_int:
from sqlglot.dialects.tsql import TSQL
style_value = style.name
converted_style = TSQL.CONVERT_FORMAT_MAPPING.get(style_value)
if not converted_style:
self.unsupported(f"Unsupported T-SQL 'style' value: {style_value}")
fmt = exp.Literal.string(converted_style)
if to.this == exp.DataType.Type.DATE:
transformed = exp.StrToDate(this=value, format=fmt)
elif to.this == exp.DataType.Type.DATETIME:
transformed = exp.StrToTime(this=value, format=fmt)
elif to.this in self.PARAMETERIZABLE_TEXT_TYPES:
transformed = cast(this=exp.TimeToStr(this=value, format=fmt), to=to, safe=safe)
elif to.this == exp.DataType.Type.TEXT:
transformed = exp.TimeToStr(this=value, format=fmt)
if not transformed:
transformed = cast(this=value, to=to, safe=safe)
return self.sql(transformed)