sqlglotc 30.23.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.23.0/sqlglotc.egg-info → sqlglotc-30.25.0}/PKG-INFO +2 -2
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/pyproject.toml +1 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/setup.py +17 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/array.py +5 -5
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/builders.py +1 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/constraints.py +2 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/core.py +7 -8
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/datatypes.py +3 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/ddl.py +8 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/query.py +16 -3
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generator.py +104 -21
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/bigquery.py +143 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/clickhouse.py +9 -8
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/databricks.py +1 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/duckdb.py +107 -46
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/exasol.py +3 -6
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/fabric.py +5 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/hive.py +8 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/mysql.py +3 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/oracle.py +0 -3
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/postgres.py +43 -5
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/presto.py +21 -9
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/python.py +5 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/snowflake.py +18 -7
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/spark2.py +22 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/sqlite.py +6 -2
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/starrocks.py +35 -4
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/teradata.py +11 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/tsql.py +4 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/helper.py +17 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/optimizer/annotate_types.py +171 -106
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/optimizer/canonicalize_internal_names.py +11 -10
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/optimizer/qualify_columns.py +98 -138
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/optimizer/resolver.py +57 -8
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/optimizer/scope.py +24 -9
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/optimizer/simplify.py +28 -6
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parser.py +186 -44
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/clickhouse.py +11 -5
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/doris.py +3 -3
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/dremio.py +3 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/drill.py +3 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/duckdb.py +115 -10
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/hive.py +13 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/mysql.py +71 -3
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/oracle.py +16 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/postgres.py +36 -6
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/presto.py +2 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/prql.py +2 -8
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/redshift.py +3 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/singlestore.py +3 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/snowflake.py +4 -4
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/spark2.py +4 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/sqlite.py +46 -2
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/starrocks.py +73 -10
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/teradata.py +15 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/trino.py +6 -1
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/tokenizer_core.py +3 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0/sqlglotc.egg-info}/PKG-INFO +2 -2
- {sqlglotc-30.23.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.23.0/sqlglotc.egg-info/scm_version.json +0 -8
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/MANIFEST.in +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/setup.cfg +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/anonymize.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/errors.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/executor/table.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/aggregate.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/dml.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/functions.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/json.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/math.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/properties.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/string.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/expressions/temporal.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/athena.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/dax.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/doris.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/dremio.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/drill.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/druid.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/dune.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/materialize.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/prql.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/redshift.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/risingwave.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/singlestore.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/solr.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/spark.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/tableau.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/generators/trino.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/lineage.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/optimizer/qualify.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/optimizer/qualify_tables.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/athena.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/base.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/bigquery.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/databricks.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/dax.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/druid.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/dune.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/exasol.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/fabric.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/materialize.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/risingwave.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/solr.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/spark.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/tableau.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/parsers/tsql.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/serde.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/time.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglot/trie.py +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglotc.egg-info/SOURCES.txt +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglotc.egg-info/dependency_links.txt +0 -0
- {sqlglotc-30.23.0 → sqlglotc-30.25.0}/sqlglotc.egg-info/scm_file_list.json +0 -0
- {sqlglotc-30.23.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"
|
|
@@ -90,6 +90,16 @@ def _source_paths():
|
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
class build_ext(_build_ext):
|
|
93
|
+
def _remove_obsolete_extensions(self, directory, expected):
|
|
94
|
+
if self.dry_run:
|
|
95
|
+
return
|
|
96
|
+
expected = {os.path.abspath(path) for path in expected}
|
|
97
|
+
for root, _, files in os.walk(directory):
|
|
98
|
+
for filename in files:
|
|
99
|
+
path = os.path.join(root, filename)
|
|
100
|
+
if filename.endswith((".so", ".pyd")) and os.path.abspath(path) not in expected:
|
|
101
|
+
self.execute(os.remove, (path,), f"removing obsolete extension {path}")
|
|
102
|
+
|
|
93
103
|
def finalize_options(self):
|
|
94
104
|
super().finalize_options()
|
|
95
105
|
# Compile in parallel by default; builds driven by pip (wheel/sdist installs)
|
|
@@ -97,8 +107,13 @@ class build_ext(_build_ext):
|
|
|
97
107
|
if self.parallel is None:
|
|
98
108
|
self.parallel = os.cpu_count() or 1
|
|
99
109
|
|
|
110
|
+
def build_extensions(self):
|
|
111
|
+
self._remove_obsolete_extensions(self.build_lib, self.get_outputs())
|
|
112
|
+
super().build_extensions()
|
|
113
|
+
|
|
100
114
|
def copy_extensions_to_source(self):
|
|
101
115
|
"""For editable installs, put sqlglot.* .so files in the sqlglot source dir."""
|
|
116
|
+
expected = []
|
|
102
117
|
for ext in self.extensions:
|
|
103
118
|
fullname = self.get_ext_fullname(ext.name)
|
|
104
119
|
filename = self.get_ext_filename(fullname)
|
|
@@ -112,7 +127,9 @@ class build_ext(_build_ext):
|
|
|
112
127
|
# Place the mypyc runtime helper (e.g., HASH__mypyc) inside sqlglot/.
|
|
113
128
|
# sqlglot/__init__.py bootstraps it into sys.modules for editable installs.
|
|
114
129
|
dst = os.path.join(SQLGLOT_SRC, os.path.basename(filename))
|
|
130
|
+
expected.append(dst)
|
|
115
131
|
self.copy_file(src, dst, level=self.verbose)
|
|
132
|
+
self._remove_obsolete_extensions(SQLGLOT_SRC, expected)
|
|
116
133
|
|
|
117
134
|
|
|
118
135
|
class sdist(_sdist):
|
|
@@ -98,17 +98,13 @@ class ArraySlice(Expression, Func):
|
|
|
98
98
|
|
|
99
99
|
|
|
100
100
|
class ArraySort(Expression, Func):
|
|
101
|
-
arg_types = {"this": True, "expression": False}
|
|
101
|
+
arg_types = {"this": True, "expression": False, "asc": False, "nulls_first": False}
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
class Shuffle(Expression, Func):
|
|
105
105
|
pass
|
|
106
106
|
|
|
107
107
|
|
|
108
|
-
class SortArray(Expression, Func):
|
|
109
|
-
arg_types = {"this": True, "asc": False, "nulls_first": False}
|
|
110
|
-
|
|
111
|
-
|
|
112
108
|
# Array predicates / search
|
|
113
109
|
|
|
114
110
|
|
|
@@ -258,6 +254,10 @@ class SplitToTable(Expression, Func, UDTF):
|
|
|
258
254
|
arg_types = {"this": True, "expression": True}
|
|
259
255
|
|
|
260
256
|
|
|
257
|
+
class StrtokSplitToTable(Expression, Func, UDTF):
|
|
258
|
+
arg_types = {"this": True, "expression": False}
|
|
259
|
+
|
|
260
|
+
|
|
261
261
|
class Stack(Expression, Func, UDTF):
|
|
262
262
|
arg_types = {"this": True, "expressions": True}
|
|
263
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,
|
|
@@ -1938,6 +1943,10 @@ class WindowSpec(Expression):
|
|
|
1938
1943
|
}
|
|
1939
1944
|
|
|
1940
1945
|
|
|
1946
|
+
class PartitionByExcluding(Expression):
|
|
1947
|
+
arg_types = {"expressions": True}
|
|
1948
|
+
|
|
1949
|
+
|
|
1941
1950
|
class PreWhere(Expression):
|
|
1942
1951
|
pass
|
|
1943
1952
|
|
|
@@ -2020,6 +2029,10 @@ class DropPartition(Expression):
|
|
|
2020
2029
|
arg_types = {"expressions": True, "exists": False}
|
|
2021
2030
|
|
|
2022
2031
|
|
|
2032
|
+
class ReplaceColumns(Expression):
|
|
2033
|
+
arg_types = {"expressions": True}
|
|
2034
|
+
|
|
2035
|
+
|
|
2023
2036
|
class ReplacePartition(Expression):
|
|
2024
2037
|
arg_types = {"expression": True, "source": True}
|
|
2025
2038
|
|
|
@@ -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__
|
|
@@ -2178,6 +2191,7 @@ class Generator:
|
|
|
2178
2191
|
property_name = exp.Properties.PROPERTY_TO_NAME.get(property_cls)
|
|
2179
2192
|
if not property_name:
|
|
2180
2193
|
self.unsupported(f"Unsupported property {expression.key}")
|
|
2194
|
+
return ""
|
|
2181
2195
|
|
|
2182
2196
|
return f"{property_name}={self.sql(expression, 'this')}"
|
|
2183
2197
|
|
|
@@ -2319,6 +2333,10 @@ class Generator:
|
|
|
2319
2333
|
override = " OVERRIDE" if expression.args.get("override") else ""
|
|
2320
2334
|
return f"LOCKING {kind}{this}{for_or_in} {lock_type}{override}"
|
|
2321
2335
|
|
|
2336
|
+
def lockingstatement_sql(self, expression: exp.LockingStatement) -> str:
|
|
2337
|
+
self.unsupported("LOCKING request modifier is not supported")
|
|
2338
|
+
return self.sql(expression, "expression")
|
|
2339
|
+
|
|
2322
2340
|
def withdataproperty_sql(self, expression: exp.WithDataProperty) -> str:
|
|
2323
2341
|
data_sql = f"WITH {'NO ' if expression.args.get('no') else ''}DATA"
|
|
2324
2342
|
statistics = expression.args.get("statistics")
|
|
@@ -2561,6 +2579,10 @@ class Generator:
|
|
|
2561
2579
|
expression: exp.TableSample,
|
|
2562
2580
|
tablesample_keyword: str | None = None,
|
|
2563
2581
|
) -> str:
|
|
2582
|
+
if expression.expressions:
|
|
2583
|
+
self.unsupported("Multiple sample sets are not supported")
|
|
2584
|
+
return ""
|
|
2585
|
+
|
|
2564
2586
|
method = self.sql(expression, "method")
|
|
2565
2587
|
method = f"{method} " if method and self.TABLESAMPLE_WITH_METHOD else ""
|
|
2566
2588
|
numerator = self.sql(expression, "bucket_numerator")
|
|
@@ -2902,6 +2924,12 @@ class Generator:
|
|
|
2902
2924
|
this = self.indent(self.sql(expression, "this"))
|
|
2903
2925
|
return f"{self.seg('HAVING')}{self.sep()}{this}"
|
|
2904
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
|
+
|
|
2905
2933
|
def connect_sql(self, expression: exp.Connect) -> str:
|
|
2906
2934
|
start = self.sql(expression, "start")
|
|
2907
2935
|
start = self.seg(f"START WITH {start}") if start else ""
|
|
@@ -2913,7 +2941,7 @@ class Generator:
|
|
|
2913
2941
|
def prior_sql(self, expression: exp.Prior) -> str:
|
|
2914
2942
|
return f"PRIOR {self.sql(expression, 'this')}"
|
|
2915
2943
|
|
|
2916
|
-
def join_sql(self, expression: exp.Join) -> str:
|
|
2944
|
+
def join_sql(self, expression: exp.Join, join_op: str | None = None) -> str:
|
|
2917
2945
|
if not self.SEMI_ANTI_JOIN_WITH_SIDE and expression.kind in ("SEMI", "ANTI"):
|
|
2918
2946
|
side = None
|
|
2919
2947
|
else:
|
|
@@ -2933,6 +2961,8 @@ class Generator:
|
|
|
2933
2961
|
)
|
|
2934
2962
|
match_cond = self.sql(expression, "match_condition")
|
|
2935
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 ""
|
|
2936
2966
|
on_sql = self.sql(expression, "on")
|
|
2937
2967
|
using = expression.args.get("using")
|
|
2938
2968
|
|
|
@@ -2953,17 +2983,27 @@ class Generator:
|
|
|
2953
2983
|
on_sql = f"{space}USING ({on_sql})"
|
|
2954
2984
|
else:
|
|
2955
2985
|
on_sql = f"{space}ON {on_sql}"
|
|
2956
|
-
elif not op_sql:
|
|
2986
|
+
elif not op_sql and not nearest:
|
|
2957
2987
|
if isinstance(this, exp.Lateral) and this.args.get("cross_apply") is not None:
|
|
2958
2988
|
return f" {this_sql}"
|
|
2959
2989
|
|
|
2960
2990
|
return f", {this_sql}"
|
|
2961
2991
|
|
|
2962
|
-
if
|
|
2992
|
+
if join_op:
|
|
2993
|
+
op_sql = join_op
|
|
2994
|
+
elif op_sql != "STRAIGHT_JOIN":
|
|
2963
2995
|
op_sql = f"{op_sql} JOIN" if op_sql else "JOIN"
|
|
2964
2996
|
|
|
2965
2997
|
pivots = self.expressions(expression, key="pivots", sep="", flat=True)
|
|
2966
|
-
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')}"
|
|
2967
3007
|
|
|
2968
3008
|
def lambda_sql(self, expression: exp.Lambda, arrow_sep: str = "->", wrap: bool = True) -> str:
|
|
2969
3009
|
args = self.expressions(expression, flat=True)
|
|
@@ -3627,6 +3667,9 @@ class Generator:
|
|
|
3627
3667
|
first = "FIRST" if first else "LAST"
|
|
3628
3668
|
|
|
3629
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})"
|
|
3630
3673
|
return f"{this} {alias}"
|
|
3631
3674
|
|
|
3632
3675
|
args = self.format_args(
|
|
@@ -3638,6 +3681,9 @@ class Generator:
|
|
|
3638
3681
|
partition = self.expressions(expression, key="partition_by", flat=True)
|
|
3639
3682
|
return f"PARTITION BY {partition}" if partition else ""
|
|
3640
3683
|
|
|
3684
|
+
def partitionbyexcluding_sql(self, expression: exp.PartitionByExcluding) -> str:
|
|
3685
|
+
return f"EXCLUDING {self.expressions(expression, flat=True)}"
|
|
3686
|
+
|
|
3641
3687
|
def windowspec_sql(self, expression: exp.WindowSpec) -> str:
|
|
3642
3688
|
kind = self.sql(expression, "kind")
|
|
3643
3689
|
start = csv(self.sql(expression, "start"), self.sql(expression, "start_side"), sep=" ")
|
|
@@ -4073,8 +4119,8 @@ class Generator:
|
|
|
4073
4119
|
if this:
|
|
4074
4120
|
interval_keyword = f"{interval_keyword} " if interval_keyword else ""
|
|
4075
4121
|
if unit_expression and isinstance(unit_expression, exp.IntervalSpan):
|
|
4076
|
-
return f"{interval_keyword}
|
|
4077
|
-
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}'))}"
|
|
4078
4124
|
return f"{interval_keyword}{unit}"
|
|
4079
4125
|
|
|
4080
4126
|
this = self.sql(expression, "this")
|
|
@@ -4496,13 +4542,17 @@ class Generator:
|
|
|
4496
4542
|
return f"{keyword} {items_sql}"
|
|
4497
4543
|
|
|
4498
4544
|
def add_column_sql(self, expression: exp.Expr) -> str:
|
|
4499
|
-
|
|
4500
|
-
if
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
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)
|
|
4504
4554
|
else:
|
|
4505
|
-
|
|
4555
|
+
sql = self.sql(expression)
|
|
4506
4556
|
|
|
4507
4557
|
return f"ADD{column_text} {sql}"
|
|
4508
4558
|
|
|
@@ -4517,6 +4567,9 @@ class Generator:
|
|
|
4517
4567
|
def addconstraint_sql(self, expression: exp.AddConstraint) -> str:
|
|
4518
4568
|
return f"ADD {self.expressions(expression, indent=False)}"
|
|
4519
4569
|
|
|
4570
|
+
def replacecolumns_sql(self, expression: exp.ReplaceColumns) -> str:
|
|
4571
|
+
return f"REPLACE COLUMNS ({self.expressions(expression, flat=True)})"
|
|
4572
|
+
|
|
4520
4573
|
def addpartition_sql(self, expression: exp.AddPartition) -> str:
|
|
4521
4574
|
exists = "IF NOT EXISTS " if expression.args.get("exists") else ""
|
|
4522
4575
|
location = self.sql(expression, "location")
|
|
@@ -4771,14 +4824,22 @@ class Generator:
|
|
|
4771
4824
|
sqls: list[str] = []
|
|
4772
4825
|
stack: list[None | str | exp.Expr] = [expression]
|
|
4773
4826
|
binary_type = type(expression)
|
|
4827
|
+
is_is = binary_type is exp.Is and op in ("IS", "IS NOT")
|
|
4828
|
+
negate = expression.args.get("negate")
|
|
4774
4829
|
|
|
4775
4830
|
while stack:
|
|
4776
4831
|
node = stack.pop()
|
|
4777
4832
|
|
|
4778
|
-
if type(node) is binary_type
|
|
4833
|
+
if type(node) is binary_type and (
|
|
4834
|
+
node is expression
|
|
4835
|
+
or (is_is and not isinstance(node.expression, exp.Boolean))
|
|
4836
|
+
or node.args.get("negate") == negate
|
|
4837
|
+
):
|
|
4779
4838
|
op_func = node.args.get("operator")
|
|
4780
4839
|
if op_func:
|
|
4781
4840
|
op = f"OPERATOR({self.sql(op_func)})"
|
|
4841
|
+
elif is_is:
|
|
4842
|
+
op = "IS NOT" if node.args.get("negate") else "IS"
|
|
4782
4843
|
|
|
4783
4844
|
stack.append(node.args.get("expression"))
|
|
4784
4845
|
stack.append(f" {self.maybe_comment(op, comments=node.comments)} ")
|
|
@@ -4957,13 +5018,27 @@ class Generator:
|
|
|
4957
5018
|
|
|
4958
5019
|
then_expression = expression.args.get("then")
|
|
4959
5020
|
if isinstance(then_expression, exp.Insert):
|
|
4960
|
-
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
|
+
)
|
|
4961
5026
|
this = f"INSERT {this}" if this else "INSERT"
|
|
4962
5027
|
then = self.sql(then_expression, "expression")
|
|
4963
5028
|
then = f"{this} VALUES {then}" if then else this
|
|
4964
5029
|
elif isinstance(then_expression, exp.Update):
|
|
4965
5030
|
if isinstance(then_expression.args.get("expressions"), exp.Star):
|
|
4966
|
-
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"
|
|
4967
5042
|
else:
|
|
4968
5043
|
expressions_sql = self.expressions(then_expression)
|
|
4969
5044
|
then = f"UPDATE SET{self.sep()}{expressions_sql}" if expressions_sql else "UPDATE"
|
|
@@ -5924,7 +5999,8 @@ class Generator:
|
|
|
5924
5999
|
|
|
5925
6000
|
def slice_sql(self, expression: exp.Slice) -> str:
|
|
5926
6001
|
step = self.sql(expression, "step")
|
|
5927
|
-
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 "")
|
|
5928
6004
|
begin = self.sql(expression.this)
|
|
5929
6005
|
|
|
5930
6006
|
sql = f"{end}:{step}" if step else end
|
|
@@ -6053,6 +6129,13 @@ class Generator:
|
|
|
6053
6129
|
exp.TimestampDiff(this=expression.this, expression=start_ts, unit=exp.var("SECONDS"))
|
|
6054
6130
|
)
|
|
6055
6131
|
|
|
6132
|
+
def arraysort_sql(self, expression: exp.ArraySort) -> str:
|
|
6133
|
+
asc = expression.args.get("asc")
|
|
6134
|
+
nulls_first = expression.args.get("nulls_first")
|
|
6135
|
+
if (asc and asc != exp.true()) or (nulls_first and nulls_first != exp.false()):
|
|
6136
|
+
self.unsupported("ARRAY_SORT only sorts ascending with NULLs last")
|
|
6137
|
+
return self.func("ARRAY_SORT", expression.this, expression.expression)
|
|
6138
|
+
|
|
6056
6139
|
def arraysize_sql(self, expression: exp.ArraySize) -> str:
|
|
6057
6140
|
dim = expression.expression
|
|
6058
6141
|
|