1
0
Fork 0

Merging 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:39 +01:00
parent b13ba670fd
commit 2c28c49d7e
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
148 changed files with 68457 additions and 63176 deletions

View file

@ -548,12 +548,10 @@ class Expression(metaclass=_Expression):
return new_node
@t.overload
def replace(self, expression: E) -> E:
...
def replace(self, expression: E) -> E: ...
@t.overload
def replace(self, expression: None) -> None:
...
def replace(self, expression: None) -> None: ...
def replace(self, expression):
"""
@ -913,14 +911,142 @@ class Predicate(Condition):
class DerivedTable(Expression):
@property
def selects(self) -> t.List[Expression]:
return self.this.selects if isinstance(self.this, Subqueryable) else []
return self.this.selects if isinstance(self.this, Query) else []
@property
def named_selects(self) -> t.List[str]:
return [select.output_name for select in self.selects]
class Unionable(Expression):
class Query(Expression):
def subquery(self, alias: t.Optional[ExpOrStr] = None, copy: bool = True) -> Subquery:
"""
Returns a `Subquery` that wraps around this query.
Example:
>>> subquery = Select().select("x").from_("tbl").subquery()
>>> Select().select("x").from_(subquery).sql()
'SELECT x FROM (SELECT x FROM tbl)'
Args:
alias: an optional alias for the subquery.
copy: if `False`, modify this expression instance in-place.
"""
instance = maybe_copy(self, copy)
if not isinstance(alias, Expression):
alias = TableAlias(this=to_identifier(alias)) if alias else None
return Subquery(this=instance, alias=alias)
def limit(
self, expression: ExpOrStr | int, dialect: DialectType = None, copy: bool = True, **opts
) -> Select:
"""
Adds a LIMIT clause to this query.
Example:
>>> select("1").union(select("1")).limit(1).sql()
'SELECT * FROM (SELECT 1 UNION SELECT 1) AS _l_0 LIMIT 1'
Args:
expression: the SQL code string to parse.
This can also be an integer.
If a `Limit` instance is passed, it will be used as-is.
If another `Expression` instance is passed, it will be wrapped in a `Limit`.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
A limited Select expression.
"""
return (
select("*")
.from_(self.subquery(alias="_l_0", copy=copy))
.limit(expression, dialect=dialect, copy=False, **opts)
)
@property
def ctes(self) -> t.List[CTE]:
"""Returns a list of all the CTEs attached to this query."""
with_ = self.args.get("with")
return with_.expressions if with_ else []
@property
def selects(self) -> t.List[Expression]:
"""Returns the query's projections."""
raise NotImplementedError("Query objects must implement `selects`")
@property
def named_selects(self) -> t.List[str]:
"""Returns the output names of the query's projections."""
raise NotImplementedError("Query objects must implement `named_selects`")
def select(
self,
*expressions: t.Optional[ExpOrStr],
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> Query:
"""
Append to or set the SELECT expressions.
Example:
>>> Select().select("x", "y").sql()
'SELECT x, y'
Args:
*expressions: the SQL code strings to parse.
If an `Expression` instance is passed, it will be used as-is.
append: if `True`, add to any existing expressions.
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expressions.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
The modified Query expression.
"""
raise NotImplementedError("Query objects must implement `select`")
def with_(
self,
alias: ExpOrStr,
as_: ExpOrStr,
recursive: t.Optional[bool] = None,
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> Query:
"""
Append to or set the common table expressions.
Example:
>>> Select().with_("tbl2", as_="SELECT * FROM tbl").select("x").from_("tbl2").sql()
'WITH tbl2 AS (SELECT * FROM tbl) SELECT x FROM tbl2'
Args:
alias: the SQL code string to parse as the table name.
If an `Expression` instance is passed, this is used as-is.
as_: the SQL code string to parse as the table expression.
If an `Expression` instance is passed, it will be used as-is.
recursive: set the RECURSIVE part of the expression. Defaults to `False`.
append: if `True`, add to any existing expressions.
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
The modified expression.
"""
return _apply_cte_builder(
self, alias, as_, recursive=recursive, append=append, dialect=dialect, copy=copy, **opts
)
def union(
self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts
) -> Union:
@ -946,7 +1072,7 @@ class Unionable(Expression):
def intersect(
self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts
) -> Unionable:
) -> Intersect:
"""
Builds an INTERSECT expression.
@ -969,7 +1095,7 @@ class Unionable(Expression):
def except_(
self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts
) -> Unionable:
) -> Except:
"""
Builds an EXCEPT expression.
@ -991,7 +1117,7 @@ class Unionable(Expression):
return except_(left=self, right=expression, distinct=distinct, dialect=dialect, **opts)
class UDTF(DerivedTable, Unionable):
class UDTF(DerivedTable):
@property
def selects(self) -> t.List[Expression]:
alias = self.args.get("alias")
@ -1017,23 +1143,23 @@ class Refresh(Expression):
class DDL(Expression):
@property
def ctes(self):
def ctes(self) -> t.List[CTE]:
"""Returns a list of all the CTEs attached to this statement."""
with_ = self.args.get("with")
if not with_:
return []
return with_.expressions
@property
def named_selects(self) -> t.List[str]:
if isinstance(self.expression, Subqueryable):
return self.expression.named_selects
return []
return with_.expressions if with_ else []
@property
def selects(self) -> t.List[Expression]:
if isinstance(self.expression, Subqueryable):
return self.expression.selects
return []
"""If this statement contains a query (e.g. a CTAS), this returns the query's projections."""
return self.expression.selects if isinstance(self.expression, Query) else []
@property
def named_selects(self) -> t.List[str]:
"""
If this statement contains a query (e.g. a CTAS), this returns the output
names of the query's projections.
"""
return self.expression.named_selects if isinstance(self.expression, Query) else []
class DML(Expression):
@ -1096,6 +1222,19 @@ class Create(DDL):
return kind and kind.upper()
class TruncateTable(Expression):
arg_types = {
"expressions": True,
"is_database": False,
"exists": False,
"only": False,
"cluster": False,
"identity": False,
"option": False,
"partition": False,
}
# https://docs.snowflake.com/en/sql-reference/sql/create-clone
# https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_clone_statement
# https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_copy
@ -1271,6 +1410,10 @@ class ColumnDef(Expression):
def constraints(self) -> t.List[ColumnConstraint]:
return self.args.get("constraints") or []
@property
def kind(self) -> t.Optional[DataType]:
return self.args.get("kind")
class AlterColumn(Expression):
arg_types = {
@ -1367,7 +1510,7 @@ class CharacterSetColumnConstraint(ColumnConstraintKind):
class CheckColumnConstraint(ColumnConstraintKind):
pass
arg_types = {"this": True, "enforced": False}
class ClusteredColumnConstraint(ColumnConstraintKind):
@ -1776,6 +1919,10 @@ class Partition(Expression):
arg_types = {"expressions": True}
class PartitionRange(Expression):
arg_types = {"this": True, "expression": True}
class Fetch(Expression):
arg_types = {
"direction": False,
@ -2173,6 +2320,10 @@ class LocationProperty(Property):
arg_types = {"this": True}
class LockProperty(Property):
arg_types = {"this": True}
class LockingProperty(Property):
arg_types = {
"this": False,
@ -2310,7 +2461,7 @@ class StabilityProperty(Property):
class TemporaryProperty(Property):
arg_types = {}
arg_types = {"this": False}
class TransformModelProperty(Property):
@ -2356,6 +2507,7 @@ class Properties(Expression):
"FORMAT": FileFormatProperty,
"LANGUAGE": LanguageProperty,
"LOCATION": LocationProperty,
"LOCK": LockProperty,
"PARTITIONED_BY": PartitionedByProperty,
"RETURNS": ReturnsProperty,
"ROW_FORMAT": RowFormatProperty,
@ -2445,102 +2597,13 @@ class Tuple(Expression):
)
class Subqueryable(Unionable):
def subquery(self, alias: t.Optional[ExpOrStr] = None, copy: bool = True) -> Subquery:
"""
Convert this expression to an aliased expression that can be used as a Subquery.
Example:
>>> subquery = Select().select("x").from_("tbl").subquery()
>>> Select().select("x").from_(subquery).sql()
'SELECT x FROM (SELECT x FROM tbl)'
Args:
alias (str | Identifier): an optional alias for the subquery
copy (bool): if `False`, modify this expression instance in-place.
Returns:
Alias: the subquery
"""
instance = maybe_copy(self, copy)
if not isinstance(alias, Expression):
alias = TableAlias(this=to_identifier(alias)) if alias else None
return Subquery(this=instance, alias=alias)
def limit(
self, expression: ExpOrStr | int, dialect: DialectType = None, copy: bool = True, **opts
) -> Select:
raise NotImplementedError
@property
def ctes(self):
with_ = self.args.get("with")
if not with_:
return []
return with_.expressions
@property
def selects(self) -> t.List[Expression]:
raise NotImplementedError("Subqueryable objects must implement `selects`")
@property
def named_selects(self) -> t.List[str]:
raise NotImplementedError("Subqueryable objects must implement `named_selects`")
def select(
self,
*expressions: t.Optional[ExpOrStr],
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> Subqueryable:
raise NotImplementedError("Subqueryable objects must implement `select`")
def with_(
self,
alias: ExpOrStr,
as_: ExpOrStr,
recursive: t.Optional[bool] = None,
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> Subqueryable:
"""
Append to or set the common table expressions.
Example:
>>> Select().with_("tbl2", as_="SELECT * FROM tbl").select("x").from_("tbl2").sql()
'WITH tbl2 AS (SELECT * FROM tbl) SELECT x FROM tbl2'
Args:
alias: the SQL code string to parse as the table name.
If an `Expression` instance is passed, this is used as-is.
as_: the SQL code string to parse as the table expression.
If an `Expression` instance is passed, it will be used as-is.
recursive: set the RECURSIVE part of the expression. Defaults to `False`.
append: if `True`, add to any existing expressions.
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
The modified expression.
"""
return _apply_cte_builder(
self, alias, as_, recursive=recursive, append=append, dialect=dialect, copy=copy, **opts
)
QUERY_MODIFIERS = {
"match": False,
"laterals": False,
"joins": False,
"connect": False,
"pivots": False,
"prewhere": False,
"where": False,
"group": False,
"having": False,
@ -2556,9 +2619,16 @@ QUERY_MODIFIERS = {
"sample": False,
"settings": False,
"format": False,
"options": False,
}
# https://learn.microsoft.com/en-us/sql/t-sql/queries/option-clause-transact-sql?view=sql-server-ver16
# https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-query?view=sql-server-ver16
class QueryOption(Expression):
arg_types = {"this": True, "expression": False}
# https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
class WithTableHint(Expression):
arg_types = {"expressions": True}
@ -2590,6 +2660,7 @@ class Table(Expression):
"pattern": False,
"ordinality": False,
"when": False,
"only": False,
}
@property
@ -2638,7 +2709,7 @@ class Table(Expression):
return col
class Union(Subqueryable):
class Union(Query):
arg_types = {
"with": False,
"this": True,
@ -2648,34 +2719,6 @@ class Union(Subqueryable):
**QUERY_MODIFIERS,
}
def limit(
self, expression: ExpOrStr | int, dialect: DialectType = None, copy: bool = True, **opts
) -> Select:
"""
Set the LIMIT expression.
Example:
>>> select("1").union(select("1")).limit(1).sql()
'SELECT * FROM (SELECT 1 UNION SELECT 1) AS _l_0 LIMIT 1'
Args:
expression: the SQL code string to parse.
This can also be an integer.
If a `Limit` instance is passed, this is used as-is.
If another `Expression` instance is passed, it will be wrapped in a `Limit`.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
The limited subqueryable.
"""
return (
select("*")
.from_(self.subquery(alias="_l_0", copy=copy))
.limit(expression, dialect=dialect, copy=False, **opts)
)
def select(
self,
*expressions: t.Optional[ExpOrStr],
@ -2684,26 +2727,7 @@ class Union(Subqueryable):
copy: bool = True,
**opts,
) -> Union:
"""Append to or set the SELECT of the union recursively.
Example:
>>> from sqlglot import parse_one
>>> parse_one("select a from x union select a from y union select a from z").select("b").sql()
'SELECT a, b FROM x UNION SELECT a, b FROM y UNION SELECT a, b FROM z'
Args:
*expressions: the SQL code strings to parse.
If an `Expression` instance is passed, it will be used as-is.
append: if `True`, add to any existing expressions.
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expressions.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
Union: the modified expression.
"""
this = self.copy() if copy else self
this = maybe_copy(self, copy)
this.this.unnest().select(*expressions, append=append, dialect=dialect, copy=False, **opts)
this.expression.unnest().select(
*expressions, append=append, dialect=dialect, copy=False, **opts
@ -2800,7 +2824,7 @@ class Lock(Expression):
arg_types = {"update": True, "expressions": False, "wait": False}
class Select(Subqueryable):
class Select(Query):
arg_types = {
"with": False,
"kind": False,
@ -3011,25 +3035,6 @@ class Select(Subqueryable):
def limit(
self, expression: ExpOrStr | int, dialect: DialectType = None, copy: bool = True, **opts
) -> Select:
"""
Set the LIMIT expression.
Example:
>>> Select().from_("tbl").select("x").limit(10).sql()
'SELECT x FROM tbl LIMIT 10'
Args:
expression: the SQL code string to parse.
This can also be an integer.
If a `Limit` instance is passed, this is used as-is.
If another `Expression` instance is passed, it will be wrapped in a `Limit`.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
Select: the modified expression.
"""
return _apply_builder(
expression=expression,
instance=self,
@ -3084,31 +3089,13 @@ class Select(Subqueryable):
copy: bool = True,
**opts,
) -> Select:
"""
Append to or set the SELECT expressions.
Example:
>>> Select().select("x", "y").sql()
'SELECT x, y'
Args:
*expressions: the SQL code strings to parse.
If an `Expression` instance is passed, it will be used as-is.
append: if `True`, add to any existing expressions.
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expressions.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
The modified Select expression.
"""
return _apply_list_builder(
*expressions,
instance=self,
arg="expressions",
append=append,
dialect=dialect,
into=Expression,
copy=copy,
**opts,
)
@ -3416,12 +3403,8 @@ class Select(Subqueryable):
The new Create expression.
"""
instance = maybe_copy(self, copy)
table_expression = maybe_parse(
table,
into=Table,
dialect=dialect,
**opts,
)
table_expression = maybe_parse(table, into=Table, dialect=dialect, **opts)
properties_expression = None
if properties:
properties_expression = Properties.from_dict(properties)
@ -3493,7 +3476,10 @@ class Select(Subqueryable):
return self.expressions
class Subquery(DerivedTable, Unionable):
UNWRAPPED_QUERIES = (Select, Union)
class Subquery(DerivedTable, Query):
arg_types = {
"this": True,
"alias": False,
@ -3502,9 +3488,7 @@ class Subquery(DerivedTable, Unionable):
}
def unnest(self):
"""
Returns the first non subquery.
"""
"""Returns the first non subquery."""
expression = self
while isinstance(expression, Subquery):
expression = expression.this
@ -3516,6 +3500,18 @@ class Subquery(DerivedTable, Unionable):
expression = t.cast(Subquery, expression.parent)
return expression
def select(
self,
*expressions: t.Optional[ExpOrStr],
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> Subquery:
this = maybe_copy(self, copy)
this.unnest().select(*expressions, append=append, dialect=dialect, copy=False, **opts)
return this
@property
def is_wrapper(self) -> bool:
"""
@ -3603,6 +3599,10 @@ class WindowSpec(Expression):
}
class PreWhere(Expression):
pass
class Where(Expression):
pass
@ -3646,6 +3646,10 @@ class Boolean(Condition):
class DataTypeParam(Expression):
arg_types = {"this": True, "expression": False}
@property
def name(self) -> str:
return self.this.name
class DataType(Expression):
arg_types = {
@ -3926,11 +3930,17 @@ class Rollback(Expression):
class AlterTable(Expression):
arg_types = {"this": True, "actions": True, "exists": False, "only": False}
arg_types = {
"this": True,
"actions": True,
"exists": False,
"only": False,
"options": False,
}
class AddConstraint(Expression):
arg_types = {"this": False, "expression": False, "enforced": False}
arg_types = {"expressions": True}
class DropPartition(Expression):
@ -3995,6 +4005,10 @@ class Overlaps(Binary):
class Dot(Binary):
@property
def is_star(self) -> bool:
return self.expression.is_star
@property
def name(self) -> str:
return self.expression.name
@ -4390,6 +4404,10 @@ class Anonymous(Func):
arg_types = {"this": True, "expressions": False}
is_var_len_args = True
@property
def name(self) -> str:
return self.this if isinstance(self.this, str) else self.this.name
class AnonymousAggFunc(AggFunc):
arg_types = {"this": True, "expressions": False}
@ -4433,8 +4451,13 @@ class ToChar(Func):
arg_types = {"this": True, "format": False, "nlsparam": False}
# https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver16#syntax
class Convert(Func):
arg_types = {"this": True, "expression": True, "style": False}
class GenerateSeries(Func):
arg_types = {"start": True, "end": True, "step": False}
arg_types = {"start": True, "end": True, "step": False, "is_end_exclusive": False}
class ArrayAgg(AggFunc):
@ -4624,6 +4647,11 @@ class ConcatWs(Concat):
_sql_names = ["CONCAT_WS"]
# https://docs.oracle.com/cd/B13789_01/server.101/b10759/operators004.htm#i1035022
class ConnectByRoot(Func):
pass
class Count(AggFunc):
arg_types = {"this": False, "expressions": False}
is_var_len_args = True
@ -5197,6 +5225,10 @@ class Month(Func):
pass
class AddMonths(Func):
arg_types = {"this": True, "expression": True}
class Nvl2(Func):
arg_types = {"this": True, "true": True, "false": False}
@ -5313,6 +5345,10 @@ class SHA2(Func):
arg_types = {"this": True, "length": False}
class Sign(Func):
_sql_names = ["SIGN", "SIGNUM"]
class SortArray(Func):
arg_types = {"this": True, "asc": False}
@ -5554,7 +5590,13 @@ class Use(Expression):
class Merge(Expression):
arg_types = {"this": True, "using": True, "on": True, "expressions": True, "with": False}
arg_types = {
"this": True,
"using": True,
"on": True,
"expressions": True,
"with": False,
}
class When(Func):
@ -5587,8 +5629,7 @@ def maybe_parse(
prefix: t.Optional[str] = None,
copy: bool = False,
**opts,
) -> E:
...
) -> E: ...
@t.overload
@ -5600,8 +5641,7 @@ def maybe_parse(
prefix: t.Optional[str] = None,
copy: bool = False,
**opts,
) -> E:
...
) -> E: ...
def maybe_parse(
@ -5653,13 +5693,11 @@ def maybe_parse(
@t.overload
def maybe_copy(instance: None, copy: bool = True) -> None:
...
def maybe_copy(instance: None, copy: bool = True) -> None: ...
@t.overload
def maybe_copy(instance: E, copy: bool = True) -> E:
...
def maybe_copy(instance: E, copy: bool = True) -> E: ...
def maybe_copy(instance, copy=True):
@ -6282,15 +6320,13 @@ SAFE_IDENTIFIER_RE: t.Pattern[str] = re.compile(r"^[_a-zA-Z][\w]*$")
@t.overload
def to_identifier(name: None, quoted: t.Optional[bool] = None, copy: bool = True) -> None:
...
def to_identifier(name: None, quoted: t.Optional[bool] = None, copy: bool = True) -> None: ...
@t.overload
def to_identifier(
name: str | Identifier, quoted: t.Optional[bool] = None, copy: bool = True
) -> Identifier:
...
) -> Identifier: ...
def to_identifier(name, quoted=None, copy=True):
@ -6362,13 +6398,11 @@ def to_interval(interval: str | Literal) -> Interval:
@t.overload
def to_table(sql_path: str | Table, **kwargs) -> Table:
...
def to_table(sql_path: str | Table, **kwargs) -> Table: ...
@t.overload
def to_table(sql_path: None, **kwargs) -> None:
...
def to_table(sql_path: None, **kwargs) -> None: ...
def to_table(
@ -6929,7 +6963,7 @@ def replace_placeholders(expression: Expression, *args, **kwargs) -> Expression:
if isinstance(node, Placeholder):
if node.name:
new_name = kwargs.get(node.name)
if new_name:
if new_name is not None:
return convert(new_name)
else:
try:
@ -6943,7 +6977,7 @@ def replace_placeholders(expression: Expression, *args, **kwargs) -> Expression:
def expand(
expression: Expression,
sources: t.Dict[str, Subqueryable],
sources: t.Dict[str, Query],
dialect: DialectType = None,
copy: bool = True,
) -> Expression:
@ -6959,7 +6993,7 @@ def expand(
Args:
expression: The expression to expand.
sources: A dictionary of name to Subqueryables.
sources: A dictionary of name to Queries.
dialect: The dialect of the sources dict.
copy: Whether to copy the expression during transformation. Defaults to True.