1
0
Fork 0

Merging upstream version 25.16.1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-13 21:52:32 +01:00
parent 7688e2bdf8
commit bad79d1f7c
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
110 changed files with 75353 additions and 68092 deletions

View file

@ -1387,6 +1387,7 @@ class Create(DDL):
"exists": False,
"properties": False,
"replace": False,
"refresh": False,
"unique": False,
"indexes": False,
"no_schema_binding": False,
@ -1436,7 +1437,13 @@ class Clone(Expression):
class Describe(Expression):
arg_types = {"this": True, "style": False, "kind": False, "expressions": False}
arg_types = {
"this": True,
"style": False,
"kind": False,
"expressions": False,
"partition": False,
}
# https://duckdb.org/docs/guides/meta/summarize.html
@ -2000,6 +2007,11 @@ class Drop(Expression):
"cluster": False,
}
@property
def kind(self) -> t.Optional[str]:
kind = self.args.get("kind")
return kind and kind.upper()
class Filter(Expression):
arg_types = {"this": True, "expression": True}
@ -2158,6 +2170,8 @@ class Insert(DDL, DML):
"ignore": False,
"by_name": False,
"stored": False,
"partition": False,
"settings": False,
}
def with_(
@ -2464,17 +2478,17 @@ class Offset(Expression):
class Order(Expression):
arg_types = {
"this": False,
"expressions": True,
"interpolate": False,
"siblings": False,
}
arg_types = {"this": False, "expressions": True, "siblings": False}
# https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier
class WithFill(Expression):
arg_types = {"from": False, "to": False, "step": False}
arg_types = {
"from": False,
"to": False,
"step": False,
"interpolate": False,
}
# hive specific sorts
@ -2669,6 +2683,11 @@ class OnCluster(Property):
arg_types = {"this": True}
# Clickhouse EMPTY table "property"
class EmptyProperty(Property):
arg_types = {}
class LikeProperty(Property):
arg_types = {"this": True, "expressions": False}
@ -2735,6 +2754,10 @@ class PartitionedOfProperty(Property):
arg_types = {"this": True, "expression": True}
class StreamingTableProperty(Property):
arg_types = {}
class RemoteWithConnectionModelProperty(Property):
arg_types = {"this": True}
@ -3137,11 +3160,11 @@ class SetOperation(Query):
return self.this.unnest().selects
@property
def left(self) -> Expression:
def left(self) -> Query:
return self.this
@property
def right(self) -> Expression:
def right(self) -> Query:
return self.expression
@ -3859,6 +3882,7 @@ class Pivot(Expression):
"group": False,
"columns": False,
"include_nulls": False,
"default_on_null": False,
}
@property
@ -3948,6 +3972,8 @@ class DataTypeParam(Expression):
return self.this.name
# The `nullable` arg is helpful when transpiling types from other dialects to ClickHouse, which
# assumes non-nullable types by default. Values `None` and `True` mean the type is nullable.
class DataType(Expression):
arg_types = {
"this": True,
@ -3956,6 +3982,7 @@ class DataType(Expression):
"values": False,
"prefix": False,
"kind": False,
"nullable": False,
}
class Type(AutoName):
@ -4194,28 +4221,45 @@ class DataType(Expression):
return DataType(**{**data_type_exp.args, **kwargs})
def is_type(self, *dtypes: DATA_TYPE) -> bool:
def is_type(self, *dtypes: DATA_TYPE, check_nullable: bool = False) -> bool:
"""
Checks whether this DataType matches one of the provided data types. Nested types or precision
will be compared using "structural equivalence" semantics, so e.g. array<int> != array<float>.
Args:
dtypes: the data types to compare this DataType to.
check_nullable: whether to take the NULLABLE type constructor into account for the comparison.
If false, it means that NULLABLE<INT> is equivalent to INT.
Returns:
True, if and only if there is a type in `dtypes` which is equal to this DataType.
"""
if (
not check_nullable
and self.this == DataType.Type.NULLABLE
and len(self.expressions) == 1
):
this_type = self.expressions[0]
else:
this_type = self
for dtype in dtypes:
other = DataType.build(dtype, copy=False, udt=True)
other_type = DataType.build(dtype, copy=False, udt=True)
if (
not check_nullable
and other_type.this == DataType.Type.NULLABLE
and len(other_type.expressions) == 1
):
other_type = other_type.expressions[0]
if (
other.expressions
or self.this == DataType.Type.USERDEFINED
or other.this == DataType.Type.USERDEFINED
other_type.expressions
or this_type.this == DataType.Type.USERDEFINED
or other_type.this == DataType.Type.USERDEFINED
):
matches = self == other
matches = this_type == other_type
else:
matches = self.this == other.this
matches = this_type.this == other_type.this
if matches:
return True
@ -4270,9 +4314,10 @@ class Rollback(Expression):
arg_types = {"savepoint": False, "this": False}
class AlterTable(Expression):
class Alter(Expression):
arg_types = {
"this": True,
"kind": True,
"actions": True,
"exists": False,
"only": False,
@ -4536,6 +4581,12 @@ class PivotAlias(Alias):
pass
# Represents Snowflake's ANY [ ORDER BY ... ] syntax
# https://docs.snowflake.com/en/sql-reference/constructs/pivot
class PivotAny(Expression):
arg_types = {"this": False}
class Aliases(Expression):
arg_types = {"this": True, "expressions": True}
@ -4790,7 +4841,7 @@ class ApproxDistinct(AggFunc):
class Array(Func):
arg_types = {"expressions": False}
arg_types = {"expressions": False, "bracket_notation": False}
is_var_len_args = True
@ -4833,10 +4884,21 @@ class Convert(Func):
arg_types = {"this": True, "expression": True, "style": False}
class ConvertTimezone(Func):
arg_types = {"source_tz": False, "target_tz": True, "timestamp": True}
class GenerateSeries(Func):
arg_types = {"start": True, "end": True, "step": False, "is_end_exclusive": False}
# Postgres' GENERATE_SERIES function returns a row set, i.e. it implicitly explodes when it's
# used in a projection, so this expression is a helper that facilitates transpilation to other
# dialects. For example, we'd generate UNNEST(GENERATE_SERIES(...)) in DuckDB
class ExplodingGenerateSeries(GenerateSeries):
pass
class ArrayAgg(AggFunc):
pass
@ -5025,7 +5087,7 @@ class Ceil(Func):
class Coalesce(Func):
arg_types = {"this": True, "expressions": False}
arg_types = {"this": True, "expressions": False, "is_nvl": False}
is_var_len_args = True
_sql_names = ["COALESCE", "IFNULL", "NVL"]
@ -5077,7 +5139,7 @@ class CurrentTime(Func):
class CurrentTimestamp(Func):
arg_types = {"this": False, "transaction": False}
arg_types = {"this": False, "sysdate": False}
class CurrentUser(Func):
@ -5286,6 +5348,7 @@ class Unnest(Func, UDTF):
"expressions": True,
"alias": False,
"offset": False,
"explode_array": False,
}
@property
@ -5309,6 +5372,11 @@ class ToBase64(Func):
pass
# https://trino.io/docs/current/functions/datetime.html#from_iso8601_timestamp
class FromISO8601Timestamp(Func):
_sql_names = ["FROM_ISO8601_TIMESTAMP"]
class GapFill(Func):
arg_types = {
"this": True,
@ -5321,8 +5389,14 @@ class GapFill(Func):
}
# https://cloud.google.com/bigquery/docs/reference/standard-sql/array_functions#generate_date_array
class GenerateDateArray(Func):
arg_types = {"start": True, "end": True, "interval": False}
arg_types = {"start": True, "end": True, "step": False}
# https://cloud.google.com/bigquery/docs/reference/standard-sql/array_functions#generate_timestamp_array
class GenerateTimestampArray(Func):
arg_types = {"start": True, "end": True, "step": True}
class Greatest(Func):
@ -5639,6 +5713,10 @@ class ScopeResolution(Expression):
arg_types = {"this": False, "expression": True}
class Stream(Expression):
pass
class StarMap(Func):
pass
@ -5920,7 +5998,7 @@ class Time(Func):
class TimeToStr(Func):
arg_types = {"this": True, "format": True, "culture": False, "timezone": False}
arg_types = {"this": True, "format": True, "culture": False, "zone": False}
class TimeToTimeStr(Func):
@ -5936,7 +6014,7 @@ class TimeStrToDate(Func):
class TimeStrToTime(Func):
pass
arg_types = {"this": True, "zone": False}
class TimeStrToUnix(Func):
@ -7144,7 +7222,9 @@ def column(
return this
def cast(expression: ExpOrStr, to: DATA_TYPE, copy: bool = True, **opts) -> Cast:
def cast(
expression: ExpOrStr, to: DATA_TYPE, copy: bool = True, dialect: DialectType = None, **opts
) -> Cast:
"""Cast an expression to a data type.
Example:
@ -7155,15 +7235,37 @@ def cast(expression: ExpOrStr, to: DATA_TYPE, copy: bool = True, **opts) -> Cast
expression: The expression to cast.
to: The datatype to cast to.
copy: Whether to copy the supplied expressions.
dialect: The target dialect. This is used to prevent a re-cast in the following scenario:
- The expression to be cast is already a exp.Cast expression
- The existing cast is to a type that is logically equivalent to new type
For example, if :expression='CAST(x as DATETIME)' and :to=Type.TIMESTAMP,
but in the target dialect DATETIME is mapped to TIMESTAMP, then we will NOT return `CAST(x (as DATETIME) as TIMESTAMP)`
and instead just return the original expression `CAST(x as DATETIME)`.
This is to prevent it being output as a double cast `CAST(x (as TIMESTAMP) as TIMESTAMP)` once the DATETIME -> TIMESTAMP
mapping is applied in the target dialect generator.
Returns:
The new Cast instance.
"""
expr = maybe_parse(expression, copy=copy, **opts)
data_type = DataType.build(to, copy=copy, **opts)
expr = maybe_parse(expression, copy=copy, dialect=dialect, **opts)
data_type = DataType.build(to, copy=copy, dialect=dialect, **opts)
if expr.is_type(data_type):
return expr
# dont re-cast if the expression is already a cast to the correct type
if isinstance(expr, Cast):
from sqlglot.dialects.dialect import Dialect
target_dialect = Dialect.get_or_raise(dialect)
type_mapping = target_dialect.generator_class.TYPE_MAPPING
existing_cast_type: DataType.Type = expr.to.this
new_cast_type: DataType.Type = data_type.this
types_are_equivalent = type_mapping.get(
existing_cast_type, existing_cast_type
) == type_mapping.get(new_cast_type, new_cast_type)
if expr.is_type(data_type) or types_are_equivalent:
return expr
expr = Cast(this=expr, to=data_type)
expr.type = data_type
@ -7259,7 +7361,7 @@ def rename_table(
old_name: str | Table,
new_name: str | Table,
dialect: DialectType = None,
) -> AlterTable:
) -> Alter:
"""Build ALTER TABLE... RENAME... expression
Args:
@ -7272,8 +7374,9 @@ def rename_table(
"""
old_table = to_table(old_name, dialect=dialect)
new_table = to_table(new_name, dialect=dialect)
return AlterTable(
return Alter(
this=old_table,
kind="TABLE",
actions=[
RenameTable(this=new_table),
],
@ -7286,7 +7389,7 @@ def rename_column(
new_column_name: str | Column,
exists: t.Optional[bool] = None,
dialect: DialectType = None,
) -> AlterTable:
) -> Alter:
"""Build ALTER TABLE... RENAME COLUMN... expression
Args:
@ -7302,8 +7405,9 @@ def rename_column(
table = to_table(table_name, dialect=dialect)
old_column = to_column(old_column_name, dialect=dialect)
new_column = to_column(new_column_name, dialect=dialect)
return AlterTable(
return Alter(
this=table,
kind="TABLE",
actions=[
RenameColumn(this=old_column, to=new_column, exists=exists),
],
@ -7335,12 +7439,15 @@ def convert(value: t.Any, copy: bool = False) -> Expression:
if isinstance(value, bytes):
return HexString(this=value.hex())
if isinstance(value, datetime.datetime):
datetime_literal = Literal.string(
(value if value.tzinfo else value.replace(tzinfo=datetime.timezone.utc)).isoformat(
sep=" "
)
)
return TimeStrToTime(this=datetime_literal)
datetime_literal = Literal.string(value.isoformat(sep=" "))
tz = None
if value.tzinfo:
# this works for zoneinfo.ZoneInfo, pytz.timezone and datetime.datetime.utc to return IANA timezone names like "America/Los_Angeles"
# instead of abbreviations like "PDT". This is for consistency with other timezone handling functions in SQLGlot
tz = Literal.string(str(value.tzinfo))
return TimeStrToTime(this=datetime_literal, zone=tz)
if isinstance(value, datetime.date):
date_literal = Literal.string(value.strftime("%Y-%m-%d"))
return DateStrToDate(this=date_literal)