sqlglotc 30.15.0__tar.gz → 30.17.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.15.0/sqlglotc.egg-info → sqlglotc-30.17.0}/PKG-INFO +3 -3
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/pyproject.toml +2 -2
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/errors.py +15 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/array.py +6 -4
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/core.py +30 -15
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/ddl.py +1 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/json.py +4 -3
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/query.py +26 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/string.py +3 -3
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generator.py +77 -14
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/bigquery.py +1 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/clickhouse.py +3 -2
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/doris.py +5 -2
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/duckdb.py +24 -22
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/hive.py +7 -3
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/mysql.py +11 -6
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/postgres.py +8 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/python.py +14 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/singlestore.py +2 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/snowflake.py +1 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/spark2.py +5 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/sqlite.py +23 -2
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/starrocks.py +3 -2
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/trino.py +60 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/tsql.py +1 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/lineage.py +78 -33
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/optimizer/annotate_types.py +21 -6
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/optimizer/canonicalize_internal_names.py +6 -4
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/optimizer/qualify_columns.py +41 -15
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/optimizer/qualify_tables.py +23 -2
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/optimizer/scope.py +64 -5
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/optimizer/simplify.py +19 -5
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parser.py +121 -25
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/clickhouse.py +26 -17
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/duckdb.py +11 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/mysql.py +1 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/postgres.py +16 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/prql.py +2 -2
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/snowflake.py +11 -4
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/spark2.py +5 -0
- sqlglotc-30.17.0/sqlglot/parsers/sqlite.py +204 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/teradata.py +1 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/trino.py +118 -9
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/tsql.py +8 -2
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/tokenizer_core.py +1 -1
- {sqlglotc-30.15.0 → sqlglotc-30.17.0/sqlglotc.egg-info}/PKG-INFO +3 -3
- sqlglotc-30.17.0/sqlglotc.egg-info/requires.txt +6 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglotc.egg-info/scm_file_list.json +2 -2
- sqlglotc-30.17.0/sqlglotc.egg-info/scm_version.json +8 -0
- sqlglotc-30.15.0/sqlglot/parsers/sqlite.py +0 -101
- sqlglotc-30.15.0/sqlglotc.egg-info/requires.txt +0 -6
- sqlglotc-30.15.0/sqlglotc.egg-info/scm_version.json +0 -8
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/MANIFEST.in +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/setup.cfg +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/setup.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/anonymize.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/executor/table.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/aggregate.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/builders.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/constraints.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/datatypes.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/dml.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/functions.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/math.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/properties.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/expressions/temporal.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/athena.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/databricks.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/dax.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/dremio.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/drill.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/druid.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/dune.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/exasol.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/fabric.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/materialize.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/oracle.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/presto.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/prql.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/redshift.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/risingwave.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/solr.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/spark.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/tableau.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/generators/teradata.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/helper.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/optimizer/qualify.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/optimizer/resolver.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/athena.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/base.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/bigquery.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/databricks.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/dax.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/doris.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/dremio.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/drill.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/druid.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/dune.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/exasol.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/fabric.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/hive.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/materialize.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/oracle.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/presto.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/redshift.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/risingwave.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/singlestore.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/solr.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/spark.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/starrocks.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/parsers/tableau.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/schema.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/serde.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/time.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglot/trie.py +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglotc.egg-info/SOURCES.txt +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglotc.egg-info/dependency_links.txt +0 -0
- {sqlglotc-30.15.0 → sqlglotc-30.17.0}/sqlglotc.egg-info/top_level.txt +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlglotc
|
|
3
|
-
Version: 30.
|
|
3
|
+
Version: 30.17.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.17.0
|
|
11
11
|
Provides-Extra: dev
|
|
12
12
|
Requires-Dist: setuptools>=61.0; extra == "dev"
|
|
13
13
|
Requires-Dist: setuptools_scm; extra == "dev"
|
|
14
|
-
Requires-Dist: sqlglot-mypy>=2.
|
|
14
|
+
Requires-Dist: sqlglot-mypy>=2.3.0.post1; extra == "dev"
|
|
15
15
|
Dynamic: requires-dist
|
|
@@ -7,7 +7,7 @@ license = "MIT"
|
|
|
7
7
|
requires-python = ">= 3.10"
|
|
8
8
|
|
|
9
9
|
[project.optional-dependencies]
|
|
10
|
-
dev = ["setuptools >= 61.0", "setuptools_scm", "sqlglot-mypy >= 2.
|
|
10
|
+
dev = ["setuptools >= 61.0", "setuptools_scm", "sqlglot-mypy >= 2.3.0.post1"]
|
|
11
11
|
|
|
12
12
|
[project.urls]
|
|
13
13
|
Homepage = "https://sqlglot.com/"
|
|
@@ -17,7 +17,7 @@ Repository = "https://github.com/tobymao/sqlglot"
|
|
|
17
17
|
requires = [
|
|
18
18
|
"setuptools >= 61.0",
|
|
19
19
|
"setuptools_scm",
|
|
20
|
-
"sqlglot-mypy >= 2.
|
|
20
|
+
"sqlglot-mypy >= 2.3.0.post1",
|
|
21
21
|
"types-python-dateutil",
|
|
22
22
|
"sqlglot",
|
|
23
23
|
]
|
|
@@ -72,7 +72,21 @@ class ParseError(SqlglotError):
|
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
class TokenError(SqlglotError):
|
|
75
|
-
|
|
75
|
+
"""Error raised when tokenizing fails.
|
|
76
|
+
|
|
77
|
+
When available, `start` and `end` are the offsets in the source SQL of the context
|
|
78
|
+
snippet quoted in the message, i.e. the snippet is `sql[start:end]`.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __init__(
|
|
82
|
+
self,
|
|
83
|
+
message: str,
|
|
84
|
+
start: int | None = None,
|
|
85
|
+
end: int | None = None,
|
|
86
|
+
):
|
|
87
|
+
super().__init__(message)
|
|
88
|
+
self.start = start
|
|
89
|
+
self.end = end
|
|
76
90
|
|
|
77
91
|
|
|
78
92
|
class OptimizeError(SqlglotError):
|
|
@@ -8,6 +8,7 @@ from sqlglot.expressions.core import (
|
|
|
8
8
|
Expr,
|
|
9
9
|
Func,
|
|
10
10
|
Binary,
|
|
11
|
+
Predicate,
|
|
11
12
|
to_identifier,
|
|
12
13
|
)
|
|
13
14
|
from sqlglot.helper import trait
|
|
@@ -109,16 +110,16 @@ class ArrayAny(Expression, Func):
|
|
|
109
110
|
arg_types = {"this": True, "expression": True}
|
|
110
111
|
|
|
111
112
|
|
|
112
|
-
class ArrayContains(Expression, Binary, Func):
|
|
113
|
+
class ArrayContains(Expression, Binary, Predicate, Func):
|
|
113
114
|
arg_types = {"this": True, "expression": True, "ensure_variant": False, "check_null": False}
|
|
114
115
|
_sql_names = ["ARRAY_CONTAINS", "ARRAY_HAS"]
|
|
115
116
|
|
|
116
117
|
|
|
117
|
-
class ArrayContainsAll(Expression, Binary, Func):
|
|
118
|
+
class ArrayContainsAll(Expression, Binary, Predicate, Func):
|
|
118
119
|
_sql_names = ["ARRAY_CONTAINS_ALL", "ARRAY_HAS_ALL"]
|
|
119
120
|
|
|
120
121
|
|
|
121
|
-
class ArrayContainedBy(Expression, Binary, Func):
|
|
122
|
+
class ArrayContainedBy(Expression, Binary, Predicate, Func):
|
|
122
123
|
pass
|
|
123
124
|
|
|
124
125
|
|
|
@@ -132,7 +133,7 @@ class ArrayIntersect(Expression, Func):
|
|
|
132
133
|
_sql_names = ["ARRAY_INTERSECT", "ARRAY_INTERSECTION"]
|
|
133
134
|
|
|
134
135
|
|
|
135
|
-
class ArrayOverlaps(Expression, Binary, Func):
|
|
136
|
+
class ArrayOverlaps(Expression, Binary, Predicate, Func):
|
|
136
137
|
arg_types = {"this": True, "expression": True, "null_safe": False}
|
|
137
138
|
|
|
138
139
|
|
|
@@ -343,6 +344,7 @@ class ToMap(Expression, Func):
|
|
|
343
344
|
class VarMap(Expression, Func):
|
|
344
345
|
arg_types = {"keys": True, "values": True}
|
|
345
346
|
is_var_len_args = True
|
|
347
|
+
var_len_arg_key = "values"
|
|
346
348
|
|
|
347
349
|
@property
|
|
348
350
|
def keys(self) -> list[Expr]:
|
|
@@ -14,7 +14,7 @@ from builtins import type as Type
|
|
|
14
14
|
from collections import deque
|
|
15
15
|
from collections.abc import Collection, Iterator, Mapping, MutableMapping, Sequence
|
|
16
16
|
from copy import deepcopy
|
|
17
|
-
from decimal import Decimal
|
|
17
|
+
from decimal import Decimal, InvalidOperation
|
|
18
18
|
from functools import reduce
|
|
19
19
|
|
|
20
20
|
from sqlglot._typing import E, GeneratorNoDialectArgs, ParserNoDialectArgs, T
|
|
@@ -85,6 +85,7 @@ class Expr:
|
|
|
85
85
|
arg_types: t.ClassVar[dict[str, bool]] = {"this": True}
|
|
86
86
|
required_args: t.ClassVar[set[str]] = {"this"}
|
|
87
87
|
is_var_len_args: t.ClassVar[bool] = False
|
|
88
|
+
var_len_arg_key: t.ClassVar[str] = "expressions"
|
|
88
89
|
_hash_raw_args: t.ClassVar[bool] = False
|
|
89
90
|
is_subquery: t.ClassVar[bool] = False
|
|
90
91
|
is_cast: t.ClassVar[bool] = False
|
|
@@ -1577,7 +1578,7 @@ class Condition(Expr):
|
|
|
1577
1578
|
|
|
1578
1579
|
@trait
|
|
1579
1580
|
class Predicate(Condition):
|
|
1580
|
-
"""
|
|
1581
|
+
"""Any condition that evaluates to a boolean, e.g. x = y, x LIKE 'a%', a @> b."""
|
|
1581
1582
|
|
|
1582
1583
|
|
|
1583
1584
|
class Cache(Expression):
|
|
@@ -1643,8 +1644,11 @@ class Func(Condition):
|
|
|
1643
1644
|
The base class for all function expressions.
|
|
1644
1645
|
|
|
1645
1646
|
Attributes:
|
|
1646
|
-
is_var_len_args (bool): if set to True the
|
|
1647
|
+
is_var_len_args (bool): if set to True the argument identified by var_len_arg_key will be
|
|
1647
1648
|
treated as a variable length argument and the argument's value will be stored as a list.
|
|
1649
|
+
var_len_arg_key (str): the arg_types key that collects the variable length arguments.
|
|
1650
|
+
Arguments preceding it in arg_types are filled positionally; those following it (e.g.
|
|
1651
|
+
dialect flags) are never populated by from_arg_list.
|
|
1648
1652
|
_sql_names (list): the SQL name (1st item in the list) and aliases (subsequent items) for this
|
|
1649
1653
|
function expression. These values are used to map this node to a name during parsing as
|
|
1650
1654
|
well as to provide the function's name during SQL string generation. By default the SQL
|
|
@@ -1652,18 +1656,17 @@ class Func(Condition):
|
|
|
1652
1656
|
"""
|
|
1653
1657
|
|
|
1654
1658
|
is_var_len_args: t.ClassVar[bool] = False
|
|
1659
|
+
var_len_arg_key: t.ClassVar[str] = "expressions"
|
|
1655
1660
|
_sql_names: t.ClassVar[list[str]] = []
|
|
1656
1661
|
|
|
1657
1662
|
@classmethod
|
|
1658
1663
|
def from_arg_list(cls, args: Sequence[object]) -> Self:
|
|
1659
1664
|
if cls.is_var_len_args:
|
|
1660
1665
|
all_arg_keys = tuple(cls.arg_types)
|
|
1661
|
-
|
|
1662
|
-
non_var_len_arg_keys = all_arg_keys[:-1] if cls.is_var_len_args else all_arg_keys
|
|
1663
|
-
num_non_var = len(non_var_len_arg_keys)
|
|
1666
|
+
var_len_index = all_arg_keys.index(cls.var_len_arg_key)
|
|
1664
1667
|
|
|
1665
|
-
args_dict = {arg_key: arg for arg, arg_key in zip(args,
|
|
1666
|
-
args_dict[
|
|
1668
|
+
args_dict = {arg_key: arg for arg, arg_key in zip(args, all_arg_keys[:var_len_index])}
|
|
1669
|
+
args_dict[cls.var_len_arg_key] = args[var_len_index:]
|
|
1667
1670
|
else:
|
|
1668
1671
|
args_dict = {arg_key: arg for arg, arg_key in zip(args, cls.arg_types)}
|
|
1669
1672
|
|
|
@@ -1696,7 +1699,16 @@ class AggFunc(Func):
|
|
|
1696
1699
|
|
|
1697
1700
|
|
|
1698
1701
|
class Column(Expression, Condition):
|
|
1699
|
-
|
|
1702
|
+
# "shadow" marks a column whose qualifier is shadowed by a projection alias, so it must be
|
|
1703
|
+
# rendered unqualified in dialects where PROJECTION_ALIASES_SHADOW_SOURCE_NAMES is set
|
|
1704
|
+
arg_types = {
|
|
1705
|
+
"this": True,
|
|
1706
|
+
"table": False,
|
|
1707
|
+
"db": False,
|
|
1708
|
+
"catalog": False,
|
|
1709
|
+
"join_mark": False,
|
|
1710
|
+
"shadow": False,
|
|
1711
|
+
}
|
|
1700
1712
|
|
|
1701
1713
|
@property
|
|
1702
1714
|
def table(self) -> str:
|
|
@@ -1764,7 +1776,10 @@ class Literal(Expression, Condition):
|
|
|
1764
1776
|
try:
|
|
1765
1777
|
return int(self.this)
|
|
1766
1778
|
except ValueError:
|
|
1767
|
-
|
|
1779
|
+
try:
|
|
1780
|
+
return Decimal(self.this)
|
|
1781
|
+
except InvalidOperation as e:
|
|
1782
|
+
raise ValueError(f"Invalid numeric literal: {self.this!r}") from e
|
|
1768
1783
|
return self.this
|
|
1769
1784
|
|
|
1770
1785
|
|
|
@@ -2119,15 +2134,15 @@ class Div(Expression, Binary):
|
|
|
2119
2134
|
arg_types = {"this": True, "expression": True, "typed": False, "safe": False}
|
|
2120
2135
|
|
|
2121
2136
|
|
|
2122
|
-
class Overlaps(Expression, Binary):
|
|
2137
|
+
class Overlaps(Expression, Binary, Predicate):
|
|
2123
2138
|
pass
|
|
2124
2139
|
|
|
2125
2140
|
|
|
2126
|
-
class ExtendsLeft(Expression, Binary):
|
|
2141
|
+
class ExtendsLeft(Expression, Binary, Predicate):
|
|
2127
2142
|
pass
|
|
2128
2143
|
|
|
2129
2144
|
|
|
2130
|
-
class ExtendsRight(Expression, Binary):
|
|
2145
|
+
class ExtendsRight(Expression, Binary, Predicate):
|
|
2131
2146
|
pass
|
|
2132
2147
|
|
|
2133
2148
|
|
|
@@ -2231,7 +2246,7 @@ class Sub(Expression, Binary):
|
|
|
2231
2246
|
pass
|
|
2232
2247
|
|
|
2233
2248
|
|
|
2234
|
-
class Adjacent(Expression, Binary):
|
|
2249
|
+
class Adjacent(Expression, Binary, Predicate):
|
|
2235
2250
|
pass
|
|
2236
2251
|
|
|
2237
2252
|
|
|
@@ -2317,7 +2332,7 @@ class Pow(Expression, Binary, Func):
|
|
|
2317
2332
|
_sql_names = ["POWER", "POW"]
|
|
2318
2333
|
|
|
2319
2334
|
|
|
2320
|
-
class RegexpLike(Expression, Binary, Func):
|
|
2335
|
+
class RegexpLike(Expression, Binary, Predicate, Func):
|
|
2321
2336
|
arg_types = {"this": True, "expression": True, "flag": False, "full_match": False}
|
|
2322
2337
|
|
|
2323
2338
|
|
|
@@ -46,15 +46,15 @@ class JSONArrayInsert(Expression, Func):
|
|
|
46
46
|
_sql_names = ["JSON_ARRAY_INSERT"]
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
class JSONBContains(Expression, Binary, Func):
|
|
49
|
+
class JSONBContains(Expression, Binary, Predicate, Func):
|
|
50
50
|
_sql_names = ["JSONB_CONTAINS"]
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
class JSONBContainsAllTopKeys(Expression, Binary, Func):
|
|
53
|
+
class JSONBContainsAllTopKeys(Expression, Binary, Predicate, Func):
|
|
54
54
|
pass
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
class JSONBContainsAnyTopKeys(Expression, Binary, Func):
|
|
57
|
+
class JSONBContainsAnyTopKeys(Expression, Binary, Predicate, Func):
|
|
58
58
|
pass
|
|
59
59
|
|
|
60
60
|
|
|
@@ -133,6 +133,7 @@ class JSONExtractScalar(Expression, Binary, Func):
|
|
|
133
133
|
"expressions": False,
|
|
134
134
|
"json_type": False,
|
|
135
135
|
"scalar_only": False,
|
|
136
|
+
"json_subtype": False,
|
|
136
137
|
}
|
|
137
138
|
_sql_names = ["JSON_EXTRACT_SCALAR"]
|
|
138
139
|
is_var_len_args = True
|
|
@@ -1050,6 +1050,11 @@ class SetOperation(Expression, Query):
|
|
|
1050
1050
|
def named_selects(self) -> list[str]:
|
|
1051
1051
|
expr: Expr = self
|
|
1052
1052
|
while isinstance(expr, SetOperation):
|
|
1053
|
+
if expr.args.get("by_name"):
|
|
1054
|
+
left = t.cast(Selectable, expr.this.unnest()).named_selects
|
|
1055
|
+
right = t.cast(Selectable, expr.expression.unnest()).named_selects
|
|
1056
|
+
return list(dict.fromkeys(left + right))
|
|
1057
|
+
|
|
1053
1058
|
expr = expr.this.unnest()
|
|
1054
1059
|
return _named_selects(expr)
|
|
1055
1060
|
|
|
@@ -2119,8 +2124,28 @@ class IfBlock(Expression):
|
|
|
2119
2124
|
arg_types = {"this": True, "true": True, "false": False}
|
|
2120
2125
|
|
|
2121
2126
|
|
|
2127
|
+
class CaseStatement(Expression):
|
|
2128
|
+
arg_types = {"this": False, "ifs": True, "default": False}
|
|
2129
|
+
|
|
2130
|
+
|
|
2122
2131
|
class WhileBlock(Expression):
|
|
2123
|
-
arg_types = {"this": True, "body": True}
|
|
2132
|
+
arg_types = {"this": True, "body": True, "label": False}
|
|
2133
|
+
|
|
2134
|
+
|
|
2135
|
+
class LoopBlock(Expression):
|
|
2136
|
+
arg_types = {"body": True, "label": False}
|
|
2137
|
+
|
|
2138
|
+
|
|
2139
|
+
class RepeatBlock(Expression):
|
|
2140
|
+
arg_types = {"body": True, "until": True, "label": False}
|
|
2141
|
+
|
|
2142
|
+
|
|
2143
|
+
class Leave(Expression):
|
|
2144
|
+
pass
|
|
2145
|
+
|
|
2146
|
+
|
|
2147
|
+
class Iterate(Expression):
|
|
2148
|
+
pass
|
|
2124
2149
|
|
|
2125
2150
|
|
|
2126
2151
|
class EndStatement(Expression):
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from sqlglot.expressions.core import Expression, Func, Binary
|
|
5
|
+
from sqlglot.expressions.core import Expression, Func, Binary, Predicate
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
# String basics
|
|
@@ -445,11 +445,11 @@ class RegexpExtractAll(Expression, Func):
|
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
|
|
448
|
-
class RegexpFullMatch(Expression, Binary, Func):
|
|
448
|
+
class RegexpFullMatch(Expression, Binary, Predicate, Func):
|
|
449
449
|
arg_types = {"this": True, "expression": True, "options": False}
|
|
450
450
|
|
|
451
451
|
|
|
452
|
-
class RegexpILike(Expression, Binary, Func):
|
|
452
|
+
class RegexpILike(Expression, Binary, Predicate, Func):
|
|
453
453
|
arg_types = {"this": True, "expression": True, "flag": False}
|
|
454
454
|
|
|
455
455
|
|
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
import re
|
|
5
5
|
import typing as t
|
|
6
6
|
from collections import defaultdict
|
|
7
|
+
from decimal import Decimal
|
|
7
8
|
from functools import reduce, wraps
|
|
8
9
|
|
|
9
10
|
from sqlglot import exp
|
|
@@ -484,6 +485,12 @@ class Generator:
|
|
|
484
485
|
# Whether ALTER TABLE ... CHANGE COLUMN column-rename-and-redefine syntax is supported
|
|
485
486
|
SUPPORTS_CHANGE_COLUMN = False
|
|
486
487
|
|
|
488
|
+
# Whether ALTER COLUMN can set a column's nullability together with its type
|
|
489
|
+
SUPPORTS_ALTER_COLUMN_NULLABILITY = False
|
|
490
|
+
|
|
491
|
+
# Whether ALTER COLUMN IF EXISTS is supported
|
|
492
|
+
SUPPORTS_ALTER_COLUMN_IF_EXISTS = False
|
|
493
|
+
|
|
487
494
|
# Whether the LikeProperty needs to be specified inside of the schema clause
|
|
488
495
|
LIKE_PROPERTY_INSIDE_SCHEMA = False
|
|
489
496
|
|
|
@@ -1144,6 +1151,10 @@ class Generator:
|
|
|
1144
1151
|
return f"{default}CHARACTER SET={self.sql(expression, 'this')}"
|
|
1145
1152
|
|
|
1146
1153
|
def column_parts(self, expression: exp.Column) -> str:
|
|
1154
|
+
if expression.args.get("shadow") and self.dialect.PROJECTION_ALIASES_SHADOW_SOURCE_NAMES:
|
|
1155
|
+
# The qualifier would be captured by a colliding projection alias (see qualify_columns)
|
|
1156
|
+
return self.sql(expression, "this")
|
|
1157
|
+
|
|
1147
1158
|
return ".".join(
|
|
1148
1159
|
self.sql(part)
|
|
1149
1160
|
for part in (
|
|
@@ -1642,10 +1653,11 @@ class Generator:
|
|
|
1642
1653
|
def unicodestring_sql(self, expression: exp.UnicodeString) -> str:
|
|
1643
1654
|
this = self.sql(expression, "this")
|
|
1644
1655
|
escape = expression.args.get("escape")
|
|
1656
|
+
unicode_start = self.dialect.UNICODE_START
|
|
1645
1657
|
|
|
1646
|
-
if
|
|
1658
|
+
if unicode_start:
|
|
1647
1659
|
escape_substitute = r"\\\1"
|
|
1648
|
-
left_quote, right_quote =
|
|
1660
|
+
left_quote, right_quote = unicode_start, self.dialect.UNICODE_END or ""
|
|
1649
1661
|
else:
|
|
1650
1662
|
escape_substitute = r"\\u\1"
|
|
1651
1663
|
left_quote, right_quote = self.dialect.QUOTE_START, self.dialect.QUOTE_END
|
|
@@ -1657,9 +1669,16 @@ class Generator:
|
|
|
1657
1669
|
escape_pattern = ESCAPED_UNICODE_RE
|
|
1658
1670
|
escape_sql = ""
|
|
1659
1671
|
|
|
1660
|
-
if not
|
|
1672
|
+
if not unicode_start or (escape and not self.SUPPORTS_UESCAPE):
|
|
1661
1673
|
this = escape_pattern.sub(self.UNICODE_SUBSTITUTE or escape_substitute, this)
|
|
1662
1674
|
|
|
1675
|
+
if unicode_start:
|
|
1676
|
+
# A Unicode literal only escapes its delimiter by doubling it; the escape character
|
|
1677
|
+
# introduces a code point, so the dialect's ordinary string escapes don't apply here
|
|
1678
|
+
this = self._replace_line_breaks(this).replace(right_quote, right_quote * 2)
|
|
1679
|
+
else:
|
|
1680
|
+
this = self.escape_str(this, escape_backslash=False)
|
|
1681
|
+
|
|
1663
1682
|
return f"{left_quote}{this}{right_quote}{escape_sql}"
|
|
1664
1683
|
|
|
1665
1684
|
def rawstring_sql(self, expression: exp.RawString) -> str:
|
|
@@ -1702,11 +1721,12 @@ class Generator:
|
|
|
1702
1721
|
continue
|
|
1703
1722
|
|
|
1704
1723
|
param_value = param.this if isinstance(param, exp.DataTypeParam) else param
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
and param_value.is_number
|
|
1708
|
-
|
|
1709
|
-
)
|
|
1724
|
+
value = (
|
|
1725
|
+
param_value.to_py()
|
|
1726
|
+
if isinstance(param_value, exp.Literal) and param_value.is_number
|
|
1727
|
+
else None
|
|
1728
|
+
)
|
|
1729
|
+
if isinstance(value, (int, Decimal)) and value > bound:
|
|
1710
1730
|
self.unsupported(
|
|
1711
1731
|
f"{type_value.value} parameter {param_value.name} exceeds "
|
|
1712
1732
|
f"{self.dialect.__class__.__name__}'s maximum of {bound}; capping"
|
|
@@ -4198,6 +4218,13 @@ class Generator:
|
|
|
4198
4218
|
def altercolumn_sql(self, expression: exp.AlterColumn) -> str:
|
|
4199
4219
|
this = self.sql(expression, "this")
|
|
4200
4220
|
|
|
4221
|
+
exists = ""
|
|
4222
|
+
if expression.args.get("exists"):
|
|
4223
|
+
if self.SUPPORTS_ALTER_COLUMN_IF_EXISTS:
|
|
4224
|
+
exists = " IF EXISTS"
|
|
4225
|
+
else:
|
|
4226
|
+
self.unsupported("ALTER COLUMN IF EXISTS is not supported by this dialect")
|
|
4227
|
+
|
|
4201
4228
|
dtype = self.sql(expression, "dtype")
|
|
4202
4229
|
if dtype:
|
|
4203
4230
|
collate = self.sql(expression, "collate")
|
|
@@ -4205,19 +4232,24 @@ class Generator:
|
|
|
4205
4232
|
using = self.sql(expression, "using")
|
|
4206
4233
|
using = f" USING {using}" if using else ""
|
|
4207
4234
|
alter_set_type = self.ALTER_SET_TYPE + " " if self.ALTER_SET_TYPE else ""
|
|
4208
|
-
|
|
4235
|
+
null_constraint = self._alter_column_null_constraint_sql(expression)
|
|
4236
|
+
|
|
4237
|
+
return (
|
|
4238
|
+
f"ALTER COLUMN{exists} {this} {alter_set_type}{dtype}"
|
|
4239
|
+
f"{collate}{using}{null_constraint}"
|
|
4240
|
+
)
|
|
4209
4241
|
|
|
4210
4242
|
default = self.sql(expression, "default")
|
|
4211
4243
|
if default:
|
|
4212
|
-
return f"ALTER COLUMN {this} SET DEFAULT {default}"
|
|
4244
|
+
return f"ALTER COLUMN{exists} {this} SET DEFAULT {default}"
|
|
4213
4245
|
|
|
4214
4246
|
comment = self.sql(expression, "comment")
|
|
4215
4247
|
if comment:
|
|
4216
|
-
return f"ALTER COLUMN {this} COMMENT {comment}"
|
|
4248
|
+
return f"ALTER COLUMN{exists} {this} COMMENT {comment}"
|
|
4217
4249
|
|
|
4218
4250
|
visible = expression.args.get("visible")
|
|
4219
4251
|
if visible:
|
|
4220
|
-
return f"ALTER COLUMN {this} SET {visible}"
|
|
4252
|
+
return f"ALTER COLUMN{exists} {this} SET {visible}"
|
|
4221
4253
|
|
|
4222
4254
|
allow_null = expression.args.get("allow_null")
|
|
4223
4255
|
drop = expression.args.get("drop")
|
|
@@ -4227,9 +4259,20 @@ class Generator:
|
|
|
4227
4259
|
|
|
4228
4260
|
if allow_null is not None:
|
|
4229
4261
|
keyword = "DROP" if drop else "SET"
|
|
4230
|
-
return f"ALTER COLUMN {this} {keyword} NOT NULL"
|
|
4262
|
+
return f"ALTER COLUMN{exists} {this} {keyword} NOT NULL"
|
|
4263
|
+
|
|
4264
|
+
return f"ALTER COLUMN{exists} {this} DROP DEFAULT"
|
|
4231
4265
|
|
|
4232
|
-
|
|
4266
|
+
def _alter_column_null_constraint_sql(self, expression: exp.AlterColumn) -> str:
|
|
4267
|
+
allow_null = expression.args.get("allow_null")
|
|
4268
|
+
if allow_null is None:
|
|
4269
|
+
return ""
|
|
4270
|
+
|
|
4271
|
+
if not self.SUPPORTS_ALTER_COLUMN_NULLABILITY:
|
|
4272
|
+
self.unsupported("ALTER COLUMN cannot set nullability along with a type")
|
|
4273
|
+
return ""
|
|
4274
|
+
|
|
4275
|
+
return " NULL" if allow_null else " NOT NULL"
|
|
4233
4276
|
|
|
4234
4277
|
def modifycolumn_sql(self, expression: exp.ModifyColumn) -> str:
|
|
4235
4278
|
this = self.sql(expression, "this")
|
|
@@ -6272,10 +6315,30 @@ class Generator:
|
|
|
6272
6315
|
self.unsupported("Unsupported If block syntax")
|
|
6273
6316
|
return ""
|
|
6274
6317
|
|
|
6318
|
+
def casestatement_sql(self, expression: exp.CaseStatement) -> str:
|
|
6319
|
+
self.unsupported("Unsupported Case statement syntax")
|
|
6320
|
+
return ""
|
|
6321
|
+
|
|
6275
6322
|
def whileblock_sql(self, expression: exp.WhileBlock) -> str:
|
|
6276
6323
|
self.unsupported("Unsupported While block syntax")
|
|
6277
6324
|
return ""
|
|
6278
6325
|
|
|
6326
|
+
def loopblock_sql(self, expression: exp.LoopBlock) -> str:
|
|
6327
|
+
self.unsupported("Unsupported Loop block syntax")
|
|
6328
|
+
return ""
|
|
6329
|
+
|
|
6330
|
+
def repeatblock_sql(self, expression: exp.RepeatBlock) -> str:
|
|
6331
|
+
self.unsupported("Unsupported Repeat block syntax")
|
|
6332
|
+
return ""
|
|
6333
|
+
|
|
6334
|
+
def leave_sql(self, expression: exp.Leave) -> str:
|
|
6335
|
+
self.unsupported("Unsupported Leave syntax")
|
|
6336
|
+
return ""
|
|
6337
|
+
|
|
6338
|
+
def iterate_sql(self, expression: exp.Iterate) -> str:
|
|
6339
|
+
self.unsupported("Unsupported Iterate syntax")
|
|
6340
|
+
return ""
|
|
6341
|
+
|
|
6279
6342
|
def execute_sql(self, expression: exp.Execute) -> str:
|
|
6280
6343
|
self.unsupported("Unsupported Execute syntax")
|
|
6281
6344
|
return ""
|
|
@@ -175,6 +175,7 @@ class ClickHouseGenerator(generator.Generator):
|
|
|
175
175
|
STRUCT_DELIMITER = ("(", ")")
|
|
176
176
|
NVL2_SUPPORTED = False
|
|
177
177
|
ALTER_SET_TYPE = "TYPE"
|
|
178
|
+
SUPPORTS_ALTER_COLUMN_IF_EXISTS = True
|
|
178
179
|
TABLESAMPLE_REQUIRES_PARENS = False
|
|
179
180
|
TABLESAMPLE_SIZE_IS_ROWS = False
|
|
180
181
|
TABLESAMPLE_KEYWORDS = "SAMPLE"
|
|
@@ -398,7 +399,7 @@ class ClickHouseGenerator(generator.Generator):
|
|
|
398
399
|
|
|
399
400
|
# There's no list in docs, but it can be found in Clickhouse code
|
|
400
401
|
# see `ClickHouse/src/Parsers/ParserCreate*.cpp`
|
|
401
|
-
ON_CLUSTER_TARGETS = {
|
|
402
|
+
ON_CLUSTER_TARGETS: t.ClassVar = {
|
|
402
403
|
"SCHEMA", # Transpiled CREATE SCHEMA may have OnCluster property set
|
|
403
404
|
"DATABASE",
|
|
404
405
|
"TABLE",
|
|
@@ -410,7 +411,7 @@ class ClickHouseGenerator(generator.Generator):
|
|
|
410
411
|
}
|
|
411
412
|
|
|
412
413
|
# https://clickhouse.com/docs/en/sql-reference/data-types/nullable
|
|
413
|
-
NON_NULLABLE_TYPES = {
|
|
414
|
+
NON_NULLABLE_TYPES: t.ClassVar = {
|
|
414
415
|
exp.DType.ARRAY,
|
|
415
416
|
exp.DType.MAP,
|
|
416
417
|
exp.DType.STRUCT,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import typing as t
|
|
4
|
+
|
|
3
5
|
from sqlglot import exp
|
|
4
6
|
from sqlglot.dialects.dialect import (
|
|
5
7
|
approx_count_distinct_sql,
|
|
@@ -22,6 +24,7 @@ def _lag_lead_sql(self, expression: exp.Lag | exp.Lead) -> str:
|
|
|
22
24
|
|
|
23
25
|
class DorisGenerator(MySQLGenerator):
|
|
24
26
|
LAST_DAY_SUPPORTS_DATE_PART = False
|
|
27
|
+
SUPPORTS_ALTER_COLUMN_NULLABILITY = False
|
|
25
28
|
VARCHAR_REQUIRES_SIZE = False
|
|
26
29
|
WITH_PROPERTIES_PREFIX = "PROPERTIES"
|
|
27
30
|
RENAME_TABLE_WITH_DB = False
|
|
@@ -41,8 +44,8 @@ class DorisGenerator(MySQLGenerator):
|
|
|
41
44
|
exp.BuildProperty: exp.Properties.Location.POST_SCHEMA,
|
|
42
45
|
}
|
|
43
46
|
|
|
44
|
-
CAST_MAPPING = {}
|
|
45
|
-
TIMESTAMP_FUNC_TYPES = set()
|
|
47
|
+
CAST_MAPPING: t.ClassVar[dict[exp.DType, str]] = {}
|
|
48
|
+
TIMESTAMP_FUNC_TYPES: t.ClassVar[set[exp.DType]] = set()
|
|
46
49
|
|
|
47
50
|
TRANSFORMS = {
|
|
48
51
|
**MySQLGenerator.TRANSFORMS,
|