1
0
Fork 0

Merging upstream version 12.2.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-13 15:53:39 +01:00
parent fffa0d5761
commit 62b2b24d3b
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
100 changed files with 35022 additions and 30936 deletions

View file

@ -64,6 +64,13 @@ class Expression(metaclass=_Expression):
and representing expressions as strings.
arg_types: determines what arguments (child nodes) are supported by an expression. It
maps arg keys to booleans that indicate whether the corresponding args are optional.
parent: a reference to the parent expression (or None, in case of root expressions).
arg_key: the arg key an expression is associated with, i.e. the name its parent expression
uses to refer to it.
comments: a list of comments that are associated with a given expression. This is used in
order to preserve comments when transpiling SQL code.
_type: the `sqlglot.expressions.DataType` type of an expression. This is inferred by the
optimizer, in order to enable some transformations that require type information.
Example:
>>> class Foo(Expression):
@ -74,13 +81,6 @@ class Expression(metaclass=_Expression):
Args:
args: a mapping used for retrieving the arguments of an expression, given their arg keys.
parent: a reference to the parent expression (or None, in case of root expressions).
arg_key: the arg key an expression is associated with, i.e. the name its parent expression
uses to refer to it.
comments: a list of comments that are associated with a given expression. This is used in
order to preserve comments when transpiling SQL code.
_type: the `sqlglot.expressions.DataType` type of an expression. This is inferred by the
optimizer, in order to enable some transformations that require type information.
"""
key = "expression"
@ -258,6 +258,12 @@ class Expression(metaclass=_Expression):
new.parent = self.parent
return new
def add_comments(self, comments: t.Optional[t.List[str]]) -> None:
if self.comments is None:
self.comments = []
if comments:
self.comments.extend(comments)
def append(self, arg_key, value):
"""
Appends value to arg_key if it's a list or sets it as a new list.
@ -650,7 +656,7 @@ ExpOrStr = t.Union[str, Expression]
class Condition(Expression):
def and_(self, *expressions, dialect=None, **opts):
def and_(self, *expressions, dialect=None, copy=True, **opts):
"""
AND this condition with one or multiple expressions.
@ -662,14 +668,15 @@ class Condition(Expression):
*expressions (str | Expression): the SQL code strings to parse.
If an `Expression` instance is passed, it will be used as-is.
dialect (str): the dialect used to parse the input expression.
copy (bool): whether or not to copy the involved expressions (only applies to Expressions).
opts (kwargs): other options to use to parse the input expressions.
Returns:
And: the new condition.
"""
return and_(self, *expressions, dialect=dialect, **opts)
return and_(self, *expressions, dialect=dialect, copy=copy, **opts)
def or_(self, *expressions, dialect=None, **opts):
def or_(self, *expressions, dialect=None, copy=True, **opts):
"""
OR this condition with one or multiple expressions.
@ -681,14 +688,15 @@ class Condition(Expression):
*expressions (str | Expression): the SQL code strings to parse.
If an `Expression` instance is passed, it will be used as-is.
dialect (str): the dialect used to parse the input expression.
copy (bool): whether or not to copy the involved expressions (only applies to Expressions).
opts (kwargs): other options to use to parse the input expressions.
Returns:
Or: the new condition.
"""
return or_(self, *expressions, dialect=dialect, **opts)
return or_(self, *expressions, dialect=dialect, copy=copy, **opts)
def not_(self):
def not_(self, copy=True):
"""
Wrap this condition with NOT.
@ -696,14 +704,17 @@ class Condition(Expression):
>>> condition("x=1").not_().sql()
'NOT x = 1'
Args:
copy (bool): whether or not to copy this object.
Returns:
Not: the new condition.
"""
return not_(self)
return not_(self, copy=copy)
def _binop(self, klass: t.Type[E], other: ExpOrStr, reverse=False) -> E:
this = self
other = convert(other)
this = self.copy()
other = convert(other, copy=True)
if not isinstance(this, klass) and not isinstance(other, klass):
this = _wrap(this, Binary)
other = _wrap(other, Binary)
@ -711,20 +722,25 @@ class Condition(Expression):
return klass(this=other, expression=this)
return klass(this=this, expression=other)
def __getitem__(self, other: ExpOrStr | slice | t.Tuple[ExpOrStr]):
if isinstance(other, slice):
return Between(
this=self,
low=convert(other.start),
high=convert(other.stop),
)
return Bracket(this=self, expressions=[convert(e) for e in ensure_list(other)])
def __getitem__(self, other: ExpOrStr | t.Tuple[ExpOrStr]):
return Bracket(
this=self.copy(), expressions=[convert(e, copy=True) for e in ensure_list(other)]
)
def isin(self, *expressions: ExpOrStr, query: t.Optional[ExpOrStr] = None, **opts) -> In:
def isin(
self, *expressions: t.Any, query: t.Optional[ExpOrStr] = None, copy=True, **opts
) -> In:
return In(
this=self,
expressions=[convert(e) for e in expressions],
query=maybe_parse(query, **opts) if query else None,
this=_maybe_copy(self, copy),
expressions=[convert(e, copy=copy) for e in expressions],
query=maybe_parse(query, copy=copy, **opts) if query else None,
)
def between(self, low: t.Any, high: t.Any, copy=True, **opts) -> Between:
return Between(
this=_maybe_copy(self, copy),
low=convert(low, copy=copy, **opts),
high=convert(high, copy=copy, **opts),
)
def like(self, other: ExpOrStr) -> Like:
@ -809,10 +825,10 @@ class Condition(Expression):
return self._binop(Or, other, reverse=True)
def __neg__(self) -> Neg:
return Neg(this=_wrap(self, Binary))
return Neg(this=_wrap(self.copy(), Binary))
def __invert__(self) -> Not:
return not_(self)
return not_(self.copy())
class Predicate(Condition):
@ -830,11 +846,7 @@ class DerivedTable(Expression):
@property
def selects(self):
alias = self.args.get("alias")
if alias:
return alias.columns
return []
return self.this.selects if isinstance(self.this, Subqueryable) else []
@property
def named_selects(self):
@ -904,7 +916,10 @@ class Unionable(Expression):
class UDTF(DerivedTable, Unionable):
pass
@property
def selects(self):
alias = self.args.get("alias")
return alias.columns if alias else []
class Cache(Expression):
@ -1073,6 +1088,10 @@ class ColumnDef(Expression):
"position": False,
}
@property
def constraints(self) -> t.List[ColumnConstraint]:
return self.args.get("constraints") or []
class AlterColumn(Expression):
arg_types = {
@ -1100,6 +1119,10 @@ class Comment(Expression):
class ColumnConstraint(Expression):
arg_types = {"this": False, "kind": True}
@property
def kind(self) -> ColumnConstraintKind:
return self.args["kind"]
class ColumnConstraintKind(Expression):
pass
@ -1937,6 +1960,15 @@ class Reference(Expression):
class Tuple(Expression):
arg_types = {"expressions": False}
def isin(
self, *expressions: t.Any, query: t.Optional[ExpOrStr] = None, copy=True, **opts
) -> In:
return In(
this=_maybe_copy(self, copy),
expressions=[convert(e, copy=copy) for e in expressions],
query=maybe_parse(query, copy=copy, **opts) if query else None,
)
class Subqueryable(Unionable):
def subquery(self, alias=None, copy=True) -> Subquery:
@ -2236,6 +2268,8 @@ class Select(Subqueryable):
"expressions": False,
"hint": False,
"distinct": False,
"struct": False, # https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#return_query_results_as_a_value_table
"value": False,
"into": False,
"from": False,
**QUERY_MODIFIERS,
@ -2611,7 +2645,7 @@ class Select(Subqueryable):
join.set("kind", kind.text)
if on:
on = and_(*ensure_collection(on), dialect=dialect, **opts)
on = and_(*ensure_collection(on), dialect=dialect, copy=copy, **opts)
join.set("on", on)
if using:
@ -2723,7 +2757,7 @@ class Select(Subqueryable):
**opts,
)
def distinct(self, distinct=True, copy=True) -> Select:
def distinct(self, *ons: ExpOrStr, distinct: bool = True, copy: bool = True) -> Select:
"""
Set the OFFSET expression.
@ -2732,14 +2766,16 @@ class Select(Subqueryable):
'SELECT DISTINCT x FROM tbl'
Args:
distinct (bool): whether the Select should be distinct
copy (bool): if `False`, modify this expression instance in-place.
ons: the expressions to distinct on
distinct: whether the Select should be distinct
copy: if `False`, modify this expression instance in-place.
Returns:
Select: the modified expression.
"""
instance = _maybe_copy(self, copy)
instance.set("distinct", Distinct() if distinct else None)
on = Tuple(expressions=[maybe_parse(on, copy=copy) for on in ons]) if ons else None
instance.set("distinct", Distinct(on=on) if distinct else None)
return instance
def ctas(self, table, properties=None, dialect=None, copy=True, **opts) -> Create:
@ -2969,6 +3005,10 @@ class DataType(Expression):
USMALLINT = auto()
BIGINT = auto()
UBIGINT = auto()
INT128 = auto()
UINT128 = auto()
INT256 = auto()
UINT256 = auto()
FLOAT = auto()
DOUBLE = auto()
DECIMAL = auto()
@ -3022,6 +3062,8 @@ class DataType(Expression):
Type.TINYINT,
Type.SMALLINT,
Type.BIGINT,
Type.INT128,
Type.INT256,
}
FLOAT_TYPES = {
@ -3069,10 +3111,6 @@ class PseudoType(Expression):
pass
class StructKwarg(Expression):
arg_types = {"this": True, "expression": True}
# WHERE x <OP> EXISTS|ALL|ANY|SOME(SELECT ...)
class SubqueryPredicate(Predicate):
pass
@ -3538,14 +3576,20 @@ class Case(Func):
arg_types = {"this": False, "ifs": True, "default": False}
def when(self, condition: ExpOrStr, then: ExpOrStr, copy: bool = True, **opts) -> Case:
this = self.copy() if copy else self
this.append("ifs", If(this=maybe_parse(condition, **opts), true=maybe_parse(then, **opts)))
return this
instance = _maybe_copy(self, copy)
instance.append(
"ifs",
If(
this=maybe_parse(condition, copy=copy, **opts),
true=maybe_parse(then, copy=copy, **opts),
),
)
return instance
def else_(self, condition: ExpOrStr, copy: bool = True, **opts) -> Case:
this = self.copy() if copy else self
this.set("default", maybe_parse(condition, **opts))
return this
instance = _maybe_copy(self, copy)
instance.set("default", maybe_parse(condition, copy=copy, **opts))
return instance
class Cast(Func):
@ -3760,6 +3804,14 @@ class Floor(Func):
arg_types = {"this": True, "decimals": False}
class FromBase64(Func):
pass
class ToBase64(Func):
pass
class Greatest(Func):
arg_types = {"this": True, "expressions": False}
is_var_len_args = True
@ -3930,11 +3982,11 @@ class Pow(Binary, Func):
class PercentileCont(AggFunc):
pass
arg_types = {"this": True, "expression": False}
class PercentileDisc(AggFunc):
pass
arg_types = {"this": True, "expression": False}
class Quantile(AggFunc):
@ -4405,14 +4457,16 @@ def _apply_conjunction_builder(
if append and existing is not None:
expressions = [existing.this if into else existing] + list(expressions)
node = and_(*expressions, dialect=dialect, **opts)
node = and_(*expressions, dialect=dialect, copy=copy, **opts)
inst.set(arg, into(this=node) if into else node)
return inst
def _combine(expressions, operator, dialect=None, **opts):
expressions = [condition(expression, dialect=dialect, **opts) for expression in expressions]
def _combine(expressions, operator, dialect=None, copy=True, **opts):
expressions = [
condition(expression, dialect=dialect, copy=copy, **opts) for expression in expressions
]
this = expressions[0]
if expressions[1:]:
this = _wrap(this, Connector)
@ -4626,7 +4680,7 @@ def delete(
return delete_expr
def condition(expression, dialect=None, **opts) -> Condition:
def condition(expression, dialect=None, copy=True, **opts) -> Condition:
"""
Initialize a logical condition expression.
@ -4645,6 +4699,7 @@ def condition(expression, dialect=None, **opts) -> Condition:
If an Expression instance is passed, this is used as-is.
dialect (str): the dialect used to parse the input expression (in the case that the
input expression is a SQL string).
copy (bool): Whether or not to copy `expression` (only applies to expressions).
**opts: other options to use to parse the input expressions (again, in the case
that the input expression is a SQL string).
@ -4655,11 +4710,12 @@ def condition(expression, dialect=None, **opts) -> Condition:
expression,
into=Condition,
dialect=dialect,
copy=copy,
**opts,
)
def and_(*expressions, dialect=None, **opts) -> And:
def and_(*expressions, dialect=None, copy=True, **opts) -> And:
"""
Combine multiple conditions with an AND logical operator.
@ -4671,15 +4727,16 @@ def and_(*expressions, dialect=None, **opts) -> And:
*expressions (str | Expression): the SQL code strings to parse.
If an Expression instance is passed, this is used as-is.
dialect (str): the dialect used to parse the input expression.
copy (bool): whether or not to copy `expressions` (only applies to Expressions).
**opts: other options to use to parse the input expressions.
Returns:
And: the new condition
"""
return _combine(expressions, And, dialect, **opts)
return _combine(expressions, And, dialect, copy=copy, **opts)
def or_(*expressions, dialect=None, **opts) -> Or:
def or_(*expressions, dialect=None, copy=True, **opts) -> Or:
"""
Combine multiple conditions with an OR logical operator.
@ -4691,15 +4748,16 @@ def or_(*expressions, dialect=None, **opts) -> Or:
*expressions (str | Expression): the SQL code strings to parse.
If an Expression instance is passed, this is used as-is.
dialect (str): the dialect used to parse the input expression.
copy (bool): whether or not to copy `expressions` (only applies to Expressions).
**opts: other options to use to parse the input expressions.
Returns:
Or: the new condition
"""
return _combine(expressions, Or, dialect, **opts)
return _combine(expressions, Or, dialect, copy=copy, **opts)
def not_(expression, dialect=None, **opts) -> Not:
def not_(expression, dialect=None, copy=True, **opts) -> Not:
"""
Wrap a condition with a NOT operator.
@ -4719,13 +4777,14 @@ def not_(expression, dialect=None, **opts) -> Not:
this = condition(
expression,
dialect=dialect,
copy=copy,
**opts,
)
return Not(this=_wrap(this, Connector))
def paren(expression) -> Paren:
return Paren(this=expression)
def paren(expression, copy=True) -> Paren:
return Paren(this=_maybe_copy(expression, copy))
SAFE_IDENTIFIER_RE = re.compile(r"^[_a-zA-Z][\w]*$")
@ -4998,29 +5057,20 @@ def values(
alias: optional alias
columns: Optional list of ordered column names or ordered dictionary of column names to types.
If either are provided then an alias is also required.
If a dictionary is provided then the first column of the values will be casted to the expected type
in order to help with type inference.
Returns:
Values: the Values expression object
"""
if columns and not alias:
raise ValueError("Alias is required when providing columns")
table_alias = (
TableAlias(this=to_identifier(alias), columns=[to_identifier(x) for x in columns])
if columns
else TableAlias(this=to_identifier(alias) if alias else None)
)
expressions = [convert(tup) for tup in values]
if columns and isinstance(columns, dict):
types = list(columns.values())
expressions[0].set(
"expressions",
[cast(x, types[i]) for i, x in enumerate(expressions[0].expressions)],
)
return Values(
expressions=expressions,
alias=table_alias,
expressions=[convert(tup) for tup in values],
alias=(
TableAlias(this=to_identifier(alias), columns=[to_identifier(x) for x in columns])
if columns
else (TableAlias(this=to_identifier(alias)) if alias else None)
),
)
@ -5068,19 +5118,20 @@ def rename_table(old_name: str | Table, new_name: str | Table) -> AlterTable:
)
def convert(value) -> Expression:
def convert(value: t.Any, copy: bool = False) -> Expression:
"""Convert a python value into an expression object.
Raises an error if a conversion is not possible.
Args:
value (Any): a python object
value: A python object.
copy: Whether or not to copy `value` (only applies to Expressions and collections).
Returns:
Expression: the equivalent expression object
Expression: the equivalent expression object.
"""
if isinstance(value, Expression):
return value
return _maybe_copy(value, copy)
if isinstance(value, str):
return Literal.string(value)
if isinstance(value, bool):
@ -5098,13 +5149,13 @@ def convert(value) -> Expression:
date_literal = Literal.string(value.strftime("%Y-%m-%d"))
return DateStrToDate(this=date_literal)
if isinstance(value, tuple):
return Tuple(expressions=[convert(v) for v in value])
return Tuple(expressions=[convert(v, copy=copy) for v in value])
if isinstance(value, list):
return Array(expressions=[convert(v) for v in value])
return Array(expressions=[convert(v, copy=copy) for v in value])
if isinstance(value, dict):
return Map(
keys=[convert(k) for k in value],
values=[convert(v) for v in value.values()],
keys=[convert(k, copy=copy) for k in value],
values=[convert(v, copy=copy) for v in value.values()],
)
raise ValueError(f"Cannot convert {value}")