Merging upstream version 25.16.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
7688e2bdf8
commit
bad79d1f7c
110 changed files with 75353 additions and 68092 deletions
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue