sqlglot 27.7.0__py3-none-any.whl → 27.8.0__py3-none-any.whl
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.
- sqlglot/_version.py +16 -3
- sqlglot/dialects/bigquery.py +17 -3
- sqlglot/dialects/databricks.py +5 -1
- sqlglot/dialects/dialect.py +72 -23
- sqlglot/dialects/dremio.py +29 -8
- sqlglot/dialects/duckdb.py +7 -40
- sqlglot/dialects/exasol.py +5 -0
- sqlglot/dialects/mysql.py +0 -15
- sqlglot/dialects/presto.py +0 -2
- sqlglot/dialects/singlestore.py +94 -1
- sqlglot/dialects/spark.py +6 -0
- sqlglot/dialects/trino.py +1 -0
- sqlglot/expressions.py +28 -3
- sqlglot/generator.py +6 -1
- sqlglot/jsonpath.py +10 -3
- sqlglot/parser.py +15 -1
- {sqlglot-27.7.0.dist-info → sqlglot-27.8.0.dist-info}/METADATA +2 -2
- {sqlglot-27.7.0.dist-info → sqlglot-27.8.0.dist-info}/RECORD +21 -21
- {sqlglot-27.7.0.dist-info → sqlglot-27.8.0.dist-info}/WHEEL +0 -0
- {sqlglot-27.7.0.dist-info → sqlglot-27.8.0.dist-info}/licenses/LICENSE +0 -0
- {sqlglot-27.7.0.dist-info → sqlglot-27.8.0.dist-info}/top_level.txt +0 -0
sqlglot/_version.py
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
3
|
|
|
4
|
-
__all__ = [
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
5
12
|
|
|
6
13
|
TYPE_CHECKING = False
|
|
7
14
|
if TYPE_CHECKING:
|
|
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
|
|
|
9
16
|
from typing import Union
|
|
10
17
|
|
|
11
18
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
12
20
|
else:
|
|
13
21
|
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
14
23
|
|
|
15
24
|
version: str
|
|
16
25
|
__version__: str
|
|
17
26
|
__version_tuple__: VERSION_TUPLE
|
|
18
27
|
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
19
30
|
|
|
20
|
-
__version__ = version = '27.
|
|
21
|
-
__version_tuple__ = version_tuple = (27,
|
|
31
|
+
__version__ = version = '27.8.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (27, 8, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
sqlglot/dialects/bigquery.py
CHANGED
|
@@ -4,7 +4,7 @@ import logging
|
|
|
4
4
|
import re
|
|
5
5
|
import typing as t
|
|
6
6
|
|
|
7
|
-
from sqlglot import exp, generator, parser, tokens, transforms
|
|
7
|
+
from sqlglot import exp, generator, jsonpath, parser, tokens, transforms
|
|
8
8
|
from sqlglot._typing import E
|
|
9
9
|
from sqlglot.dialects.dialect import (
|
|
10
10
|
Dialect,
|
|
@@ -30,7 +30,6 @@ from sqlglot.dialects.dialect import (
|
|
|
30
30
|
unit_to_var,
|
|
31
31
|
strposition_sql,
|
|
32
32
|
groupconcat_sql,
|
|
33
|
-
space_sql,
|
|
34
33
|
)
|
|
35
34
|
from sqlglot.helper import seq_get, split_num_words
|
|
36
35
|
from sqlglot.tokens import TokenType
|
|
@@ -474,6 +473,8 @@ class BigQuery(Dialect):
|
|
|
474
473
|
exp.Substring,
|
|
475
474
|
)
|
|
476
475
|
},
|
|
476
|
+
exp.ArgMax: lambda self, e: self._annotate_by_args(e, "this"),
|
|
477
|
+
exp.ArgMin: lambda self, e: self._annotate_by_args(e, "this"),
|
|
477
478
|
exp.Array: _annotate_array,
|
|
478
479
|
exp.ArrayConcat: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
|
|
479
480
|
exp.Ascii: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BIGINT),
|
|
@@ -495,6 +496,7 @@ class BigQuery(Dialect):
|
|
|
495
496
|
exp.GenerateTimestampArray: lambda self, e: self._annotate_with_type(
|
|
496
497
|
e, exp.DataType.build("ARRAY<TIMESTAMP>", dialect="bigquery")
|
|
497
498
|
),
|
|
499
|
+
exp.Grouping: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BIGINT),
|
|
498
500
|
exp.JSONArray: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.JSON),
|
|
499
501
|
exp.JSONExtractScalar: lambda self, e: self._annotate_with_type(
|
|
500
502
|
e, exp.DataType.Type.VARCHAR
|
|
@@ -504,9 +506,13 @@ class BigQuery(Dialect):
|
|
|
504
506
|
),
|
|
505
507
|
exp.JSONType: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.VARCHAR),
|
|
506
508
|
exp.Lag: lambda self, e: self._annotate_by_args(e, "this", "default"),
|
|
509
|
+
exp.MD5Digest: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BINARY),
|
|
507
510
|
exp.ParseTime: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.TIME),
|
|
508
511
|
exp.ParseDatetime: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.DATETIME),
|
|
512
|
+
exp.RegexpExtractAll: lambda self, e: self._annotate_by_args(e, "this", array=True),
|
|
513
|
+
exp.Replace: lambda self, e: self._annotate_by_args(e, "this"),
|
|
509
514
|
exp.Reverse: lambda self, e: self._annotate_by_args(e, "this"),
|
|
515
|
+
exp.Soundex: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.VARCHAR),
|
|
510
516
|
exp.SHA: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BINARY),
|
|
511
517
|
exp.SHA2: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BINARY),
|
|
512
518
|
exp.Sign: lambda self, e: self._annotate_by_args(e, "this"),
|
|
@@ -518,6 +524,7 @@ class BigQuery(Dialect):
|
|
|
518
524
|
exp.TimeFromParts: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.TIME),
|
|
519
525
|
exp.TsOrDsToTime: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.TIME),
|
|
520
526
|
exp.TimeTrunc: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.TIME),
|
|
527
|
+
exp.Translate: lambda self, e: self._annotate_by_args(e, "this"),
|
|
521
528
|
exp.Unicode: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BIGINT),
|
|
522
529
|
}
|
|
523
530
|
|
|
@@ -550,6 +557,12 @@ class BigQuery(Dialect):
|
|
|
550
557
|
|
|
551
558
|
return super().normalize_identifier(expression)
|
|
552
559
|
|
|
560
|
+
class JSONPathTokenizer(jsonpath.JSONPathTokenizer):
|
|
561
|
+
VAR_TOKENS = {
|
|
562
|
+
TokenType.DASH,
|
|
563
|
+
TokenType.VAR,
|
|
564
|
+
}
|
|
565
|
+
|
|
553
566
|
class Tokenizer(tokens.Tokenizer):
|
|
554
567
|
QUOTES = ["'", '"', '"""', "'''"]
|
|
555
568
|
COMMENTS = ["--", "#", ("/*", "*/")]
|
|
@@ -1019,6 +1032,8 @@ class BigQuery(Dialect):
|
|
|
1019
1032
|
EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False
|
|
1020
1033
|
SUPPORTS_UNIX_SECONDS = True
|
|
1021
1034
|
|
|
1035
|
+
SAFE_JSON_PATH_KEY_RE = re.compile(r"^[_\-a-zA-Z][\-\w]*$")
|
|
1036
|
+
|
|
1022
1037
|
TS_OR_DS_TYPES = (
|
|
1023
1038
|
exp.TsOrDsToDatetime,
|
|
1024
1039
|
exp.TsOrDsToTimestamp,
|
|
@@ -1107,7 +1122,6 @@ class BigQuery(Dialect):
|
|
|
1107
1122
|
),
|
|
1108
1123
|
exp.SHA: rename_func("SHA1"),
|
|
1109
1124
|
exp.SHA2: sha256_sql,
|
|
1110
|
-
exp.Space: space_sql,
|
|
1111
1125
|
exp.StabilityProperty: lambda self, e: (
|
|
1112
1126
|
"DETERMINISTIC" if e.name == "IMMUTABLE" else "NOT DETERMINISTIC"
|
|
1113
1127
|
),
|
sqlglot/dialects/databricks.py
CHANGED
|
@@ -99,7 +99,11 @@ class Databricks(Spark):
|
|
|
99
99
|
exp.JSONExtract: _jsonextract_sql,
|
|
100
100
|
exp.JSONExtractScalar: _jsonextract_sql,
|
|
101
101
|
exp.JSONPathRoot: lambda *_: "",
|
|
102
|
-
exp.ToChar: lambda self, e:
|
|
102
|
+
exp.ToChar: lambda self, e: (
|
|
103
|
+
self.cast_sql(exp.Cast(this=e.this, to=exp.DataType(this="STRING")))
|
|
104
|
+
if e.args.get("is_numeric")
|
|
105
|
+
else self.function_fallback_sql(e)
|
|
106
|
+
),
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
TRANSFORMS.pop(exp.TryCast)
|
sqlglot/dialects/dialect.py
CHANGED
|
@@ -35,8 +35,18 @@ DATE_ADD_OR_DIFF = t.Union[
|
|
|
35
35
|
exp.TsOrDsDiff,
|
|
36
36
|
]
|
|
37
37
|
DATE_ADD_OR_SUB = t.Union[exp.DateAdd, exp.TsOrDsAdd, exp.DateSub]
|
|
38
|
-
JSON_EXTRACT_TYPE = t.Union[
|
|
39
|
-
|
|
38
|
+
JSON_EXTRACT_TYPE = t.Union[
|
|
39
|
+
exp.JSONExtract, exp.JSONExtractScalar, exp.JSONBExtract, exp.JSONBExtractScalar
|
|
40
|
+
]
|
|
41
|
+
DATETIME_DELTA = t.Union[
|
|
42
|
+
exp.DateAdd,
|
|
43
|
+
exp.DatetimeAdd,
|
|
44
|
+
exp.DatetimeSub,
|
|
45
|
+
exp.TimeAdd,
|
|
46
|
+
exp.TimeSub,
|
|
47
|
+
exp.TimestampSub,
|
|
48
|
+
exp.TsOrDsAdd,
|
|
49
|
+
]
|
|
40
50
|
|
|
41
51
|
if t.TYPE_CHECKING:
|
|
42
52
|
from sqlglot._typing import B, E, F
|
|
@@ -1059,7 +1069,9 @@ class Dialect(metaclass=_Dialect):
|
|
|
1059
1069
|
try:
|
|
1060
1070
|
return parse_json_path(path_text, self)
|
|
1061
1071
|
except ParseError as e:
|
|
1062
|
-
if self.STRICT_JSON_PATH_SYNTAX
|
|
1072
|
+
if self.STRICT_JSON_PATH_SYNTAX and not path_text.lstrip().startswith(
|
|
1073
|
+
("lax", "strict")
|
|
1074
|
+
):
|
|
1063
1075
|
logger.warning(f"Invalid JSON path syntax. {str(e)}")
|
|
1064
1076
|
|
|
1065
1077
|
return path
|
|
@@ -1643,14 +1655,49 @@ def date_delta_sql(name: str, cast: bool = False) -> t.Callable[[Generator, DATE
|
|
|
1643
1655
|
return _delta_sql
|
|
1644
1656
|
|
|
1645
1657
|
|
|
1658
|
+
def date_delta_to_binary_interval_op(
|
|
1659
|
+
cast: bool = True,
|
|
1660
|
+
) -> t.Callable[[Generator, DATETIME_DELTA], str]:
|
|
1661
|
+
def date_delta_to_binary_interval_op_sql(self: Generator, expression: DATETIME_DELTA) -> str:
|
|
1662
|
+
this = expression.this
|
|
1663
|
+
unit = unit_to_var(expression)
|
|
1664
|
+
op = (
|
|
1665
|
+
"+"
|
|
1666
|
+
if isinstance(expression, (exp.DateAdd, exp.TimeAdd, exp.DatetimeAdd, exp.TsOrDsAdd))
|
|
1667
|
+
else "-"
|
|
1668
|
+
)
|
|
1669
|
+
|
|
1670
|
+
to_type: t.Optional[exp.DATA_TYPE] = None
|
|
1671
|
+
if cast:
|
|
1672
|
+
if isinstance(expression, exp.TsOrDsAdd):
|
|
1673
|
+
to_type = expression.return_type
|
|
1674
|
+
elif this.is_string:
|
|
1675
|
+
# Cast string literals (i.e function parameters) to the appropriate type for +/- interval to work
|
|
1676
|
+
to_type = (
|
|
1677
|
+
exp.DataType.Type.DATETIME
|
|
1678
|
+
if isinstance(expression, (exp.DatetimeAdd, exp.DatetimeSub))
|
|
1679
|
+
else exp.DataType.Type.DATE
|
|
1680
|
+
)
|
|
1681
|
+
|
|
1682
|
+
this = exp.cast(this, to_type) if to_type else this
|
|
1683
|
+
|
|
1684
|
+
expr = expression.expression
|
|
1685
|
+
interval = expr if isinstance(expr, exp.Interval) else exp.Interval(this=expr, unit=unit)
|
|
1686
|
+
|
|
1687
|
+
return f"{self.sql(this)} {op} {self.sql(interval)}"
|
|
1688
|
+
|
|
1689
|
+
return date_delta_to_binary_interval_op_sql
|
|
1690
|
+
|
|
1691
|
+
|
|
1646
1692
|
def unit_to_str(expression: exp.Expression, default: str = "DAY") -> t.Optional[exp.Expression]:
|
|
1647
1693
|
unit = expression.args.get("unit")
|
|
1694
|
+
if not unit:
|
|
1695
|
+
return exp.Literal.string(default) if default else None
|
|
1648
1696
|
|
|
1649
|
-
if isinstance(unit, exp.Placeholder):
|
|
1697
|
+
if isinstance(unit, exp.Placeholder) or type(unit) not in (exp.Var, exp.Literal):
|
|
1650
1698
|
return unit
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
return exp.Literal.string(default) if default else None
|
|
1699
|
+
|
|
1700
|
+
return exp.Literal.string(unit.name)
|
|
1654
1701
|
|
|
1655
1702
|
|
|
1656
1703
|
def unit_to_var(expression: exp.Expression, default: str = "DAY") -> t.Optional[exp.Expression]:
|
|
@@ -1730,7 +1777,10 @@ def merge_without_target_sql(self: Generator, expression: exp.Merge) -> str:
|
|
|
1730
1777
|
|
|
1731
1778
|
|
|
1732
1779
|
def build_json_extract_path(
|
|
1733
|
-
expr_type: t.Type[F],
|
|
1780
|
+
expr_type: t.Type[F],
|
|
1781
|
+
zero_based_indexing: bool = True,
|
|
1782
|
+
arrow_req_json_type: bool = False,
|
|
1783
|
+
json_type: t.Optional[str] = None,
|
|
1734
1784
|
) -> t.Callable[[t.List], F]:
|
|
1735
1785
|
def _builder(args: t.List) -> F:
|
|
1736
1786
|
segments: t.List[exp.JSONPathPart] = [exp.JSONPathRoot()]
|
|
@@ -1750,11 +1800,19 @@ def build_json_extract_path(
|
|
|
1750
1800
|
|
|
1751
1801
|
# This is done to avoid failing in the expression validator due to the arg count
|
|
1752
1802
|
del args[2:]
|
|
1753
|
-
|
|
1754
|
-
this
|
|
1755
|
-
expression
|
|
1756
|
-
|
|
1757
|
-
|
|
1803
|
+
kwargs = {
|
|
1804
|
+
"this": seq_get(args, 0),
|
|
1805
|
+
"expression": exp.JSONPath(expressions=segments),
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
is_jsonb = issubclass(expr_type, (exp.JSONBExtract, exp.JSONBExtractScalar))
|
|
1809
|
+
if not is_jsonb:
|
|
1810
|
+
kwargs["only_json_types"] = arrow_req_json_type
|
|
1811
|
+
|
|
1812
|
+
if json_type is not None:
|
|
1813
|
+
kwargs["json_type"] = json_type
|
|
1814
|
+
|
|
1815
|
+
return expr_type(**kwargs)
|
|
1758
1816
|
|
|
1759
1817
|
return _builder
|
|
1760
1818
|
|
|
@@ -1962,7 +2020,7 @@ def groupconcat_sql(
|
|
|
1962
2020
|
return self.sql(listagg)
|
|
1963
2021
|
|
|
1964
2022
|
|
|
1965
|
-
def build_timetostr_or_tochar(args: t.List, dialect:
|
|
2023
|
+
def build_timetostr_or_tochar(args: t.List, dialect: DialectType) -> exp.TimeToStr | exp.ToChar:
|
|
1966
2024
|
if len(args) == 2:
|
|
1967
2025
|
this = args[0]
|
|
1968
2026
|
if not this.type:
|
|
@@ -1983,12 +2041,3 @@ def build_replace_with_optional_replacement(args: t.List) -> exp.Replace:
|
|
|
1983
2041
|
expression=seq_get(args, 1),
|
|
1984
2042
|
replacement=seq_get(args, 2) or exp.Literal.string(""),
|
|
1985
2043
|
)
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
def space_sql(self: Generator, expression: exp.Space) -> str:
|
|
1989
|
-
return self.sql(
|
|
1990
|
-
exp.Repeat(
|
|
1991
|
-
this=exp.Literal.string(" "),
|
|
1992
|
-
times=expression.this,
|
|
1993
|
-
)
|
|
1994
|
-
)
|
sqlglot/dialects/dremio.py
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import typing as t
|
|
4
|
+
|
|
3
5
|
from sqlglot import expressions as exp
|
|
4
6
|
from sqlglot import parser, generator, tokens
|
|
5
|
-
from sqlglot.dialects.dialect import
|
|
6
|
-
|
|
7
|
+
from sqlglot.dialects.dialect import (
|
|
8
|
+
Dialect,
|
|
9
|
+
build_timetostr_or_tochar,
|
|
10
|
+
build_formatted_time,
|
|
11
|
+
rename_func,
|
|
12
|
+
unit_to_var,
|
|
13
|
+
)
|
|
14
|
+
from sqlglot.helper import seq_get
|
|
15
|
+
|
|
16
|
+
if t.TYPE_CHECKING:
|
|
17
|
+
from sqlglot.dialects.dialect import DialectType
|
|
7
18
|
|
|
8
|
-
DATE_DELTA = t.Union[
|
|
9
|
-
exp.DateAdd,
|
|
10
|
-
exp.DateSub,
|
|
11
|
-
]
|
|
19
|
+
DATE_DELTA = t.Union[exp.DateAdd, exp.DateSub]
|
|
12
20
|
|
|
13
21
|
|
|
14
22
|
def _date_delta_sql(name: str) -> t.Callable[[Dremio.Generator, DATE_DELTA], str]:
|
|
@@ -31,6 +39,17 @@ def _date_delta_sql(name: str) -> t.Callable[[Dremio.Generator, DATE_DELTA], str
|
|
|
31
39
|
return _delta_sql
|
|
32
40
|
|
|
33
41
|
|
|
42
|
+
def to_char_is_numeric_handler(args: t.List, dialect: DialectType) -> exp.TimeToStr | exp.ToChar:
|
|
43
|
+
expression = build_timetostr_or_tochar(args, dialect)
|
|
44
|
+
fmt = seq_get(args, 1)
|
|
45
|
+
|
|
46
|
+
if fmt and isinstance(expression, exp.ToChar) and fmt.is_string and "#" in fmt.name:
|
|
47
|
+
# Only mark as numeric if format is a literal containing #
|
|
48
|
+
expression.set("is_numeric", True)
|
|
49
|
+
|
|
50
|
+
return expression
|
|
51
|
+
|
|
52
|
+
|
|
34
53
|
class Dremio(Dialect):
|
|
35
54
|
SUPPORTS_USER_DEFINED_TYPES = False
|
|
36
55
|
CONCAT_COALESCE = True
|
|
@@ -94,7 +113,9 @@ class Dremio(Dialect):
|
|
|
94
113
|
|
|
95
114
|
FUNCTIONS = {
|
|
96
115
|
**parser.Parser.FUNCTIONS,
|
|
97
|
-
"TO_CHAR":
|
|
116
|
+
"TO_CHAR": to_char_is_numeric_handler,
|
|
117
|
+
"DATE_FORMAT": build_formatted_time(exp.TimeToStr, "dremio"),
|
|
118
|
+
"TO_DATE": build_formatted_time(exp.TsOrDsToDate, "dremio"),
|
|
98
119
|
}
|
|
99
120
|
|
|
100
121
|
class Generator(generator.Generator):
|
|
@@ -123,8 +144,8 @@ class Dremio(Dialect):
|
|
|
123
144
|
|
|
124
145
|
TRANSFORMS = {
|
|
125
146
|
**generator.Generator.TRANSFORMS,
|
|
147
|
+
exp.ToChar: rename_func("TO_CHAR"),
|
|
126
148
|
exp.TimeToStr: lambda self, e: self.func("TO_CHAR", e.this, self.format_time(e)),
|
|
127
|
-
exp.ToChar: lambda self, e: self.function_fallback_sql(e),
|
|
128
149
|
exp.DateAdd: _date_delta_sql("DATE_ADD"),
|
|
129
150
|
exp.DateSub: _date_delta_sql("DATE_SUB"),
|
|
130
151
|
}
|
sqlglot/dialects/duckdb.py
CHANGED
|
@@ -4,7 +4,6 @@ import typing as t
|
|
|
4
4
|
|
|
5
5
|
from sqlglot import exp, generator, parser, tokens, transforms
|
|
6
6
|
|
|
7
|
-
from sqlglot.expressions import DATA_TYPE
|
|
8
7
|
from sqlglot.dialects.dialect import (
|
|
9
8
|
Dialect,
|
|
10
9
|
JSON_EXTRACT_TYPE,
|
|
@@ -16,6 +15,7 @@ from sqlglot.dialects.dialect import (
|
|
|
16
15
|
bool_xor_sql,
|
|
17
16
|
build_default_decimal_type,
|
|
18
17
|
count_if_to_sum,
|
|
18
|
+
date_delta_to_binary_interval_op,
|
|
19
19
|
date_trunc_to_time,
|
|
20
20
|
datestrtodate_sql,
|
|
21
21
|
no_datetime_sql,
|
|
@@ -32,7 +32,6 @@ from sqlglot.dialects.dialect import (
|
|
|
32
32
|
str_to_time_sql,
|
|
33
33
|
timestamptrunc_sql,
|
|
34
34
|
timestrtotime_sql,
|
|
35
|
-
unit_to_var,
|
|
36
35
|
unit_to_str,
|
|
37
36
|
sha256_sql,
|
|
38
37
|
build_regexp_extract,
|
|
@@ -45,38 +44,6 @@ from sqlglot.helper import seq_get
|
|
|
45
44
|
from sqlglot.tokens import TokenType
|
|
46
45
|
from sqlglot.parser import binary_range_parser
|
|
47
46
|
|
|
48
|
-
DATETIME_DELTA = t.Union[
|
|
49
|
-
exp.DateAdd, exp.TimeAdd, exp.DatetimeAdd, exp.TsOrDsAdd, exp.DateSub, exp.DatetimeSub
|
|
50
|
-
]
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def _date_delta_sql(self: DuckDB.Generator, expression: DATETIME_DELTA) -> str:
|
|
54
|
-
this = expression.this
|
|
55
|
-
unit = unit_to_var(expression)
|
|
56
|
-
op = (
|
|
57
|
-
"+"
|
|
58
|
-
if isinstance(expression, (exp.DateAdd, exp.TimeAdd, exp.DatetimeAdd, exp.TsOrDsAdd))
|
|
59
|
-
else "-"
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
to_type: t.Optional[DATA_TYPE] = None
|
|
63
|
-
if isinstance(expression, exp.TsOrDsAdd):
|
|
64
|
-
to_type = expression.return_type
|
|
65
|
-
elif this.is_string:
|
|
66
|
-
# Cast string literals (i.e function parameters) to the appropriate type for +/- interval to work
|
|
67
|
-
to_type = (
|
|
68
|
-
exp.DataType.Type.DATETIME
|
|
69
|
-
if isinstance(expression, (exp.DatetimeAdd, exp.DatetimeSub))
|
|
70
|
-
else exp.DataType.Type.DATE
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
this = exp.cast(this, to_type) if to_type else this
|
|
74
|
-
|
|
75
|
-
expr = expression.expression
|
|
76
|
-
interval = expr if isinstance(expr, exp.Interval) else exp.Interval(this=expr, unit=unit)
|
|
77
|
-
|
|
78
|
-
return f"{self.sql(this)} {op} {self.sql(interval)}"
|
|
79
|
-
|
|
80
47
|
|
|
81
48
|
# BigQuery -> DuckDB conversion for the DATE function
|
|
82
49
|
def _date_sql(self: DuckDB.Generator, expression: exp.Date) -> str:
|
|
@@ -687,14 +654,14 @@ class DuckDB(Dialect):
|
|
|
687
654
|
exp.DayOfYear: rename_func("DAYOFYEAR"),
|
|
688
655
|
exp.DataType: _datatype_sql,
|
|
689
656
|
exp.Date: _date_sql,
|
|
690
|
-
exp.DateAdd:
|
|
657
|
+
exp.DateAdd: date_delta_to_binary_interval_op(),
|
|
691
658
|
exp.DateFromParts: rename_func("MAKE_DATE"),
|
|
692
|
-
exp.DateSub:
|
|
659
|
+
exp.DateSub: date_delta_to_binary_interval_op(),
|
|
693
660
|
exp.DateDiff: _date_diff_sql,
|
|
694
661
|
exp.DateStrToDate: datestrtodate_sql,
|
|
695
662
|
exp.Datetime: no_datetime_sql,
|
|
696
|
-
exp.DatetimeSub:
|
|
697
|
-
exp.DatetimeAdd:
|
|
663
|
+
exp.DatetimeSub: date_delta_to_binary_interval_op(),
|
|
664
|
+
exp.DatetimeAdd: date_delta_to_binary_interval_op(),
|
|
698
665
|
exp.DateToDi: lambda self,
|
|
699
666
|
e: f"CAST(STRFTIME({self.sql(e, 'this')}, {DuckDB.DATEINT_FORMAT}) AS INT)",
|
|
700
667
|
exp.Decode: lambda self, e: encode_decode_sql(self, e, "DECODE", replace=False),
|
|
@@ -756,7 +723,7 @@ class DuckDB(Dialect):
|
|
|
756
723
|
),
|
|
757
724
|
exp.Struct: _struct_sql,
|
|
758
725
|
exp.Transform: rename_func("LIST_TRANSFORM"),
|
|
759
|
-
exp.TimeAdd:
|
|
726
|
+
exp.TimeAdd: date_delta_to_binary_interval_op(),
|
|
760
727
|
exp.Time: no_time_sql,
|
|
761
728
|
exp.TimeDiff: _timediff_sql,
|
|
762
729
|
exp.Timestamp: no_timestamp_sql,
|
|
@@ -773,7 +740,7 @@ class DuckDB(Dialect):
|
|
|
773
740
|
exp.TimeToUnix: rename_func("EPOCH"),
|
|
774
741
|
exp.TsOrDiToDi: lambda self,
|
|
775
742
|
e: f"CAST(SUBSTR(REPLACE(CAST({self.sql(e, 'this')} AS TEXT), '-', ''), 1, 8) AS INT)",
|
|
776
|
-
exp.TsOrDsAdd:
|
|
743
|
+
exp.TsOrDsAdd: date_delta_to_binary_interval_op(),
|
|
777
744
|
exp.TsOrDsDiff: lambda self, e: self.func(
|
|
778
745
|
"DATE_DIFF",
|
|
779
746
|
f"'{e.args.get('unit') or 'DAY'}'",
|
sqlglot/dialects/exasol.py
CHANGED
|
@@ -109,6 +109,7 @@ class Exasol(Dialect):
|
|
|
109
109
|
"ENDIF": TokenType.END,
|
|
110
110
|
"LONG VARCHAR": TokenType.TEXT,
|
|
111
111
|
}
|
|
112
|
+
KEYWORDS.pop("DIV")
|
|
112
113
|
|
|
113
114
|
class Parser(parser.Parser):
|
|
114
115
|
FUNCTIONS = {
|
|
@@ -131,6 +132,7 @@ class Exasol(Dialect):
|
|
|
131
132
|
"DATE_TRUNC": lambda args: exp.TimestampTrunc(
|
|
132
133
|
this=seq_get(args, 1), unit=seq_get(args, 0)
|
|
133
134
|
),
|
|
135
|
+
"DIV": binary_from_function(exp.IntDiv),
|
|
134
136
|
"EVERY": lambda args: exp.All(this=seq_get(args, 0)),
|
|
135
137
|
"EDIT_DISTANCE": exp.Levenshtein.from_arg_list,
|
|
136
138
|
"HASH_SHA": exp.SHA.from_arg_list,
|
|
@@ -228,6 +230,8 @@ class Exasol(Dialect):
|
|
|
228
230
|
# https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/bit_xor.htm
|
|
229
231
|
exp.BitwiseXor: rename_func("BIT_XOR"),
|
|
230
232
|
exp.DateDiff: _date_diff_sql,
|
|
233
|
+
# https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/div.htm#DIV
|
|
234
|
+
exp.IntDiv: rename_func("DIV"),
|
|
231
235
|
exp.TsOrDsDiff: _date_diff_sql,
|
|
232
236
|
exp.DateTrunc: lambda self, e: self.func("TRUNC", e.this, unit_to_str(e)),
|
|
233
237
|
exp.DatetimeTrunc: timestamptrunc_sql(),
|
|
@@ -280,6 +284,7 @@ class Exasol(Dialect):
|
|
|
280
284
|
exp.MD5Digest: rename_func("HASHTYPE_MD5"),
|
|
281
285
|
# https://docs.exasol.com/db/latest/sql/create_view.htm
|
|
282
286
|
exp.CommentColumnConstraint: lambda self, e: f"COMMENT IS {self.sql(e, 'this')}",
|
|
287
|
+
exp.WeekOfYear: rename_func("WEEK"),
|
|
283
288
|
}
|
|
284
289
|
|
|
285
290
|
def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str:
|
sqlglot/dialects/mysql.py
CHANGED
|
@@ -709,21 +709,6 @@ class MySQL(Dialect):
|
|
|
709
709
|
|
|
710
710
|
return self.expression(exp.GroupConcat, this=this, separator=separator)
|
|
711
711
|
|
|
712
|
-
def _parse_json_value(self) -> exp.JSONValue:
|
|
713
|
-
this = self._parse_bitwise()
|
|
714
|
-
self._match(TokenType.COMMA)
|
|
715
|
-
path = self._parse_bitwise()
|
|
716
|
-
|
|
717
|
-
returning = self._match(TokenType.RETURNING) and self._parse_type()
|
|
718
|
-
|
|
719
|
-
return self.expression(
|
|
720
|
-
exp.JSONValue,
|
|
721
|
-
this=this,
|
|
722
|
-
path=self.dialect.to_json_path(path),
|
|
723
|
-
returning=returning,
|
|
724
|
-
on_condition=self._parse_on_condition(),
|
|
725
|
-
)
|
|
726
|
-
|
|
727
712
|
def _parse_alter_table_alter_index(self) -> exp.AlterIndex:
|
|
728
713
|
index = self._parse_field(any_token=True)
|
|
729
714
|
|
sqlglot/dialects/presto.py
CHANGED
|
@@ -31,7 +31,6 @@ from sqlglot.dialects.dialect import (
|
|
|
31
31
|
sequence_sql,
|
|
32
32
|
build_regexp_extract,
|
|
33
33
|
explode_to_unnest_sql,
|
|
34
|
-
space_sql,
|
|
35
34
|
)
|
|
36
35
|
from sqlglot.dialects.hive import Hive
|
|
37
36
|
from sqlglot.dialects.mysql import MySQL
|
|
@@ -506,7 +505,6 @@ class Presto(Dialect):
|
|
|
506
505
|
amend_exploded_column_table,
|
|
507
506
|
]
|
|
508
507
|
),
|
|
509
|
-
exp.Space: space_sql,
|
|
510
508
|
exp.SortArray: _no_sort_array,
|
|
511
509
|
exp.StrPosition: lambda self, e: strposition_sql(self, e, supports_occurrence=True),
|
|
512
510
|
exp.StrToDate: lambda self, e: f"CAST({_str_to_time_sql(self, e)} AS DATE)",
|
sqlglot/dialects/singlestore.py
CHANGED
|
@@ -2,7 +2,13 @@ from sqlglot import TokenType
|
|
|
2
2
|
import typing as t
|
|
3
3
|
|
|
4
4
|
from sqlglot import exp
|
|
5
|
-
from sqlglot.dialects.dialect import
|
|
5
|
+
from sqlglot.dialects.dialect import (
|
|
6
|
+
build_formatted_time,
|
|
7
|
+
build_json_extract_path,
|
|
8
|
+
json_extract_segments,
|
|
9
|
+
json_path_key_only_name,
|
|
10
|
+
rename_func,
|
|
11
|
+
)
|
|
6
12
|
from sqlglot.dialects.mysql import MySQL
|
|
7
13
|
from sqlglot.generator import unsupported_args
|
|
8
14
|
from sqlglot.helper import seq_get
|
|
@@ -66,6 +72,27 @@ class SingleStore(MySQL):
|
|
|
66
72
|
),
|
|
67
73
|
"UNIX_TIMESTAMP": exp.StrToUnix.from_arg_list,
|
|
68
74
|
"FROM_UNIXTIME": build_formatted_time(exp.UnixToTime, "mysql"),
|
|
75
|
+
"BSON_EXTRACT_BSON": build_json_extract_path(exp.JSONBExtract),
|
|
76
|
+
"BSON_EXTRACT_STRING": build_json_extract_path(
|
|
77
|
+
exp.JSONBExtractScalar, json_type="STRING"
|
|
78
|
+
),
|
|
79
|
+
"BSON_EXTRACT_DOUBLE": build_json_extract_path(
|
|
80
|
+
exp.JSONBExtractScalar, json_type="DOUBLE"
|
|
81
|
+
),
|
|
82
|
+
"BSON_EXTRACT_BIGINT": build_json_extract_path(
|
|
83
|
+
exp.JSONBExtractScalar, json_type="BIGINT"
|
|
84
|
+
),
|
|
85
|
+
"JSON_EXTRACT_JSON": build_json_extract_path(exp.JSONExtract),
|
|
86
|
+
"JSON_EXTRACT_STRING": build_json_extract_path(
|
|
87
|
+
exp.JSONExtractScalar, json_type="STRING"
|
|
88
|
+
),
|
|
89
|
+
"JSON_EXTRACT_DOUBLE": build_json_extract_path(
|
|
90
|
+
exp.JSONExtractScalar, json_type="DOUBLE"
|
|
91
|
+
),
|
|
92
|
+
"JSON_EXTRACT_BIGINT": build_json_extract_path(
|
|
93
|
+
exp.JSONExtractScalar, json_type="BIGINT"
|
|
94
|
+
),
|
|
95
|
+
"DATE": exp.Date.from_arg_list,
|
|
69
96
|
}
|
|
70
97
|
|
|
71
98
|
CAST_COLUMN_OPERATORS = {TokenType.COLON_GT, TokenType.NCOLON_GT}
|
|
@@ -81,9 +108,24 @@ class SingleStore(MySQL):
|
|
|
81
108
|
this=this,
|
|
82
109
|
to=to,
|
|
83
110
|
),
|
|
111
|
+
TokenType.DCOLON: lambda self, this, path: build_json_extract_path(exp.JSONExtract)(
|
|
112
|
+
[this, exp.Literal.string(path.name)]
|
|
113
|
+
),
|
|
114
|
+
TokenType.DCOLONDOLLAR: lambda self, this, path: build_json_extract_path(
|
|
115
|
+
exp.JSONExtractScalar, json_type="STRING"
|
|
116
|
+
)([this, exp.Literal.string(path.name)]),
|
|
117
|
+
TokenType.DCOLONPERCENT: lambda self, this, path: build_json_extract_path(
|
|
118
|
+
exp.JSONExtractScalar, json_type="DOUBLE"
|
|
119
|
+
)([this, exp.Literal.string(path.name)]),
|
|
84
120
|
}
|
|
85
121
|
|
|
86
122
|
class Generator(MySQL.Generator):
|
|
123
|
+
SUPPORTED_JSON_PATH_PARTS = {
|
|
124
|
+
exp.JSONPathKey,
|
|
125
|
+
exp.JSONPathRoot,
|
|
126
|
+
exp.JSONPathSubscript,
|
|
127
|
+
}
|
|
128
|
+
|
|
87
129
|
TRANSFORMS = {
|
|
88
130
|
**MySQL.Generator.TRANSFORMS,
|
|
89
131
|
exp.TsOrDsToDate: lambda self, e: self.func("TO_DATE", e.this, self.format_time(e)),
|
|
@@ -107,6 +149,7 @@ class SingleStore(MySQL):
|
|
|
107
149
|
inverse_time_trie=MySQL.INVERSE_TIME_TRIE,
|
|
108
150
|
),
|
|
109
151
|
),
|
|
152
|
+
exp.Date: unsupported_args("zone", "expressions")(rename_func("DATE")),
|
|
110
153
|
exp.Cast: unsupported_args("format", "action", "default")(
|
|
111
154
|
lambda self, e: f"{self.sql(e, 'this')} :> {self.sql(e, 'to')}"
|
|
112
155
|
),
|
|
@@ -138,7 +181,29 @@ class SingleStore(MySQL):
|
|
|
138
181
|
),
|
|
139
182
|
),
|
|
140
183
|
exp.UnixToTimeStr: lambda self, e: f"FROM_UNIXTIME({self.sql(e, 'this')}) :> TEXT",
|
|
184
|
+
exp.JSONExtract: unsupported_args(
|
|
185
|
+
"only_json_types",
|
|
186
|
+
"expressions",
|
|
187
|
+
"variant_extract",
|
|
188
|
+
"json_query",
|
|
189
|
+
"option",
|
|
190
|
+
"quote",
|
|
191
|
+
"on_condition",
|
|
192
|
+
"requires_json",
|
|
193
|
+
)(json_extract_segments("JSON_EXTRACT_JSON")),
|
|
194
|
+
exp.JSONBExtract: json_extract_segments("BSON_EXTRACT_BSON"),
|
|
195
|
+
exp.JSONPathKey: json_path_key_only_name,
|
|
196
|
+
exp.JSONPathSubscript: lambda self, e: self.json_path_part(e.this),
|
|
197
|
+
exp.JSONPathRoot: lambda *_: "",
|
|
141
198
|
}
|
|
199
|
+
TRANSFORMS.pop(exp.JSONExtractScalar)
|
|
200
|
+
TRANSFORMS.pop(exp.JSONPathFilter)
|
|
201
|
+
TRANSFORMS.pop(exp.JSONPathRecursive)
|
|
202
|
+
TRANSFORMS.pop(exp.JSONPathScript)
|
|
203
|
+
TRANSFORMS.pop(exp.JSONPathSelector)
|
|
204
|
+
TRANSFORMS.pop(exp.JSONPathSlice)
|
|
205
|
+
TRANSFORMS.pop(exp.JSONPathUnion)
|
|
206
|
+
TRANSFORMS.pop(exp.JSONPathWildcard)
|
|
142
207
|
|
|
143
208
|
# https://docs.singlestore.com/cloud/reference/sql-reference/restricted-keywords/list-of-restricted-keywords/
|
|
144
209
|
RESERVED_KEYWORDS = {
|
|
@@ -1193,3 +1258,31 @@ class SingleStore(MySQL):
|
|
|
1193
1258
|
"zerofill",
|
|
1194
1259
|
"zone",
|
|
1195
1260
|
}
|
|
1261
|
+
|
|
1262
|
+
def jsonextractscalar_sql(self, expression: exp.JSONExtractScalar) -> str:
|
|
1263
|
+
json_type = expression.args.get("json_type")
|
|
1264
|
+
func_name = "JSON_EXTRACT_JSON" if json_type is None else f"JSON_EXTRACT_{json_type}"
|
|
1265
|
+
return json_extract_segments(func_name)(self, expression)
|
|
1266
|
+
|
|
1267
|
+
def jsonbextractscalar_sql(self, expression: exp.JSONBExtractScalar) -> str:
|
|
1268
|
+
json_type = expression.args.get("json_type")
|
|
1269
|
+
func_name = "BSON_EXTRACT_BSON" if json_type is None else f"BSON_EXTRACT_{json_type}"
|
|
1270
|
+
return json_extract_segments(func_name)(self, expression)
|
|
1271
|
+
|
|
1272
|
+
def jsonextractarray_sql(self, expression: exp.JSONExtractArray) -> str:
|
|
1273
|
+
self.unsupported("Arrays are not supported in SingleStore")
|
|
1274
|
+
return self.function_fallback_sql(expression)
|
|
1275
|
+
|
|
1276
|
+
@unsupported_args("on_condition")
|
|
1277
|
+
def jsonvalue_sql(self, expression: exp.JSONValue) -> str:
|
|
1278
|
+
res: exp.Expression = exp.JSONExtractScalar(
|
|
1279
|
+
this=expression.this,
|
|
1280
|
+
expression=expression.args.get("path"),
|
|
1281
|
+
json_type="STRING",
|
|
1282
|
+
)
|
|
1283
|
+
|
|
1284
|
+
returning = expression.args.get("returning")
|
|
1285
|
+
if returning is not None:
|
|
1286
|
+
res = exp.Cast(this=res, to=returning)
|
|
1287
|
+
|
|
1288
|
+
return self.sql(res)
|
sqlglot/dialects/spark.py
CHANGED
|
@@ -9,6 +9,7 @@ from sqlglot.dialects.dialect import (
|
|
|
9
9
|
unit_to_var,
|
|
10
10
|
timestampdiff_sql,
|
|
11
11
|
build_date_delta,
|
|
12
|
+
date_delta_to_binary_interval_op,
|
|
12
13
|
groupconcat_sql,
|
|
13
14
|
)
|
|
14
15
|
from sqlglot.dialects.hive import _build_with_ignore_nulls
|
|
@@ -195,13 +196,18 @@ class Spark(Spark2):
|
|
|
195
196
|
]
|
|
196
197
|
),
|
|
197
198
|
exp.DateFromUnixDate: rename_func("DATE_FROM_UNIX_DATE"),
|
|
199
|
+
exp.DatetimeAdd: date_delta_to_binary_interval_op(cast=False),
|
|
200
|
+
exp.DatetimeSub: date_delta_to_binary_interval_op(cast=False),
|
|
198
201
|
exp.GroupConcat: _groupconcat_sql,
|
|
199
202
|
exp.EndsWith: rename_func("ENDSWITH"),
|
|
200
203
|
exp.PartitionedByProperty: lambda self,
|
|
201
204
|
e: f"PARTITIONED BY {self.wrap(self.expressions(sqls=[_normalize_partition(e) for e in e.this.expressions], skip_first=True))}",
|
|
202
205
|
exp.StartsWith: rename_func("STARTSWITH"),
|
|
206
|
+
exp.TimeAdd: date_delta_to_binary_interval_op(cast=False),
|
|
207
|
+
exp.TimeSub: date_delta_to_binary_interval_op(cast=False),
|
|
203
208
|
exp.TsOrDsAdd: _dateadd_sql,
|
|
204
209
|
exp.TimestampAdd: _dateadd_sql,
|
|
210
|
+
exp.TimestampSub: date_delta_to_binary_interval_op(cast=False),
|
|
205
211
|
exp.DatetimeDiff: timestampdiff_sql,
|
|
206
212
|
exp.TimestampDiff: timestampdiff_sql,
|
|
207
213
|
exp.TryCast: lambda self, e: (
|
sqlglot/dialects/trino.py
CHANGED
|
@@ -21,6 +21,7 @@ class Trino(Presto):
|
|
|
21
21
|
**Presto.Parser.FUNCTION_PARSERS,
|
|
22
22
|
"TRIM": lambda self: self._parse_trim(),
|
|
23
23
|
"JSON_QUERY": lambda self: self._parse_json_query(),
|
|
24
|
+
"JSON_VALUE": lambda self: self._parse_json_value(),
|
|
24
25
|
"LISTAGG": lambda self: self._parse_string_agg(),
|
|
25
26
|
}
|
|
26
27
|
|
sqlglot/expressions.py
CHANGED
|
@@ -5301,7 +5301,7 @@ class TimeUnit(Expression):
|
|
|
5301
5301
|
|
|
5302
5302
|
def __init__(self, **args):
|
|
5303
5303
|
unit = args.get("unit")
|
|
5304
|
-
if
|
|
5304
|
+
if type(unit) in self.VAR_LIKE:
|
|
5305
5305
|
args["unit"] = Var(
|
|
5306
5306
|
this=(self.UNABBREVIATED_UNIT_NAME.get(unit.name) or unit.name).upper()
|
|
5307
5307
|
)
|
|
@@ -5464,6 +5464,15 @@ class Transform(Func):
|
|
|
5464
5464
|
arg_types = {"this": True, "expression": True}
|
|
5465
5465
|
|
|
5466
5466
|
|
|
5467
|
+
class Translate(Func):
|
|
5468
|
+
arg_types = {"this": True, "from": True, "to": True}
|
|
5469
|
+
|
|
5470
|
+
|
|
5471
|
+
class Grouping(AggFunc):
|
|
5472
|
+
arg_types = {"expressions": True}
|
|
5473
|
+
is_var_len_args = True
|
|
5474
|
+
|
|
5475
|
+
|
|
5467
5476
|
class Anonymous(Func):
|
|
5468
5477
|
arg_types = {"this": True, "expressions": False}
|
|
5469
5478
|
is_var_len_args = True
|
|
@@ -5531,7 +5540,12 @@ class Pad(Func):
|
|
|
5531
5540
|
# https://docs.snowflake.com/en/sql-reference/functions/to_char
|
|
5532
5541
|
# https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/TO_CHAR-number.html
|
|
5533
5542
|
class ToChar(Func):
|
|
5534
|
-
arg_types = {
|
|
5543
|
+
arg_types = {
|
|
5544
|
+
"this": True,
|
|
5545
|
+
"format": False,
|
|
5546
|
+
"nlsparam": False,
|
|
5547
|
+
"is_numeric": False,
|
|
5548
|
+
}
|
|
5535
5549
|
|
|
5536
5550
|
|
|
5537
5551
|
# https://docs.snowflake.com/en/sql-reference/functions/to_decimal
|
|
@@ -6508,7 +6522,13 @@ class JSONExtractArray(Func):
|
|
|
6508
6522
|
|
|
6509
6523
|
|
|
6510
6524
|
class JSONExtractScalar(Binary, Func):
|
|
6511
|
-
arg_types = {
|
|
6525
|
+
arg_types = {
|
|
6526
|
+
"this": True,
|
|
6527
|
+
"expression": True,
|
|
6528
|
+
"only_json_types": False,
|
|
6529
|
+
"expressions": False,
|
|
6530
|
+
"json_type": False,
|
|
6531
|
+
}
|
|
6512
6532
|
_sql_names = ["JSON_EXTRACT_SCALAR"]
|
|
6513
6533
|
is_var_len_args = True
|
|
6514
6534
|
|
|
@@ -6522,6 +6542,7 @@ class JSONBExtract(Binary, Func):
|
|
|
6522
6542
|
|
|
6523
6543
|
|
|
6524
6544
|
class JSONBExtractScalar(Binary, Func):
|
|
6545
|
+
arg_types = {"this": True, "expression": True, "json_type": False}
|
|
6525
6546
|
_sql_names = ["JSONB_EXTRACT_SCALAR"]
|
|
6526
6547
|
|
|
6527
6548
|
|
|
@@ -6841,6 +6862,10 @@ class SortArray(Func):
|
|
|
6841
6862
|
arg_types = {"this": True, "asc": False}
|
|
6842
6863
|
|
|
6843
6864
|
|
|
6865
|
+
class Soundex(Func):
|
|
6866
|
+
pass
|
|
6867
|
+
|
|
6868
|
+
|
|
6844
6869
|
class Split(Func):
|
|
6845
6870
|
arg_types = {"this": True, "expression": True, "limit": False}
|
|
6846
6871
|
|
sqlglot/generator.py
CHANGED
|
@@ -692,6 +692,8 @@ class Generator(metaclass=_Generator):
|
|
|
692
692
|
|
|
693
693
|
RESPECT_IGNORE_NULLS_UNSUPPORTED_EXPRESSIONS: t.Tuple[t.Type[exp.Expression], ...] = ()
|
|
694
694
|
|
|
695
|
+
SAFE_JSON_PATH_KEY_RE = exp.SAFE_IDENTIFIER_RE
|
|
696
|
+
|
|
695
697
|
SENTINEL_LINE_BREAK = "__SQLGLOT__LB__"
|
|
696
698
|
|
|
697
699
|
__slots__ = (
|
|
@@ -4362,7 +4364,7 @@ class Generator(metaclass=_Generator):
|
|
|
4362
4364
|
this = self.json_path_part(this)
|
|
4363
4365
|
return f".{this}" if this else ""
|
|
4364
4366
|
|
|
4365
|
-
if
|
|
4367
|
+
if self.SAFE_JSON_PATH_KEY_RE.match(this):
|
|
4366
4368
|
return f".{this}"
|
|
4367
4369
|
|
|
4368
4370
|
this = self.json_path_part(this)
|
|
@@ -5146,3 +5148,6 @@ class Generator(metaclass=_Generator):
|
|
|
5146
5148
|
unit=exp.var("DAY"),
|
|
5147
5149
|
)
|
|
5148
5150
|
)
|
|
5151
|
+
|
|
5152
|
+
def space_sql(self: Generator, expression: exp.Space) -> str:
|
|
5153
|
+
return self.sql(exp.Repeat(this=exp.Literal.string(" "), times=expression.this))
|
sqlglot/jsonpath.py
CHANGED
|
@@ -36,6 +36,10 @@ class JSONPathTokenizer(Tokenizer):
|
|
|
36
36
|
IDENTIFIER_ESCAPES = ["\\"]
|
|
37
37
|
STRING_ESCAPES = ["\\"]
|
|
38
38
|
|
|
39
|
+
VAR_TOKENS = {
|
|
40
|
+
TokenType.VAR,
|
|
41
|
+
}
|
|
42
|
+
|
|
39
43
|
|
|
40
44
|
def parse(path: str, dialect: DialectType = None) -> exp.JSONPath:
|
|
41
45
|
"""Takes in a JSON path string and parses it into a JSONPath expression."""
|
|
@@ -76,6 +80,9 @@ def parse(path: str, dialect: DialectType = None) -> exp.JSONPath:
|
|
|
76
80
|
raise ParseError(_error(f"Expected {token_type}"))
|
|
77
81
|
return None
|
|
78
82
|
|
|
83
|
+
def _match_set(types: t.Collection[TokenType]) -> t.Optional[Token]:
|
|
84
|
+
return _advance() if _curr() in types else None
|
|
85
|
+
|
|
79
86
|
def _parse_literal() -> t.Any:
|
|
80
87
|
token = _match(TokenType.STRING) or _match(TokenType.IDENTIFIER)
|
|
81
88
|
if token:
|
|
@@ -155,7 +162,7 @@ def parse(path: str, dialect: DialectType = None) -> exp.JSONPath:
|
|
|
155
162
|
"""
|
|
156
163
|
prev_index = i - 2
|
|
157
164
|
|
|
158
|
-
while
|
|
165
|
+
while _match_set(jsonpath_tokenizer.VAR_TOKENS):
|
|
159
166
|
pass
|
|
160
167
|
|
|
161
168
|
start = 0 if prev_index < 0 else tokens[prev_index].end + 1
|
|
@@ -177,7 +184,7 @@ def parse(path: str, dialect: DialectType = None) -> exp.JSONPath:
|
|
|
177
184
|
if _match(TokenType.DOT) or _match(TokenType.COLON):
|
|
178
185
|
recursive = _prev().text == ".."
|
|
179
186
|
|
|
180
|
-
if
|
|
187
|
+
if _match_set(jsonpath_tokenizer.VAR_TOKENS):
|
|
181
188
|
value: t.Optional[str | exp.JSONPathWildcard] = _parse_var_text()
|
|
182
189
|
elif _match(TokenType.IDENTIFIER):
|
|
183
190
|
value = _prev().text
|
|
@@ -194,7 +201,7 @@ def parse(path: str, dialect: DialectType = None) -> exp.JSONPath:
|
|
|
194
201
|
raise ParseError(_error("Expected key name or * after DOT"))
|
|
195
202
|
elif _match(TokenType.L_BRACKET):
|
|
196
203
|
expressions.append(_parse_bracket())
|
|
197
|
-
elif
|
|
204
|
+
elif _match_set(jsonpath_tokenizer.VAR_TOKENS):
|
|
198
205
|
expressions.append(exp.JSONPathKey(this=_parse_var_text()))
|
|
199
206
|
elif _match(TokenType.IDENTIFIER):
|
|
200
207
|
expressions.append(exp.JSONPathKey(this=_prev().text))
|
sqlglot/parser.py
CHANGED
|
@@ -577,7 +577,6 @@ class Parser(metaclass=_Parser):
|
|
|
577
577
|
|
|
578
578
|
TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
|
|
579
579
|
TokenType.ANTI,
|
|
580
|
-
TokenType.APPLY,
|
|
581
580
|
TokenType.ASOF,
|
|
582
581
|
TokenType.FULL,
|
|
583
582
|
TokenType.LEFT,
|
|
@@ -8708,3 +8707,18 @@ class Parser(metaclass=_Parser):
|
|
|
8708
8707
|
kwargs["requires_string"] = self.dialect.TRY_CAST_REQUIRES_STRING
|
|
8709
8708
|
|
|
8710
8709
|
return self.expression(exp_class, **kwargs)
|
|
8710
|
+
|
|
8711
|
+
def _parse_json_value(self) -> exp.JSONValue:
|
|
8712
|
+
this = self._parse_bitwise()
|
|
8713
|
+
self._match(TokenType.COMMA)
|
|
8714
|
+
path = self._parse_bitwise()
|
|
8715
|
+
|
|
8716
|
+
returning = self._match(TokenType.RETURNING) and self._parse_type()
|
|
8717
|
+
|
|
8718
|
+
return self.expression(
|
|
8719
|
+
exp.JSONValue,
|
|
8720
|
+
this=this,
|
|
8721
|
+
path=self.dialect.to_json_path(path),
|
|
8722
|
+
returning=returning,
|
|
8723
|
+
on_condition=self._parse_on_condition(),
|
|
8724
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlglot
|
|
3
|
-
Version: 27.
|
|
3
|
+
Version: 27.8.0
|
|
4
4
|
Summary: An easily customizable SQL parser and transpiler
|
|
5
5
|
Author-email: Toby Mao <toby.mao@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://sqlglot.com/
|
|
@@ -256,7 +256,7 @@ sqlglot.errors.ParseError: Expecting ). Line 1, Col: 34.
|
|
|
256
256
|
Structured syntax errors are accessible for programmatic use:
|
|
257
257
|
|
|
258
258
|
```python
|
|
259
|
-
import sqlglot
|
|
259
|
+
import sqlglot.errors
|
|
260
260
|
try:
|
|
261
261
|
sqlglot.transpile("SELECT foo FROM (SELECT baz FROM t")
|
|
262
262
|
except sqlglot.errors.ParseError as e:
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
sqlglot/__init__.py,sha256=za08rtdPh2v7dOpGdNomttlIVGgTrKja7rPd6sQwaTg,5391
|
|
2
2
|
sqlglot/__main__.py,sha256=022c173KqxsiABWTEpUIq_tJUxuNiW7a7ABsxBXqvu8,2069
|
|
3
3
|
sqlglot/_typing.py,sha256=-1HPyr3w5COlSJWqlgt8jhFk2dyMvBuvVBqIX1wyVCM,642
|
|
4
|
-
sqlglot/_version.py,sha256=
|
|
4
|
+
sqlglot/_version.py,sha256=6Bcdz-xEd_4XJzvpG14av5V0A6AT1_hYMo5MIczQYNw,706
|
|
5
5
|
sqlglot/diff.py,sha256=PtOllQMQa1Sw1-V2Y8eypmDqGujXYPaTOp_WLsWkAWk,17314
|
|
6
6
|
sqlglot/errors.py,sha256=QNKMr-pzLUDR-tuMmn_GK6iMHUIVdb_YSJ_BhGEvuso,2126
|
|
7
|
-
sqlglot/expressions.py,sha256=
|
|
8
|
-
sqlglot/generator.py,sha256=
|
|
7
|
+
sqlglot/expressions.py,sha256=qtKgdbejSFXnsDcIZ8XT6wR6EXrtru7U2G4edUyVzU4,247540
|
|
8
|
+
sqlglot/generator.py,sha256=KXHnyJQKSq2Xy5RBDC-6GAW_zJqcNsHhZFV4P13l_iU,219354
|
|
9
9
|
sqlglot/helper.py,sha256=9nZjFVRBtMKFC3EdzpDQ6jkazFO19po6BF8xHiNGZIo,15111
|
|
10
|
-
sqlglot/jsonpath.py,sha256=
|
|
10
|
+
sqlglot/jsonpath.py,sha256=SQgaxzaEYBN7At9dkTK4N1Spk6xHxvHL6QtCIP6iM30,7905
|
|
11
11
|
sqlglot/lineage.py,sha256=Qj5ykuDNcATppb9vOjoIKBqRVLbu3OMPiZk9f3iyv40,15312
|
|
12
|
-
sqlglot/parser.py,sha256=
|
|
12
|
+
sqlglot/parser.py,sha256=3DexBAzFLyrg4eEgNffcHB9d1ugwsxrFoZBWttRnmto,329221
|
|
13
13
|
sqlglot/planner.py,sha256=ql7Li-bWJRcyXzNaZy_n6bQ6B2ZfunEIB8Ztv2xaxq4,14634
|
|
14
14
|
sqlglot/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
sqlglot/schema.py,sha256=13H2qKQs27EKdTpDLOvcNnSTDAUbYNKjWtJs4aQCSOA,20509
|
|
@@ -20,36 +20,36 @@ sqlglot/transforms.py,sha256=utNDsCBsA7hPUK3-aby3DDgiY_XVMAKQqeoLm1EyihI,41218
|
|
|
20
20
|
sqlglot/trie.py,sha256=v27uXMrHfqrXlJ6GmeTSMovsB_3o0ctnlKhdNt7W6fI,2245
|
|
21
21
|
sqlglot/dialects/__init__.py,sha256=BQUv9EuMmvhP_wVitGLo0PlCi15atvfXgvREpsTsxeQ,3799
|
|
22
22
|
sqlglot/dialects/athena.py,sha256=ofArmayYLev4qZQ15GM8mevG04qqR5WGFb2ZcuYm6x4,10966
|
|
23
|
-
sqlglot/dialects/bigquery.py,sha256=
|
|
23
|
+
sqlglot/dialects/bigquery.py,sha256=OAzuqTOGti3_US_oa0s0LWP56LjBaxTJ1B8tVZBgwVY,59733
|
|
24
24
|
sqlglot/dialects/clickhouse.py,sha256=ygkVXh8fAxQ2sPvsDIP3y-1bUxV2PSLeS-983MI1uKs,57780
|
|
25
|
-
sqlglot/dialects/databricks.py,sha256=
|
|
26
|
-
sqlglot/dialects/dialect.py,sha256=
|
|
25
|
+
sqlglot/dialects/databricks.py,sha256=761qPlGOFHa9V8mdQYNAEw0pv4HUJYMkGEuFsdsLC7s,4714
|
|
26
|
+
sqlglot/dialects/dialect.py,sha256=QXis6e9a0jX02QbtqpEKGXDY-gWa46EWOv14k9TE_zE,73001
|
|
27
27
|
sqlglot/dialects/doris.py,sha256=HT3NyPORz8E1Kk6nNT00CEe4cwz1CfXGhhBcg8Hht1s,21709
|
|
28
|
-
sqlglot/dialects/dremio.py,sha256=
|
|
28
|
+
sqlglot/dialects/dremio.py,sha256=opJ6QbsJJwhJRH4josxwkw28M_ABgP6zMY30-A6JFdg,5189
|
|
29
29
|
sqlglot/dialects/drill.py,sha256=FOh7_KjPx_77pv0DiHKZog0CcmzqeF9_PEmGnJ1ESSM,5825
|
|
30
30
|
sqlglot/dialects/druid.py,sha256=kh3snZtneehNOWqs3XcPjsrhNaRbkCQ8E4hHbWJ1fHM,690
|
|
31
|
-
sqlglot/dialects/duckdb.py,sha256=
|
|
31
|
+
sqlglot/dialects/duckdb.py,sha256=YUne3dZOD-nRlf_JGK5EcT_DJt9I0w7byeYuPcXvKvo,51894
|
|
32
32
|
sqlglot/dialects/dune.py,sha256=gALut-fFfN2qMsr8LvZ1NQK3F3W9z2f4PwMvTMXVVVg,375
|
|
33
|
-
sqlglot/dialects/exasol.py,sha256=
|
|
33
|
+
sqlglot/dialects/exasol.py,sha256=vvoL5QcPF6eBoXuZF_iRc_VpF0OviRNjtWD0ER59xqI,14554
|
|
34
34
|
sqlglot/dialects/fabric.py,sha256=4Sng2ZhQSaf6eK3ituR9DqDZERaVwYS_UfdpusjsISg,10220
|
|
35
35
|
sqlglot/dialects/hive.py,sha256=bAZz0qnaOH9f5FyIMkqBu3XB2Cj7y-xnCPbxPsk8U9I,31959
|
|
36
36
|
sqlglot/dialects/materialize.py,sha256=LD2q1kTRrCwkIu1BfoBvnjTGbupDtoQ8JQMDCIYAXHg,3533
|
|
37
|
-
sqlglot/dialects/mysql.py,sha256=
|
|
37
|
+
sqlglot/dialects/mysql.py,sha256=ds_dsTw1ZzsoW0tRbxpKOB9fVaIpXb9t1Hqa9n5MGX0,48764
|
|
38
38
|
sqlglot/dialects/oracle.py,sha256=DpckKjR3FauVmXDIDaNTFqJE0KzXnW4sUlnZjQC8z0Y,15735
|
|
39
39
|
sqlglot/dialects/postgres.py,sha256=8QF9uEXXFAGCXQah1n8mv4fonF58o0n59Il66hOZYqI,33942
|
|
40
|
-
sqlglot/dialects/presto.py,sha256=
|
|
40
|
+
sqlglot/dialects/presto.py,sha256=XVeYr2NP86x5enlRqI7MYR6le85_ucYg_BBRocGN3jM,33413
|
|
41
41
|
sqlglot/dialects/prql.py,sha256=fwN-SPEGx-drwf1K0U2MByN-PkW3C_rOgQ3xeJeychg,7908
|
|
42
42
|
sqlglot/dialects/redshift.py,sha256=MXI9W7CgKCtMNjNRPcZPxO8NBA9_PxZx14HB52o-aUc,15822
|
|
43
43
|
sqlglot/dialects/risingwave.py,sha256=BqWwW1iT_OIVMwfRamaww79snnBwIgCfr22Go-ggO68,3289
|
|
44
|
-
sqlglot/dialects/singlestore.py,sha256=
|
|
44
|
+
sqlglot/dialects/singlestore.py,sha256=FQzHqeFQd_nBisCIcUK4-4cbLr8bjnAcbVNN7LI7HPk,35533
|
|
45
45
|
sqlglot/dialects/snowflake.py,sha256=XPsqYGBjn3dfddF2dcuM7Ur-4sYdthjW7cSPnptWq_s,70542
|
|
46
|
-
sqlglot/dialects/spark.py,sha256=
|
|
46
|
+
sqlglot/dialects/spark.py,sha256=5dKMb9cGl0GMreEyFfjClvW1Cwm1JEx3W-hFnxjqW8E,9362
|
|
47
47
|
sqlglot/dialects/spark2.py,sha256=aCwPqLduLRSUSPtbI1VtBjydK6haKgEy3iahmueGRo4,14742
|
|
48
48
|
sqlglot/dialects/sqlite.py,sha256=XIDmiNTswWcrDwlFm8gOODCrJ_rPmXQKkm9U_-YAlVs,13183
|
|
49
49
|
sqlglot/dialects/starrocks.py,sha256=2gav0PSNgRdAGXzawdznZliBpglJoQ0wBxPI7ZIMsRw,11314
|
|
50
50
|
sqlglot/dialects/tableau.py,sha256=oIawDzUITxGCWaEMB8OaNMPWhbC3U-2y09pYPm4eazc,2190
|
|
51
51
|
sqlglot/dialects/teradata.py,sha256=7LxCcRwP0Idd_OnCzA57NCdheVjHcKC2aFAKG5N49IU,18202
|
|
52
|
-
sqlglot/dialects/trino.py,sha256=
|
|
52
|
+
sqlglot/dialects/trino.py,sha256=Z7prRhCxIBh0KCxIQpWmVOIGHCJM9Xl5oRlqySxln4Y,4350
|
|
53
53
|
sqlglot/dialects/tsql.py,sha256=sz1t79iCcsMXw8PKYnKldZJbAQ2iobNsqLPVAj-QTXk,54036
|
|
54
54
|
sqlglot/executor/__init__.py,sha256=FslewzYQtQdDNg_0Ju2UaiP4vo4IMUgkfkmFsYUhcN0,2958
|
|
55
55
|
sqlglot/executor/context.py,sha256=WJHJdYQCOeVXwLw0uSSrWSc25eBMn5Ix108RCvdsKRQ,3386
|
|
@@ -76,8 +76,8 @@ sqlglot/optimizer/qualify_tables.py,sha256=dA4ZazL7ShQh2JgBwpHuG-4c5lBw1TNzCnuN7
|
|
|
76
76
|
sqlglot/optimizer/scope.py,sha256=T6iVYnYwubt-WB1BOFsFYdJ-D7WtWZGL37SuCRQK23s,31154
|
|
77
77
|
sqlglot/optimizer/simplify.py,sha256=-_yus42OYwqjQ9a2TSGhtG2G0pSkInUry1z7hEMz2pY,51062
|
|
78
78
|
sqlglot/optimizer/unnest_subqueries.py,sha256=kzWUVDlxs8z9nmRx-8U-pHXPtVZhEIwkKqmKhr2QLvc,10908
|
|
79
|
-
sqlglot-27.
|
|
80
|
-
sqlglot-27.
|
|
81
|
-
sqlglot-27.
|
|
82
|
-
sqlglot-27.
|
|
83
|
-
sqlglot-27.
|
|
79
|
+
sqlglot-27.8.0.dist-info/licenses/LICENSE,sha256=p1Yk0B4oa0l8Rh-_dYyy75d8spjPd_vTloXfz4FWxys,1065
|
|
80
|
+
sqlglot-27.8.0.dist-info/METADATA,sha256=wmjTJpMM7ieiqzI1z-VsjfHD7NH6NzBycgCo0Of-OgY,19444
|
|
81
|
+
sqlglot-27.8.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
82
|
+
sqlglot-27.8.0.dist-info/top_level.txt,sha256=5kRskCGA_gVADF9rSfSzPdLHXqvfMusDYeHePfNY2nQ,8
|
|
83
|
+
sqlglot-27.8.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|