sqlglotc 30.24.0__tar.gz → 30.25.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sqlglotc-30.24.0/sqlglotc.egg-info → sqlglotc-30.25.0}/PKG-INFO +2 -2
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/pyproject.toml +1 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/array.py +4 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/builders.py +1 -1
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/constraints.py +2 -1
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/core.py +7 -8
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/datatypes.py +3 -1
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/ddl.py +8 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/query.py +8 -3
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generator.py +73 -20
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/bigquery.py +1 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/clickhouse.py +7 -7
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/databricks.py +1 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/duckdb.py +72 -7
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/exasol.py +3 -6
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/hive.py +4 -1
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/oracle.py +0 -3
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/postgres.py +35 -2
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/presto.py +7 -2
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/python.py +5 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/snowflake.py +3 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/sqlite.py +6 -2
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/tsql.py +4 -1
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/optimizer/annotate_types.py +150 -93
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/optimizer/canonicalize_internal_names.py +11 -10
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/optimizer/qualify_columns.py +94 -158
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/optimizer/resolver.py +57 -8
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/optimizer/scope.py +16 -2
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/optimizer/simplify.py +5 -1
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parser.py +41 -12
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/clickhouse.py +5 -5
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/duckdb.py +81 -2
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/oracle.py +13 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/postgres.py +33 -5
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/sqlite.py +32 -1
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/tokenizer_core.py +2 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0/sqlglotc.egg-info}/PKG-INFO +2 -2
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglotc.egg-info/requires.txt +1 -1
- sqlglotc-30.25.0/sqlglotc.egg-info/scm_version.json +8 -0
- sqlglotc-30.24.0/sqlglotc.egg-info/scm_version.json +0 -8
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/MANIFEST.in +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/setup.cfg +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/setup.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/anonymize.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/errors.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/executor/table.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/aggregate.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/dml.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/functions.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/json.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/math.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/properties.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/string.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/expressions/temporal.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/athena.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/dax.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/doris.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/dremio.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/drill.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/druid.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/dune.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/fabric.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/materialize.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/mysql.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/prql.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/redshift.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/risingwave.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/singlestore.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/solr.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/spark.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/spark2.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/starrocks.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/tableau.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/teradata.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/generators/trino.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/helper.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/lineage.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/optimizer/qualify.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/optimizer/qualify_tables.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/athena.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/base.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/bigquery.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/databricks.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/dax.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/doris.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/dremio.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/drill.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/druid.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/dune.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/exasol.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/fabric.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/hive.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/materialize.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/mysql.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/presto.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/prql.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/redshift.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/risingwave.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/singlestore.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/snowflake.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/solr.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/spark.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/spark2.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/starrocks.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/tableau.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/teradata.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/trino.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/parsers/tsql.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/serde.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/time.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglot/trie.py +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglotc.egg-info/SOURCES.txt +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglotc.egg-info/dependency_links.txt +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglotc.egg-info/scm_file_list.json +0 -0
- {sqlglotc-30.24.0 → sqlglotc-30.25.0}/sqlglotc.egg-info/top_level.txt +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlglotc
|
|
3
|
-
Version: 30.
|
|
3
|
+
Version: 30.25.0
|
|
4
4
|
Summary: mypyc-compiled extensions for sqlglot
|
|
5
5
|
Author-email: Toby Mao <toby.mao@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://sqlglot.com/
|
|
8
8
|
Project-URL: Repository, https://github.com/tobymao/sqlglot
|
|
9
9
|
Requires-Python: >=3.10
|
|
10
|
-
Requires-Dist: sqlglot==30.
|
|
10
|
+
Requires-Dist: sqlglot==30.25.0
|
|
11
11
|
Provides-Extra: dev
|
|
12
12
|
Requires-Dist: setuptools>=61.0; extra == "dev"
|
|
13
13
|
Requires-Dist: setuptools_scm; extra == "dev"
|
|
@@ -254,6 +254,10 @@ class SplitToTable(Expression, Func, UDTF):
|
|
|
254
254
|
arg_types = {"this": True, "expression": True}
|
|
255
255
|
|
|
256
256
|
|
|
257
|
+
class StrtokSplitToTable(Expression, Func, UDTF):
|
|
258
|
+
arg_types = {"this": True, "expression": False}
|
|
259
|
+
|
|
260
|
+
|
|
257
261
|
class Stack(Expression, Func, UDTF):
|
|
258
262
|
arg_types = {"this": True, "expressions": True}
|
|
259
263
|
is_var_len_args = True
|
|
@@ -921,7 +921,7 @@ def replace_placeholders(expression: Expr, *args: object, **kwargs: t.Any) -> Ex
|
|
|
921
921
|
def _replace_placeholders(node: Expr, args: Iterator[object], **kwargs: object) -> Expr:
|
|
922
922
|
if isinstance(node, Placeholder):
|
|
923
923
|
if node.this:
|
|
924
|
-
new_name = kwargs.get(node.
|
|
924
|
+
new_name = kwargs.get(node.name)
|
|
925
925
|
if new_name is not None:
|
|
926
926
|
return _replace_placeholder(node, convert(new_name))
|
|
927
927
|
else:
|
|
@@ -161,7 +161,7 @@ class OnUpdateColumnConstraint(Expression, ColumnConstraintKind):
|
|
|
161
161
|
|
|
162
162
|
|
|
163
163
|
class PrimaryKeyColumnConstraint(Expression, ColumnConstraintKind):
|
|
164
|
-
arg_types = {"desc": False, "options": False}
|
|
164
|
+
arg_types = {"desc": False, "options": False, "include": False}
|
|
165
165
|
|
|
166
166
|
|
|
167
167
|
class TitleColumnConstraint(Expression, ColumnConstraintKind):
|
|
@@ -175,6 +175,7 @@ class UniqueColumnConstraint(Expression, ColumnConstraintKind):
|
|
|
175
175
|
"on_conflict": False,
|
|
176
176
|
"nulls": False,
|
|
177
177
|
"options": False,
|
|
178
|
+
"include": False,
|
|
178
179
|
}
|
|
179
180
|
|
|
180
181
|
|
|
@@ -1734,13 +1734,13 @@ class Column(Expression, Condition):
|
|
|
1734
1734
|
return self.name
|
|
1735
1735
|
|
|
1736
1736
|
@property
|
|
1737
|
-
def parts(self) -> list[
|
|
1737
|
+
def parts(self) -> list[Expr]:
|
|
1738
1738
|
"""Return the parts of a column in order catalog, db, table, name."""
|
|
1739
1739
|
return [
|
|
1740
1740
|
self.args[part] for part in ("catalog", "db", "table", "this") if self.args.get(part)
|
|
1741
1741
|
]
|
|
1742
1742
|
|
|
1743
|
-
def to_dot(self, include_dots: bool = True) ->
|
|
1743
|
+
def to_dot(self, include_dots: bool = True) -> Expr:
|
|
1744
1744
|
"""Converts the column into a dot expression."""
|
|
1745
1745
|
parts = self.parts
|
|
1746
1746
|
parent = self.parent
|
|
@@ -3071,7 +3071,7 @@ def alias_(
|
|
|
3071
3071
|
|
|
3072
3072
|
@t.overload
|
|
3073
3073
|
def column(
|
|
3074
|
-
col: str |
|
|
3074
|
+
col: str | Expr,
|
|
3075
3075
|
table: str | Identifier | None = None,
|
|
3076
3076
|
db: str | Identifier | None = None,
|
|
3077
3077
|
catalog: str | Identifier | None = None,
|
|
@@ -3085,7 +3085,7 @@ def column(
|
|
|
3085
3085
|
|
|
3086
3086
|
@t.overload
|
|
3087
3087
|
def column(
|
|
3088
|
-
col: str |
|
|
3088
|
+
col: str | Expr,
|
|
3089
3089
|
table: str | Identifier | None = None,
|
|
3090
3090
|
db: str | Identifier | None = None,
|
|
3091
3091
|
catalog: str | Identifier | None = None,
|
|
@@ -3111,19 +3111,18 @@ def column(
|
|
|
3111
3111
|
Build a Column.
|
|
3112
3112
|
|
|
3113
3113
|
Args:
|
|
3114
|
-
col: Column name.
|
|
3114
|
+
col: Column name or expression.
|
|
3115
3115
|
table: Table name.
|
|
3116
3116
|
db: Database name.
|
|
3117
3117
|
catalog: Catalog name.
|
|
3118
3118
|
fields: Additional fields using dots.
|
|
3119
3119
|
quoted: Whether to force quotes on the column's identifiers.
|
|
3120
|
-
copy: Whether to copy
|
|
3120
|
+
copy: Whether to copy expressions if passed in.
|
|
3121
3121
|
|
|
3122
3122
|
Returns:
|
|
3123
3123
|
The new Column instance.
|
|
3124
3124
|
"""
|
|
3125
|
-
if
|
|
3126
|
-
col = to_identifier(col, quoted=quoted, copy=copy)
|
|
3125
|
+
col = maybe_copy(col, copy) if isinstance(col, Expr) else to_identifier(col, quoted=quoted)
|
|
3127
3126
|
|
|
3128
3127
|
this: Column | Dot = Column(
|
|
3129
3128
|
this=col,
|
|
@@ -461,7 +461,9 @@ class IntervalSpan(DataType):
|
|
|
461
461
|
|
|
462
462
|
|
|
463
463
|
class Interval(_TimeUnit):
|
|
464
|
-
|
|
464
|
+
# fraction_in_string: a fractional amount was written with its unit in one string, e.g.
|
|
465
|
+
# INTERVAL '1.5 DAY', which differs from INTERVAL '1.5' DAY in e.g. DuckDB and Postgres
|
|
466
|
+
arg_types = {"this": False, "unit": False, "fraction_in_string": False}
|
|
465
467
|
|
|
466
468
|
|
|
467
469
|
DATA_TYPE = t.Union[str, Identifier, Dot, DataType, DType]
|
|
@@ -131,6 +131,14 @@ class Describe(Expression):
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
|
|
134
|
+
class ConnectTo(Expression):
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class Disconnect(Expression):
|
|
139
|
+
arg_types = {}
|
|
140
|
+
|
|
141
|
+
|
|
134
142
|
class Attach(Expression):
|
|
135
143
|
arg_types = {"this": True, "exists": False, "expressions": False}
|
|
136
144
|
|
|
@@ -663,7 +663,7 @@ class GroupingSets(Expression):
|
|
|
663
663
|
|
|
664
664
|
|
|
665
665
|
class Lambda(Expression):
|
|
666
|
-
arg_types = {"this": True, "expressions": True
|
|
666
|
+
arg_types = {"this": True, "expressions": True}
|
|
667
667
|
|
|
668
668
|
|
|
669
669
|
class Limit(Expression):
|
|
@@ -699,8 +699,9 @@ class Join(Expression):
|
|
|
699
699
|
"method": False,
|
|
700
700
|
"global_": False,
|
|
701
701
|
"hint": False,
|
|
702
|
-
"match_condition": False,
|
|
703
|
-
"
|
|
702
|
+
"match_condition": False,
|
|
703
|
+
"nearest": False,
|
|
704
|
+
"directed": False,
|
|
704
705
|
"expressions": False,
|
|
705
706
|
"pivots": False,
|
|
706
707
|
}
|
|
@@ -817,6 +818,10 @@ class Join(Expression):
|
|
|
817
818
|
return join
|
|
818
819
|
|
|
819
820
|
|
|
821
|
+
class Nearest(Expression):
|
|
822
|
+
arg_types = {"this": True, "count": True, "approximate": False, "similarity": False}
|
|
823
|
+
|
|
824
|
+
|
|
820
825
|
class Lateral(Expression, UDTF):
|
|
821
826
|
arg_types = {
|
|
822
827
|
"this": True,
|
|
@@ -333,6 +333,9 @@ class Generator:
|
|
|
333
333
|
# Whether MERGE ... WHEN MATCHED/NOT MATCHED THEN UPDATE/INSERT ... WHERE is supported
|
|
334
334
|
SUPPORTS_MERGE_WHERE = False
|
|
335
335
|
|
|
336
|
+
# Whether MERGE uses ALL BY NAME instead of a star to update or insert all columns
|
|
337
|
+
MERGE_ALL_BY_NAME = False
|
|
338
|
+
|
|
336
339
|
# Whether the INTERVAL expression works only with values like '1 day'
|
|
337
340
|
SINGLE_STRING_INTERVAL = False
|
|
338
341
|
|
|
@@ -370,6 +373,9 @@ class Generator:
|
|
|
370
373
|
# Whether directed joins are supported
|
|
371
374
|
DIRECTED_JOINS = False
|
|
372
375
|
|
|
376
|
+
# Whether top-k distance/similarity joins are supported
|
|
377
|
+
SUPPORTS_NEAREST_JOIN = False
|
|
378
|
+
|
|
373
379
|
# Whether table hints should be generated
|
|
374
380
|
TABLE_HINTS = True
|
|
375
381
|
|
|
@@ -414,9 +420,12 @@ class Generator:
|
|
|
414
420
|
# SELECT * VALUES into SELECT UNION
|
|
415
421
|
VALUES_AS_TABLE = True
|
|
416
422
|
|
|
417
|
-
# Whether
|
|
423
|
+
# Whether COLUMN/COLUMNS keywords are included when adding columns with ALTER TABLE.
|
|
418
424
|
ALTER_TABLE_INCLUDE_COLUMN_KEYWORD = True
|
|
419
425
|
|
|
426
|
+
# Whether ALTER TABLE mutli-column additions are wrapped in parentheses.
|
|
427
|
+
ALTER_TABLE_ADD_COLUMNS_WRAPPED = True
|
|
428
|
+
|
|
420
429
|
# UNNEST WITH ORDINALITY (presto) instead of UNNEST WITH OFFSET (bigquery)
|
|
421
430
|
UNNEST_WITH_ORDINALITY = True
|
|
422
431
|
|
|
@@ -1322,7 +1331,8 @@ class Generator:
|
|
|
1322
1331
|
return f"PRIMARY KEY{' DESC' if desc else ' ASC'}"
|
|
1323
1332
|
options = self.expressions(expression, key="options", flat=True, sep=" ")
|
|
1324
1333
|
options = f" {options}" if options else ""
|
|
1325
|
-
|
|
1334
|
+
include = self.sql(expression, "include")
|
|
1335
|
+
return f"PRIMARY KEY{include}{options}"
|
|
1326
1336
|
|
|
1327
1337
|
def uniquecolumnconstraint_sql(self, expression: exp.UniqueColumnConstraint) -> str:
|
|
1328
1338
|
this = self.sql(expression, "this")
|
|
@@ -1334,7 +1344,8 @@ class Generator:
|
|
|
1334
1344
|
nulls_sql = " NULLS NOT DISTINCT" if expression.args.get("nulls") else ""
|
|
1335
1345
|
options = self.expressions(expression, key="options", flat=True, sep=" ")
|
|
1336
1346
|
options = f" {options}" if options else ""
|
|
1337
|
-
|
|
1347
|
+
include = self.sql(expression, "include")
|
|
1348
|
+
return f"UNIQUE{nulls_sql}{this}{index_type}{on_conflict}{include}{options}"
|
|
1338
1349
|
|
|
1339
1350
|
def inoutcolumnconstraint_sql(self, expression: exp.InOutColumnConstraint) -> str:
|
|
1340
1351
|
input_ = expression.args.get("input_")
|
|
@@ -2024,7 +2035,9 @@ class Generator:
|
|
|
2024
2035
|
with_storage = self.expressions(expression, key="with_storage", flat=True)
|
|
2025
2036
|
with_storage = f" WITH ({with_storage})" if with_storage else ""
|
|
2026
2037
|
tablespace = self.sql(expression, "tablespace")
|
|
2027
|
-
|
|
2038
|
+
if tablespace:
|
|
2039
|
+
prefix = "" if isinstance(expression.parent, exp.Index) else " USING INDEX"
|
|
2040
|
+
tablespace = f"{prefix} TABLESPACE {tablespace}"
|
|
2028
2041
|
on = self.sql(expression, "on")
|
|
2029
2042
|
on = f" ON {on}" if on else ""
|
|
2030
2043
|
|
|
@@ -2168,7 +2181,7 @@ class Generator:
|
|
|
2168
2181
|
def property_name(self, expression: exp.Property, string_key: bool = False) -> str:
|
|
2169
2182
|
if isinstance(expression.this, exp.Dot):
|
|
2170
2183
|
return self.sql(expression, "this")
|
|
2171
|
-
return
|
|
2184
|
+
return self.sql(exp.Literal.string(expression.name)) if string_key else expression.name
|
|
2172
2185
|
|
|
2173
2186
|
def property_sql(self, expression: exp.Property) -> str:
|
|
2174
2187
|
property_cls = expression.__class__
|
|
@@ -2911,6 +2924,12 @@ class Generator:
|
|
|
2911
2924
|
this = self.indent(self.sql(expression, "this"))
|
|
2912
2925
|
return f"{self.seg('HAVING')}{self.sep()}{this}"
|
|
2913
2926
|
|
|
2927
|
+
def connectto_sql(self, expression: exp.ConnectTo) -> str:
|
|
2928
|
+
return f"CONNECT {self.sql(expression, 'this')}"
|
|
2929
|
+
|
|
2930
|
+
def disconnect_sql(self, expression: exp.Disconnect) -> str:
|
|
2931
|
+
return "DISCONNECT"
|
|
2932
|
+
|
|
2914
2933
|
def connect_sql(self, expression: exp.Connect) -> str:
|
|
2915
2934
|
start = self.sql(expression, "start")
|
|
2916
2935
|
start = self.seg(f"START WITH {start}") if start else ""
|
|
@@ -2922,7 +2941,7 @@ class Generator:
|
|
|
2922
2941
|
def prior_sql(self, expression: exp.Prior) -> str:
|
|
2923
2942
|
return f"PRIOR {self.sql(expression, 'this')}"
|
|
2924
2943
|
|
|
2925
|
-
def join_sql(self, expression: exp.Join) -> str:
|
|
2944
|
+
def join_sql(self, expression: exp.Join, join_op: str | None = None) -> str:
|
|
2926
2945
|
if not self.SEMI_ANTI_JOIN_WITH_SIDE and expression.kind in ("SEMI", "ANTI"):
|
|
2927
2946
|
side = None
|
|
2928
2947
|
else:
|
|
@@ -2942,6 +2961,8 @@ class Generator:
|
|
|
2942
2961
|
)
|
|
2943
2962
|
match_cond = self.sql(expression, "match_condition")
|
|
2944
2963
|
match_cond = f" MATCH_CONDITION ({match_cond})" if match_cond else ""
|
|
2964
|
+
nearest = self.sql(expression, "nearest")
|
|
2965
|
+
nearest = f" {nearest}" if nearest else ""
|
|
2945
2966
|
on_sql = self.sql(expression, "on")
|
|
2946
2967
|
using = expression.args.get("using")
|
|
2947
2968
|
|
|
@@ -2962,17 +2983,27 @@ class Generator:
|
|
|
2962
2983
|
on_sql = f"{space}USING ({on_sql})"
|
|
2963
2984
|
else:
|
|
2964
2985
|
on_sql = f"{space}ON {on_sql}"
|
|
2965
|
-
elif not op_sql:
|
|
2986
|
+
elif not op_sql and not nearest:
|
|
2966
2987
|
if isinstance(this, exp.Lateral) and this.args.get("cross_apply") is not None:
|
|
2967
2988
|
return f" {this_sql}"
|
|
2968
2989
|
|
|
2969
2990
|
return f", {this_sql}"
|
|
2970
2991
|
|
|
2971
|
-
if
|
|
2992
|
+
if join_op:
|
|
2993
|
+
op_sql = join_op
|
|
2994
|
+
elif op_sql != "STRAIGHT_JOIN":
|
|
2972
2995
|
op_sql = f"{op_sql} JOIN" if op_sql else "JOIN"
|
|
2973
2996
|
|
|
2974
2997
|
pivots = self.expressions(expression, key="pivots", sep="", flat=True)
|
|
2975
|
-
return f"{self.seg(op_sql)} {this_sql}{match_cond}{on_sql}{pivots}"
|
|
2998
|
+
return f"{self.seg(op_sql)} {this_sql}{match_cond}{nearest}{on_sql}{pivots}"
|
|
2999
|
+
|
|
3000
|
+
def nearest_sql(self, expression: exp.Nearest) -> str:
|
|
3001
|
+
if not self.SUPPORTS_NEAREST_JOIN:
|
|
3002
|
+
self.unsupported("NEAREST joins are not supported")
|
|
3003
|
+
|
|
3004
|
+
approximate = "APPROX " if expression.args.get("approximate") else ""
|
|
3005
|
+
metric = "SIMILARITY" if expression.args.get("similarity") else "DISTANCE"
|
|
3006
|
+
return f"{approximate}NEAREST {self.sql(expression, 'count')} BY {metric} {self.sql(expression, 'this')}"
|
|
2976
3007
|
|
|
2977
3008
|
def lambda_sql(self, expression: exp.Lambda, arrow_sep: str = "->", wrap: bool = True) -> str:
|
|
2978
3009
|
args = self.expressions(expression, flat=True)
|
|
@@ -3636,6 +3667,9 @@ class Generator:
|
|
|
3636
3667
|
first = "FIRST" if first else "LAST"
|
|
3637
3668
|
|
|
3638
3669
|
if not partition and not order and not spec and alias:
|
|
3670
|
+
# WINDOW w2 AS w1 is unparseable in DuckDB/Postgres; parens are required.
|
|
3671
|
+
if expression.arg_key == "windows":
|
|
3672
|
+
return f"{this} ({alias})"
|
|
3639
3673
|
return f"{this} {alias}"
|
|
3640
3674
|
|
|
3641
3675
|
args = self.format_args(
|
|
@@ -4085,8 +4119,8 @@ class Generator:
|
|
|
4085
4119
|
if this:
|
|
4086
4120
|
interval_keyword = f"{interval_keyword} " if interval_keyword else ""
|
|
4087
4121
|
if unit_expression and isinstance(unit_expression, exp.IntervalSpan):
|
|
4088
|
-
return f"{interval_keyword}
|
|
4089
|
-
return f"{interval_keyword}'{this}{unit}'"
|
|
4122
|
+
return f"{interval_keyword}{self.sql(exp.Literal.string(this))}{unit}"
|
|
4123
|
+
return f"{interval_keyword}{self.sql(exp.Literal.string(f'{this}{unit}'))}"
|
|
4090
4124
|
return f"{interval_keyword}{unit}"
|
|
4091
4125
|
|
|
4092
4126
|
this = self.sql(expression, "this")
|
|
@@ -4508,13 +4542,17 @@ class Generator:
|
|
|
4508
4542
|
return f"{keyword} {items_sql}"
|
|
4509
4543
|
|
|
4510
4544
|
def add_column_sql(self, expression: exp.Expr) -> str:
|
|
4511
|
-
|
|
4512
|
-
if
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4545
|
+
column_text = ""
|
|
4546
|
+
if self.ALTER_TABLE_INCLUDE_COLUMN_KEYWORD:
|
|
4547
|
+
if isinstance(expression, exp.ColumnDef):
|
|
4548
|
+
column_text = " COLUMN"
|
|
4549
|
+
elif isinstance(expression, exp.Schema):
|
|
4550
|
+
column_text = " COLUMNS"
|
|
4551
|
+
|
|
4552
|
+
if isinstance(expression, exp.Schema) and not self.ALTER_TABLE_ADD_COLUMNS_WRAPPED:
|
|
4553
|
+
sql = self.expressions(expression, flat=True)
|
|
4516
4554
|
else:
|
|
4517
|
-
|
|
4555
|
+
sql = self.sql(expression)
|
|
4518
4556
|
|
|
4519
4557
|
return f"ADD{column_text} {sql}"
|
|
4520
4558
|
|
|
@@ -4980,13 +5018,27 @@ class Generator:
|
|
|
4980
5018
|
|
|
4981
5019
|
then_expression = expression.args.get("then")
|
|
4982
5020
|
if isinstance(then_expression, exp.Insert):
|
|
4983
|
-
this =
|
|
5021
|
+
this = (
|
|
5022
|
+
"ALL BY NAME"
|
|
5023
|
+
if self.MERGE_ALL_BY_NAME and isinstance(then_expression.this, exp.Star)
|
|
5024
|
+
else self.sql(then_expression, "this")
|
|
5025
|
+
)
|
|
4984
5026
|
this = f"INSERT {this}" if this else "INSERT"
|
|
4985
5027
|
then = self.sql(then_expression, "expression")
|
|
4986
5028
|
then = f"{this} VALUES {then}" if then else this
|
|
4987
5029
|
elif isinstance(then_expression, exp.Update):
|
|
4988
5030
|
if isinstance(then_expression.args.get("expressions"), exp.Star):
|
|
4989
|
-
then =
|
|
5031
|
+
then = (
|
|
5032
|
+
"UPDATE ALL BY NAME"
|
|
5033
|
+
if self.MERGE_ALL_BY_NAME
|
|
5034
|
+
else f"UPDATE {self.sql(then_expression, 'expressions')}"
|
|
5035
|
+
)
|
|
5036
|
+
elif (
|
|
5037
|
+
self.MERGE_ALL_BY_NAME
|
|
5038
|
+
and len(then_expression.expressions) == 1
|
|
5039
|
+
and isinstance(then_expression.expressions[0], exp.Star)
|
|
5040
|
+
):
|
|
5041
|
+
then = "UPDATE ALL BY NAME"
|
|
4990
5042
|
else:
|
|
4991
5043
|
expressions_sql = self.expressions(then_expression)
|
|
4992
5044
|
then = f"UPDATE SET{self.sep()}{expressions_sql}" if expressions_sql else "UPDATE"
|
|
@@ -5947,7 +5999,8 @@ class Generator:
|
|
|
5947
5999
|
|
|
5948
6000
|
def slice_sql(self, expression: exp.Slice) -> str:
|
|
5949
6001
|
step = self.sql(expression, "step")
|
|
5950
|
-
end
|
|
6002
|
+
# An omitted end is written as `-` before a step, since `::` is the cast operator
|
|
6003
|
+
end = self.sql(expression.expression) or ("-" if step else "")
|
|
5951
6004
|
begin = self.sql(expression.this)
|
|
5952
6005
|
|
|
5953
6006
|
sql = f"{end}:{step}" if step else end
|
|
@@ -429,6 +429,7 @@ class BigQueryGenerator(generator.Generator):
|
|
|
429
429
|
exp.DateFromUnixDate: rename_func("DATE_FROM_UNIX_DATE"),
|
|
430
430
|
exp.Day: _extract_part("DAY"),
|
|
431
431
|
exp.DayOfMonth: _extract_part("DAY"),
|
|
432
|
+
exp.DayOfWeek: _extract_part("DAYOFWEEK"),
|
|
432
433
|
exp.DayOfWeekIso: _day_of_week_iso_sql,
|
|
433
434
|
exp.DayOfYear: _extract_part("DAYOFYEAR"),
|
|
434
435
|
exp.Filter: no_filter_sql,
|
|
@@ -24,6 +24,7 @@ from sqlglot.dialects.dialect import (
|
|
|
24
24
|
)
|
|
25
25
|
from sqlglot.generator import unsupported_args
|
|
26
26
|
from sqlglot.helper import is_int
|
|
27
|
+
from sqlglot.optimizer.simplify import simplify_parens
|
|
27
28
|
from collections import defaultdict
|
|
28
29
|
|
|
29
30
|
DATETIME_DELTA = t.Union[exp.DateAdd, exp.DateDiff, exp.DateSub, exp.TimestampSub, exp.TimestampAdd]
|
|
@@ -433,13 +434,12 @@ class ClickHouseGenerator(generator.Generator):
|
|
|
433
434
|
|
|
434
435
|
@unsupported_args("json_scope")
|
|
435
436
|
def contains_sql(self, expression: exp.Contains) -> str:
|
|
436
|
-
# ClickHouse has no CONTAINS; the
|
|
437
|
-
result = exp.
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
return self.sql(result)
|
|
437
|
+
# ClickHouse has no CONTAINS; keep the parentheses only where the parent needs them
|
|
438
|
+
result = exp.paren(
|
|
439
|
+
exp.StrPosition(this=expression.this, substr=expression.expression) > 0, copy=False
|
|
440
|
+
)
|
|
441
|
+
result.parent = expression.parent
|
|
442
|
+
return self.sql(simplify_parens(result, self.dialect))
|
|
443
443
|
|
|
444
444
|
def groupconcat_sql(self, expression: exp.GroupConcat) -> str:
|
|
445
445
|
this = expression.this
|
|
@@ -672,6 +672,15 @@ def _struct_sql(self: DuckDBGenerator, expression: exp.Struct) -> str:
|
|
|
672
672
|
return f"ROW({csv_args})" if is_bq_inline_struct else f"{{{csv_args}}}"
|
|
673
673
|
|
|
674
674
|
|
|
675
|
+
@unsupported_args("unique_keys", "return_type", "encoding", "strict")
|
|
676
|
+
def _json_constructor_sql(self: DuckDBGenerator, expression: exp.JSONArray | exp.JSONObject) -> str:
|
|
677
|
+
if expression.args.get("null_handling") == "ABSENT ON NULL":
|
|
678
|
+
self.unsupported("ABSENT ON NULL is not supported in DuckDB")
|
|
679
|
+
|
|
680
|
+
name = "JSON_ARRAY" if isinstance(expression, exp.JSONArray) else "JSON_OBJECT"
|
|
681
|
+
return self.func(name, *expression.expressions)
|
|
682
|
+
|
|
683
|
+
|
|
675
684
|
def _json_format_sql(self: DuckDBGenerator, expression: exp.JSONFormat) -> str:
|
|
676
685
|
sql = self.func("TO_JSON", expression.this, expression.args.get("options"))
|
|
677
686
|
return f"CAST({sql} AS TEXT)"
|
|
@@ -889,6 +898,19 @@ WRAPPED_JSON_EXTRACT_EXPRESSIONS = (exp.Binary, exp.Bracket, exp.In, exp.Not)
|
|
|
889
898
|
|
|
890
899
|
|
|
891
900
|
def _arrow_json_extract_sql(self: DuckDBGenerator, expression: JSON_EXTRACT_TYPE) -> str:
|
|
901
|
+
paths = expression.expressions
|
|
902
|
+
if isinstance(expression, exp.JSONExtract) and paths:
|
|
903
|
+
# JSON_EXTRACT with several paths (SQLite, MySQL) returns a JSON array of the results,
|
|
904
|
+
# which DuckDB builds from a list of paths
|
|
905
|
+
return self.func(
|
|
906
|
+
"TO_JSON",
|
|
907
|
+
self.func(
|
|
908
|
+
"JSON_EXTRACT",
|
|
909
|
+
expression.this,
|
|
910
|
+
exp.Array(expressions=[expression.expression, *paths]),
|
|
911
|
+
),
|
|
912
|
+
)
|
|
913
|
+
|
|
892
914
|
arrow_sql = arrow_json_extract_sql(self, expression)
|
|
893
915
|
if not expression.same_parent and isinstance(
|
|
894
916
|
expression.parent, WRAPPED_JSON_EXTRACT_EXPRESSIONS
|
|
@@ -1567,6 +1589,7 @@ class DuckDBGenerator(generator.Generator):
|
|
|
1567
1589
|
TABLE_HINTS = False
|
|
1568
1590
|
QUERY_HINTS = False
|
|
1569
1591
|
LIMIT_FETCH = "LIMIT"
|
|
1592
|
+
SUPPORTS_NEAREST_JOIN = True
|
|
1570
1593
|
STRUCT_DELIMITER = ("(", ")")
|
|
1571
1594
|
RENAME_TABLE_WITH_DB = False
|
|
1572
1595
|
NVL2_SUPPORTED = False
|
|
@@ -1794,7 +1817,7 @@ class DuckDBGenerator(generator.Generator):
|
|
|
1794
1817
|
exp.TsOrDsAdd: _date_delta_to_binary_interval_op(),
|
|
1795
1818
|
exp.TsOrDsDiff: lambda self, e: self.func(
|
|
1796
1819
|
"DATE_DIFF",
|
|
1797
|
-
|
|
1820
|
+
exp.Literal.string(e.unit or "DAY"),
|
|
1798
1821
|
exp.cast(e.expression, exp.DType.TIMESTAMP),
|
|
1799
1822
|
exp.cast(e.this, exp.DType.TIMESTAMP),
|
|
1800
1823
|
),
|
|
@@ -1824,6 +1847,8 @@ class DuckDBGenerator(generator.Generator):
|
|
|
1824
1847
|
),
|
|
1825
1848
|
exp.Xor: _xor_sql,
|
|
1826
1849
|
exp.JSONObjectAgg: rename_func("JSON_GROUP_OBJECT"),
|
|
1850
|
+
exp.JSONArray: _json_constructor_sql,
|
|
1851
|
+
exp.JSONObject: _json_constructor_sql,
|
|
1827
1852
|
exp.JSONBObjectAgg: rename_func("JSON_GROUP_OBJECT"),
|
|
1828
1853
|
exp.DateBin: rename_func("TIME_BUCKET"),
|
|
1829
1854
|
exp.LastDay: _last_day_sql,
|
|
@@ -1970,6 +1995,7 @@ class DuckDBGenerator(generator.Generator):
|
|
|
1970
1995
|
exp.TemporaryProperty: exp.Properties.Location.POST_CREATE,
|
|
1971
1996
|
exp.ReturnsProperty: exp.Properties.Location.POST_ALIAS,
|
|
1972
1997
|
exp.SequenceProperties: exp.Properties.Location.POST_EXPRESSION,
|
|
1998
|
+
exp.TriggerProperties: exp.Properties.Location.POST_EXPRESSION,
|
|
1973
1999
|
exp.IcebergProperty: exp.Properties.Location.POST_CREATE,
|
|
1974
2000
|
}
|
|
1975
2001
|
|
|
@@ -2387,6 +2413,27 @@ class DuckDBGenerator(generator.Generator):
|
|
|
2387
2413
|
|
|
2388
2414
|
return self.sql(add_expr)
|
|
2389
2415
|
|
|
2416
|
+
def unicodestring_sql(self, expression: exp.UnicodeString) -> str:
|
|
2417
|
+
# DuckDB has no Unicode escape strings and doesn't read \u in a string, so the escapes
|
|
2418
|
+
# are decoded into the characters, e.g. U&'d\0061t\0061' and U&'d!+000061ta' UESCAPE '!'
|
|
2419
|
+
# are both 'data'
|
|
2420
|
+
escape = expression.args.get("escape")
|
|
2421
|
+
escape_char = re.escape(escape.name if isinstance(escape, exp.Expr) else "\\")
|
|
2422
|
+
pattern = re.compile(
|
|
2423
|
+
rf"{escape_char}(?:\+([0-9a-fA-F]{{6}})|([0-9a-fA-F]{{4}})|({escape_char}))"
|
|
2424
|
+
)
|
|
2425
|
+
|
|
2426
|
+
def decode(match: re.Match[str]) -> str:
|
|
2427
|
+
if match.group(3):
|
|
2428
|
+
return match.group(3)
|
|
2429
|
+
return chr(int(match.group(1) or match.group(2), 16))
|
|
2430
|
+
|
|
2431
|
+
# A character outside the BMP can be written as a UTF-16 surrogate pair
|
|
2432
|
+
text = (
|
|
2433
|
+
pattern.sub(decode, expression.name).encode("utf-16", "surrogatepass").decode("utf-16")
|
|
2434
|
+
)
|
|
2435
|
+
return self.sql(exp.Literal.string(text))
|
|
2436
|
+
|
|
2390
2437
|
def bytestring_sql(self, expression: exp.ByteString) -> str:
|
|
2391
2438
|
if not expression.args.get("is_bytes"):
|
|
2392
2439
|
return super().bytestring_sql(expression)
|
|
@@ -2551,9 +2598,6 @@ class DuckDBGenerator(generator.Generator):
|
|
|
2551
2598
|
initial_value = expression.args.get("initial")
|
|
2552
2599
|
merge_lambda = expression.args.get("merge")
|
|
2553
2600
|
|
|
2554
|
-
if merge_lambda:
|
|
2555
|
-
merge_lambda.set("colon", True)
|
|
2556
|
-
|
|
2557
2601
|
return self.func("list_reduce", array_arg, merge_lambda, initial_value)
|
|
2558
2602
|
|
|
2559
2603
|
def zipf_sql(self, expression: exp.Zipf) -> str:
|
|
@@ -2678,7 +2722,7 @@ class DuckDBGenerator(generator.Generator):
|
|
|
2678
2722
|
return self._greatest_least_sql(expression)
|
|
2679
2723
|
|
|
2680
2724
|
def lambda_sql(self, expression: exp.Lambda, arrow_sep: str = "->", wrap: bool = True) -> str:
|
|
2681
|
-
if
|
|
2725
|
+
if self.dialect.version >= (1, 3):
|
|
2682
2726
|
prefix = "LAMBDA "
|
|
2683
2727
|
arrow_sep = ":"
|
|
2684
2728
|
wrap = False
|
|
@@ -2697,6 +2741,11 @@ class DuckDBGenerator(generator.Generator):
|
|
|
2697
2741
|
self.unsupported("SOUNDEX is not supported in DuckDB")
|
|
2698
2742
|
return self.func("SOUNDEX", expression.this)
|
|
2699
2743
|
|
|
2744
|
+
def placeholder_sql(self, expression: exp.Placeholder) -> str:
|
|
2745
|
+
if isinstance(expression.this, exp.Identifier):
|
|
2746
|
+
return f"${self.sql(expression, 'this')}"
|
|
2747
|
+
return super().placeholder_sql(expression)
|
|
2748
|
+
|
|
2700
2749
|
def install_sql(self, expression: exp.Install) -> str:
|
|
2701
2750
|
force = "FORCE " if expression.args.get("force") else ""
|
|
2702
2751
|
this = self.sql(expression, "this")
|
|
@@ -3163,10 +3212,26 @@ class DuckDBGenerator(generator.Generator):
|
|
|
3163
3212
|
)
|
|
3164
3213
|
return super().in_sql(expression)
|
|
3165
3214
|
|
|
3166
|
-
def
|
|
3215
|
+
def interval_sql(self, expression: exp.Interval) -> str:
|
|
3216
|
+
# DuckDB truncates INTERVAL '1.5' DAY to 1 day, but keeps the fraction in INTERVAL '1.5 DAY'
|
|
3217
|
+
this = expression.this
|
|
3218
|
+
unit = expression.unit
|
|
3219
|
+
if expression.args.get("fraction_in_string") and this and isinstance(unit, exp.Var):
|
|
3220
|
+
return f"INTERVAL '{this.name} {self.sql(unit)}'"
|
|
3221
|
+
|
|
3222
|
+
return super().interval_sql(expression)
|
|
3223
|
+
|
|
3224
|
+
def join_sql(self, expression: exp.Join, join_op: str | None = None) -> str:
|
|
3225
|
+
if expression.kind in ("MARK", "SINGLE") or (
|
|
3226
|
+
expression.side == "RIGHT" and expression.is_semi_or_anti_join
|
|
3227
|
+
):
|
|
3228
|
+
kind = "_".join(part for part in (expression.side, expression.kind) if part)
|
|
3229
|
+
return super().join_sql(expression, join_op=f"JOIN BY (TYPE {kind})")
|
|
3230
|
+
|
|
3167
3231
|
if (
|
|
3168
3232
|
not expression.args.get("using")
|
|
3169
3233
|
and not expression.args.get("on")
|
|
3234
|
+
and not expression.args.get("nearest")
|
|
3170
3235
|
and not expression.method
|
|
3171
3236
|
and (expression.kind in ("", "INNER", "OUTER"))
|
|
3172
3237
|
):
|
|
@@ -3178,7 +3243,7 @@ class DuckDBGenerator(generator.Generator):
|
|
|
3178
3243
|
expression.set("side", None)
|
|
3179
3244
|
expression.set("kind", None)
|
|
3180
3245
|
|
|
3181
|
-
return super().join_sql(expression)
|
|
3246
|
+
return super().join_sql(expression, join_op=join_op)
|
|
3182
3247
|
|
|
3183
3248
|
def countif_sql(self, expression: exp.CountIf) -> str:
|
|
3184
3249
|
if self.dialect.version >= (1, 2):
|
|
@@ -100,12 +100,9 @@ def _trunc_sql(
|
|
|
100
100
|
node = expression.this.this if isinstance(expression.this, exp.Cast) else expression.this
|
|
101
101
|
expr_sql = self.sql(node)
|
|
102
102
|
if isinstance(node, exp.Literal) and node.is_string:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
else f"DATE '{node.this}'"
|
|
107
|
-
)
|
|
108
|
-
return f"DATE_TRUNC('{unit}', {expr_sql})"
|
|
103
|
+
text = node.this.replace("T", " ") if kind == "TIMESTAMP" else node.this
|
|
104
|
+
expr_sql = f"{kind} {self.sql(exp.Literal.string(text))}"
|
|
105
|
+
return f"DATE_TRUNC({self.sql(exp.Literal.string(unit))}, {expr_sql})"
|
|
109
106
|
|
|
110
107
|
|
|
111
108
|
def _date_trunc_sql(self: ExasolGenerator, expression: exp.DateTrunc) -> str:
|
|
@@ -246,6 +246,7 @@ class HiveGenerator(generator.Generator):
|
|
|
246
246
|
PARSE_JSON_NAME: str | None = "PARSE_JSON"
|
|
247
247
|
PAD_FILL_PATTERN_IS_REQUIRED = True
|
|
248
248
|
SUPPORTS_MEDIAN = False
|
|
249
|
+
SUPPORTS_TEMPORAL_PRECISION = False
|
|
249
250
|
ARRAY_SIZE_NAME = "SIZE"
|
|
250
251
|
ALTER_SET_TYPE = ""
|
|
251
252
|
|
|
@@ -506,7 +507,9 @@ class HiveGenerator(generator.Generator):
|
|
|
506
507
|
expression.set("expressions", None)
|
|
507
508
|
elif expression.is_type(exp.DType.TEXT) and expression.expressions:
|
|
508
509
|
expression.set("this", exp.DType.VARCHAR)
|
|
509
|
-
elif
|
|
510
|
+
elif (
|
|
511
|
+
not self.SUPPORTS_TEMPORAL_PRECISION and expression.this in exp.DataType.TEMPORAL_TYPES
|
|
512
|
+
):
|
|
510
513
|
expression.set("expressions", None)
|
|
511
514
|
elif expression.is_type("float"):
|
|
512
515
|
size_expression = expression.find(exp.DataTypeParam)
|
|
@@ -145,9 +145,6 @@ class OracleGenerator(generator.Generator):
|
|
|
145
145
|
def offset_sql(self, expression: exp.Offset) -> str:
|
|
146
146
|
return f"{super().offset_sql(expression)} ROWS"
|
|
147
147
|
|
|
148
|
-
def add_column_sql(self, expression: exp.Expr) -> str:
|
|
149
|
-
return f"ADD {self.sql(expression)}"
|
|
150
|
-
|
|
151
148
|
def queryoption_sql(self, expression: exp.QueryOption) -> str:
|
|
152
149
|
option = self.sql(expression, "this")
|
|
153
150
|
value = self.sql(expression, "expression")
|