sqlglot 27.7.0__py3-none-any.whl → 27.9.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/__init__.py +1 -1
- sqlglot/dialects/bigquery.py +129 -9
- sqlglot/dialects/clickhouse.py +11 -0
- sqlglot/dialects/databricks.py +5 -1
- sqlglot/dialects/dialect.py +74 -23
- sqlglot/dialects/doris.py +77 -9
- sqlglot/dialects/dremio.py +102 -21
- sqlglot/dialects/duckdb.py +20 -43
- sqlglot/dialects/exasol.py +28 -0
- sqlglot/dialects/mysql.py +0 -48
- sqlglot/dialects/presto.py +0 -2
- sqlglot/dialects/redshift.py +1 -0
- sqlglot/dialects/singlestore.py +252 -13
- sqlglot/dialects/spark.py +6 -0
- sqlglot/dialects/trino.py +1 -0
- sqlglot/dialects/tsql.py +2 -0
- sqlglot/expressions.py +143 -7
- sqlglot/generator.py +98 -27
- sqlglot/jsonpath.py +10 -3
- sqlglot/optimizer/qualify_columns.py +1 -1
- sqlglot/parser.py +58 -17
- {sqlglot-27.7.0.dist-info → sqlglot-27.9.0.dist-info}/METADATA +42 -2
- {sqlglot-27.7.0.dist-info → sqlglot-27.9.0.dist-info}/RECORD +27 -27
- {sqlglot-27.7.0.dist-info → sqlglot-27.9.0.dist-info}/WHEEL +0 -0
- {sqlglot-27.7.0.dist-info → sqlglot-27.9.0.dist-info}/licenses/LICENSE +0 -0
- {sqlglot-27.7.0.dist-info → sqlglot-27.9.0.dist-info}/top_level.txt +0 -0
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__ = (
|
|
@@ -1135,14 +1137,14 @@ class Generator(metaclass=_Generator):
|
|
|
1135
1137
|
if properties_locs.get(exp.Properties.Location.POST_SCHEMA) or properties_locs.get(
|
|
1136
1138
|
exp.Properties.Location.POST_WITH
|
|
1137
1139
|
):
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
]
|
|
1144
|
-
)
|
|
1140
|
+
props_ast = exp.Properties(
|
|
1141
|
+
expressions=[
|
|
1142
|
+
*properties_locs[exp.Properties.Location.POST_SCHEMA],
|
|
1143
|
+
*properties_locs[exp.Properties.Location.POST_WITH],
|
|
1144
|
+
]
|
|
1145
1145
|
)
|
|
1146
|
+
props_ast.parent = expression
|
|
1147
|
+
properties_sql = self.sql(props_ast)
|
|
1146
1148
|
|
|
1147
1149
|
if properties_locs.get(exp.Properties.Location.POST_SCHEMA):
|
|
1148
1150
|
properties_sql = self.sep() + properties_sql
|
|
@@ -1668,8 +1670,14 @@ class Generator(metaclass=_Generator):
|
|
|
1668
1670
|
elif p_loc == exp.Properties.Location.POST_SCHEMA:
|
|
1669
1671
|
root_properties.append(p)
|
|
1670
1672
|
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
+
root_props_ast = exp.Properties(expressions=root_properties)
|
|
1674
|
+
root_props_ast.parent = expression.parent
|
|
1675
|
+
|
|
1676
|
+
with_props_ast = exp.Properties(expressions=with_properties)
|
|
1677
|
+
with_props_ast.parent = expression.parent
|
|
1678
|
+
|
|
1679
|
+
root_props = self.root_properties(root_props_ast)
|
|
1680
|
+
with_props = self.with_properties(with_props_ast)
|
|
1673
1681
|
|
|
1674
1682
|
if root_props and with_props and not self.pretty:
|
|
1675
1683
|
with_props = " " + with_props
|
|
@@ -2990,7 +2998,19 @@ class Generator(metaclass=_Generator):
|
|
|
2990
2998
|
args = [exp.cast(e, exp.DataType.Type.TEXT) for e in args]
|
|
2991
2999
|
|
|
2992
3000
|
if not self.dialect.CONCAT_COALESCE and expression.args.get("coalesce"):
|
|
2993
|
-
|
|
3001
|
+
|
|
3002
|
+
def _wrap_with_coalesce(e: exp.Expression) -> exp.Expression:
|
|
3003
|
+
if not e.type:
|
|
3004
|
+
from sqlglot.optimizer.annotate_types import annotate_types
|
|
3005
|
+
|
|
3006
|
+
e = annotate_types(e, dialect=self.dialect)
|
|
3007
|
+
|
|
3008
|
+
if e.is_string or e.is_type(exp.DataType.Type.ARRAY):
|
|
3009
|
+
return e
|
|
3010
|
+
|
|
3011
|
+
return exp.func("coalesce", e, exp.Literal.string(""))
|
|
3012
|
+
|
|
3013
|
+
args = [_wrap_with_coalesce(e) for e in args]
|
|
2994
3014
|
|
|
2995
3015
|
return args
|
|
2996
3016
|
|
|
@@ -3541,8 +3561,9 @@ class Generator(metaclass=_Generator):
|
|
|
3541
3561
|
options = f", {options}" if options else ""
|
|
3542
3562
|
kind = self.sql(expression, "kind")
|
|
3543
3563
|
not_valid = " NOT VALID" if expression.args.get("not_valid") else ""
|
|
3564
|
+
check = " WITH CHECK" if expression.args.get("check") else ""
|
|
3544
3565
|
|
|
3545
|
-
return f"ALTER {kind}{exists}{only} {self.sql(expression, 'this')}{on_cluster}{self.sep()}{actions_sql}{not_valid}{options}"
|
|
3566
|
+
return f"ALTER {kind}{exists}{only} {self.sql(expression, 'this')}{on_cluster}{check}{self.sep()}{actions_sql}{not_valid}{options}"
|
|
3546
3567
|
|
|
3547
3568
|
def add_column_sql(self, expression: exp.Expression) -> str:
|
|
3548
3569
|
sql = self.sql(expression)
|
|
@@ -4027,8 +4048,10 @@ class Generator(metaclass=_Generator):
|
|
|
4027
4048
|
return f"DUPLICATE KEY ({self.expressions(expression, flat=True)})"
|
|
4028
4049
|
|
|
4029
4050
|
# https://docs.starrocks.io/docs/sql-reference/sql-statements/table_bucket_part_index/CREATE_TABLE/
|
|
4030
|
-
def uniquekeyproperty_sql(
|
|
4031
|
-
|
|
4051
|
+
def uniquekeyproperty_sql(
|
|
4052
|
+
self, expression: exp.UniqueKeyProperty, prefix: str = "UNIQUE KEY"
|
|
4053
|
+
) -> str:
|
|
4054
|
+
return f"{prefix} ({self.expressions(expression, flat=True)})"
|
|
4032
4055
|
|
|
4033
4056
|
# https://docs.starrocks.io/docs/sql-reference/sql-statements/data-definition/CREATE_TABLE/#distribution_desc
|
|
4034
4057
|
def distributedbyproperty_sql(self, expression: exp.DistributedByProperty) -> str:
|
|
@@ -4160,6 +4183,47 @@ class Generator(metaclass=_Generator):
|
|
|
4160
4183
|
parameters = self.sql(expression, "params_struct")
|
|
4161
4184
|
return self.func("PREDICT", model, table, parameters or None)
|
|
4162
4185
|
|
|
4186
|
+
def generateembedding_sql(self, expression: exp.GenerateEmbedding) -> str:
|
|
4187
|
+
model = self.sql(expression, "this")
|
|
4188
|
+
model = f"MODEL {model}"
|
|
4189
|
+
table = self.sql(expression, "expression")
|
|
4190
|
+
table = f"TABLE {table}" if not isinstance(expression.expression, exp.Subquery) else table
|
|
4191
|
+
parameters = self.sql(expression, "params_struct")
|
|
4192
|
+
return self.func("GENERATE_EMBEDDING", model, table, parameters or None)
|
|
4193
|
+
|
|
4194
|
+
def featuresattime_sql(self, expression: exp.FeaturesAtTime) -> str:
|
|
4195
|
+
this_sql = self.sql(expression, "this")
|
|
4196
|
+
if isinstance(expression.this, exp.Table):
|
|
4197
|
+
this_sql = f"TABLE {this_sql}"
|
|
4198
|
+
|
|
4199
|
+
return self.func(
|
|
4200
|
+
"FEATURES_AT_TIME",
|
|
4201
|
+
this_sql,
|
|
4202
|
+
expression.args.get("time"),
|
|
4203
|
+
expression.args.get("num_rows"),
|
|
4204
|
+
expression.args.get("ignore_feature_nulls"),
|
|
4205
|
+
)
|
|
4206
|
+
|
|
4207
|
+
def vectorsearch_sql(self, expression: exp.VectorSearch) -> str:
|
|
4208
|
+
this_sql = self.sql(expression, "this")
|
|
4209
|
+
if isinstance(expression.this, exp.Table):
|
|
4210
|
+
this_sql = f"TABLE {this_sql}"
|
|
4211
|
+
|
|
4212
|
+
query_table = self.sql(expression, "query_table")
|
|
4213
|
+
if isinstance(expression.args["query_table"], exp.Table):
|
|
4214
|
+
query_table = f"TABLE {query_table}"
|
|
4215
|
+
|
|
4216
|
+
return self.func(
|
|
4217
|
+
"VECTOR_SEARCH",
|
|
4218
|
+
this_sql,
|
|
4219
|
+
expression.args.get("column_to_search"),
|
|
4220
|
+
query_table,
|
|
4221
|
+
expression.args.get("query_column_to_search"),
|
|
4222
|
+
expression.args.get("top_k"),
|
|
4223
|
+
expression.args.get("distance_type"),
|
|
4224
|
+
expression.args.get("options"),
|
|
4225
|
+
)
|
|
4226
|
+
|
|
4163
4227
|
def forin_sql(self, expression: exp.ForIn) -> str:
|
|
4164
4228
|
this = self.sql(expression, "this")
|
|
4165
4229
|
expression_sql = self.sql(expression, "expression")
|
|
@@ -4362,7 +4426,7 @@ class Generator(metaclass=_Generator):
|
|
|
4362
4426
|
this = self.json_path_part(this)
|
|
4363
4427
|
return f".{this}" if this else ""
|
|
4364
4428
|
|
|
4365
|
-
if
|
|
4429
|
+
if self.SAFE_JSON_PATH_KEY_RE.match(this):
|
|
4366
4430
|
return f".{this}"
|
|
4367
4431
|
|
|
4368
4432
|
this = self.json_path_part(this)
|
|
@@ -4867,19 +4931,6 @@ class Generator(metaclass=_Generator):
|
|
|
4867
4931
|
value = f" {value}" if value else ""
|
|
4868
4932
|
return f"{this}{value}"
|
|
4869
4933
|
|
|
4870
|
-
def featuresattime_sql(self, expression: exp.FeaturesAtTime) -> str:
|
|
4871
|
-
this_sql = self.sql(expression, "this")
|
|
4872
|
-
if isinstance(expression.this, exp.Table):
|
|
4873
|
-
this_sql = f"TABLE {this_sql}"
|
|
4874
|
-
|
|
4875
|
-
return self.func(
|
|
4876
|
-
"FEATURES_AT_TIME",
|
|
4877
|
-
this_sql,
|
|
4878
|
-
expression.args.get("time"),
|
|
4879
|
-
expression.args.get("num_rows"),
|
|
4880
|
-
expression.args.get("ignore_feature_nulls"),
|
|
4881
|
-
)
|
|
4882
|
-
|
|
4883
4934
|
def watermarkcolumnconstraint_sql(self, expression: exp.WatermarkColumnConstraint) -> str:
|
|
4884
4935
|
return (
|
|
4885
4936
|
f"WATERMARK FOR {self.sql(expression, 'this')} AS {self.sql(expression, 'expression')}"
|
|
@@ -5146,3 +5197,23 @@ class Generator(metaclass=_Generator):
|
|
|
5146
5197
|
unit=exp.var("DAY"),
|
|
5147
5198
|
)
|
|
5148
5199
|
)
|
|
5200
|
+
|
|
5201
|
+
def space_sql(self: Generator, expression: exp.Space) -> str:
|
|
5202
|
+
return self.sql(exp.Repeat(this=exp.Literal.string(" "), times=expression.this))
|
|
5203
|
+
|
|
5204
|
+
def buildproperty_sql(self, expression: exp.BuildProperty) -> str:
|
|
5205
|
+
return f"BUILD {self.sql(expression, 'this')}"
|
|
5206
|
+
|
|
5207
|
+
def refreshtriggerproperty_sql(self, expression: exp.RefreshTriggerProperty) -> str:
|
|
5208
|
+
method = self.sql(expression, "method")
|
|
5209
|
+
kind = expression.args.get("kind")
|
|
5210
|
+
if not kind:
|
|
5211
|
+
return f"REFRESH {method}"
|
|
5212
|
+
|
|
5213
|
+
every = self.sql(expression, "every")
|
|
5214
|
+
unit = self.sql(expression, "unit")
|
|
5215
|
+
every = f" EVERY {every} {unit}" if every else ""
|
|
5216
|
+
starts = self.sql(expression, "starts")
|
|
5217
|
+
starts = f" STARTS {starts}" if starts else ""
|
|
5218
|
+
|
|
5219
|
+
return f"REFRESH {method} ON {kind}{every}{starts}"
|
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))
|
|
@@ -853,7 +853,7 @@ def qualify_outputs(scope_or_expression: Scope | exp.Expression) -> None:
|
|
|
853
853
|
if isinstance(selection, exp.Subquery):
|
|
854
854
|
if not selection.output_name:
|
|
855
855
|
selection.set("alias", exp.TableAlias(this=exp.to_identifier(f"_col_{i}")))
|
|
856
|
-
elif not isinstance(selection, exp.Alias) and not selection.is_star:
|
|
856
|
+
elif not isinstance(selection, (exp.Alias, exp.Aliases)) and not selection.is_star:
|
|
857
857
|
selection = alias(
|
|
858
858
|
selection,
|
|
859
859
|
alias=selection.output_name or f"_col_{i}",
|
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,
|
|
@@ -1245,7 +1244,6 @@ class Parser(metaclass=_Parser):
|
|
|
1245
1244
|
"OPENJSON": lambda self: self._parse_open_json(),
|
|
1246
1245
|
"OVERLAY": lambda self: self._parse_overlay(),
|
|
1247
1246
|
"POSITION": lambda self: self._parse_position(),
|
|
1248
|
-
"PREDICT": lambda self: self._parse_predict(),
|
|
1249
1247
|
"SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
|
|
1250
1248
|
"STRING_AGG": lambda self: self._parse_string_agg(),
|
|
1251
1249
|
"SUBSTRING": lambda self: self._parse_substring(),
|
|
@@ -3534,10 +3532,17 @@ class Parser(metaclass=_Parser):
|
|
|
3534
3532
|
|
|
3535
3533
|
while True:
|
|
3536
3534
|
if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
|
|
3537
|
-
|
|
3535
|
+
modifier_token = self._curr
|
|
3536
|
+
parser = self.QUERY_MODIFIER_PARSERS[modifier_token.token_type]
|
|
3538
3537
|
key, expression = parser(self)
|
|
3539
3538
|
|
|
3540
3539
|
if expression:
|
|
3540
|
+
if this.args.get(key):
|
|
3541
|
+
self.raise_error(
|
|
3542
|
+
f"Found multiple '{modifier_token.text.upper()}' clauses",
|
|
3543
|
+
token=modifier_token,
|
|
3544
|
+
)
|
|
3545
|
+
|
|
3541
3546
|
this.set(key, expression)
|
|
3542
3547
|
if key == "limit":
|
|
3543
3548
|
offset = expression.args.pop("offset", None)
|
|
@@ -6915,20 +6920,6 @@ class Parser(metaclass=_Parser):
|
|
|
6915
6920
|
exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
|
|
6916
6921
|
)
|
|
6917
6922
|
|
|
6918
|
-
def _parse_predict(self) -> exp.Predict:
|
|
6919
|
-
self._match_text_seq("MODEL")
|
|
6920
|
-
this = self._parse_table()
|
|
6921
|
-
|
|
6922
|
-
self._match(TokenType.COMMA)
|
|
6923
|
-
self._match_text_seq("TABLE")
|
|
6924
|
-
|
|
6925
|
-
return self.expression(
|
|
6926
|
-
exp.Predict,
|
|
6927
|
-
this=this,
|
|
6928
|
-
expression=self._parse_table(),
|
|
6929
|
-
params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
|
|
6930
|
-
)
|
|
6931
|
-
|
|
6932
6923
|
def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
|
|
6933
6924
|
args = self._parse_csv(self._parse_table)
|
|
6934
6925
|
return exp.JoinHint(this=func_name.upper(), expressions=args)
|
|
@@ -7598,6 +7589,7 @@ class Parser(metaclass=_Parser):
|
|
|
7598
7589
|
exists = self._parse_exists()
|
|
7599
7590
|
only = self._match_text_seq("ONLY")
|
|
7600
7591
|
this = self._parse_table(schema=True)
|
|
7592
|
+
check = self._match_text_seq("WITH", "CHECK")
|
|
7601
7593
|
cluster = self._parse_on_property() if self._match(TokenType.ON) else None
|
|
7602
7594
|
|
|
7603
7595
|
if self._next:
|
|
@@ -7620,6 +7612,7 @@ class Parser(metaclass=_Parser):
|
|
|
7620
7612
|
options=options,
|
|
7621
7613
|
cluster=cluster,
|
|
7622
7614
|
not_valid=not_valid,
|
|
7615
|
+
check=check,
|
|
7623
7616
|
)
|
|
7624
7617
|
|
|
7625
7618
|
return self._parse_as_command(start)
|
|
@@ -8708,3 +8701,51 @@ class Parser(metaclass=_Parser):
|
|
|
8708
8701
|
kwargs["requires_string"] = self.dialect.TRY_CAST_REQUIRES_STRING
|
|
8709
8702
|
|
|
8710
8703
|
return self.expression(exp_class, **kwargs)
|
|
8704
|
+
|
|
8705
|
+
def _parse_json_value(self) -> exp.JSONValue:
|
|
8706
|
+
this = self._parse_bitwise()
|
|
8707
|
+
self._match(TokenType.COMMA)
|
|
8708
|
+
path = self._parse_bitwise()
|
|
8709
|
+
|
|
8710
|
+
returning = self._match(TokenType.RETURNING) and self._parse_type()
|
|
8711
|
+
|
|
8712
|
+
return self.expression(
|
|
8713
|
+
exp.JSONValue,
|
|
8714
|
+
this=this,
|
|
8715
|
+
path=self.dialect.to_json_path(path),
|
|
8716
|
+
returning=returning,
|
|
8717
|
+
on_condition=self._parse_on_condition(),
|
|
8718
|
+
)
|
|
8719
|
+
|
|
8720
|
+
def _parse_group_concat(self) -> t.Optional[exp.Expression]:
|
|
8721
|
+
def concat_exprs(
|
|
8722
|
+
node: t.Optional[exp.Expression], exprs: t.List[exp.Expression]
|
|
8723
|
+
) -> exp.Expression:
|
|
8724
|
+
if isinstance(node, exp.Distinct) and len(node.expressions) > 1:
|
|
8725
|
+
concat_exprs = [
|
|
8726
|
+
self.expression(exp.Concat, expressions=node.expressions, safe=True)
|
|
8727
|
+
]
|
|
8728
|
+
node.set("expressions", concat_exprs)
|
|
8729
|
+
return node
|
|
8730
|
+
if len(exprs) == 1:
|
|
8731
|
+
return exprs[0]
|
|
8732
|
+
return self.expression(exp.Concat, expressions=args, safe=True)
|
|
8733
|
+
|
|
8734
|
+
args = self._parse_csv(self._parse_lambda)
|
|
8735
|
+
|
|
8736
|
+
if args:
|
|
8737
|
+
order = args[-1] if isinstance(args[-1], exp.Order) else None
|
|
8738
|
+
|
|
8739
|
+
if order:
|
|
8740
|
+
# Order By is the last (or only) expression in the list and has consumed the 'expr' before it,
|
|
8741
|
+
# remove 'expr' from exp.Order and add it back to args
|
|
8742
|
+
args[-1] = order.this
|
|
8743
|
+
order.set("this", concat_exprs(order.this, args))
|
|
8744
|
+
|
|
8745
|
+
this = order or concat_exprs(args[0], args)
|
|
8746
|
+
else:
|
|
8747
|
+
this = None
|
|
8748
|
+
|
|
8749
|
+
separator = self._parse_field() if self._match(TokenType.SEPARATOR) else None
|
|
8750
|
+
|
|
8751
|
+
return self.expression(exp.GroupConcat, this=this, separator=separator)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlglot
|
|
3
|
-
Version: 27.
|
|
3
|
+
Version: 27.9.0
|
|
4
4
|
Summary: An easily customizable SQL parser and transpiler
|
|
5
5
|
Author-email: Toby Mao <toby.mao@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
6
7
|
Project-URL: Homepage, https://sqlglot.com/
|
|
7
8
|
Project-URL: Documentation, https://sqlglot.com/sqlglot.html
|
|
8
9
|
Project-URL: Repository, https://github.com/tobymao/sqlglot
|
|
@@ -72,6 +73,7 @@ Contributions are very welcome in SQLGlot; read the [contribution guide](https:/
|
|
|
72
73
|
* [Run Tests and Lint](#run-tests-and-lint)
|
|
73
74
|
* [Benchmarks](#benchmarks)
|
|
74
75
|
* [Optional Dependencies](#optional-dependencies)
|
|
76
|
+
* [Supported Dialects](#supported-dialects)
|
|
75
77
|
|
|
76
78
|
## Install
|
|
77
79
|
|
|
@@ -256,7 +258,7 @@ sqlglot.errors.ParseError: Expecting ). Line 1, Col: 34.
|
|
|
256
258
|
Structured syntax errors are accessible for programmatic use:
|
|
257
259
|
|
|
258
260
|
```python
|
|
259
|
-
import sqlglot
|
|
261
|
+
import sqlglot.errors
|
|
260
262
|
try:
|
|
261
263
|
sqlglot.transpile("SELECT foo FROM (SELECT baz FROM t")
|
|
262
264
|
except sqlglot.errors.ParseError as e:
|
|
@@ -584,3 +586,41 @@ SQLGlot uses [dateutil](https://github.com/dateutil/dateutil) to simplify litera
|
|
|
584
586
|
```sql
|
|
585
587
|
x + interval '1' month
|
|
586
588
|
```
|
|
589
|
+
|
|
590
|
+
## Supported Dialects
|
|
591
|
+
|
|
592
|
+
| Dialect | Support Level |
|
|
593
|
+
|---------|---------------|
|
|
594
|
+
| Athena | Official |
|
|
595
|
+
| BigQuery | Official |
|
|
596
|
+
| ClickHouse | Official |
|
|
597
|
+
| Databricks | Official |
|
|
598
|
+
| Doris | Community |
|
|
599
|
+
| Dremio | Community |
|
|
600
|
+
| Drill | Community |
|
|
601
|
+
| Druid | Community |
|
|
602
|
+
| DuckDB | Official |
|
|
603
|
+
| Exasol | Community |
|
|
604
|
+
| Fabric | Community |
|
|
605
|
+
| Hive | Official |
|
|
606
|
+
| Materialize | Community |
|
|
607
|
+
| MySQL | Official |
|
|
608
|
+
| Oracle | Official |
|
|
609
|
+
| Postgres | Official |
|
|
610
|
+
| Presto | Official |
|
|
611
|
+
| PRQL | Community |
|
|
612
|
+
| Redshift | Official |
|
|
613
|
+
| RisingWave | Community |
|
|
614
|
+
| SingleStore | Community |
|
|
615
|
+
| Snowflake | Official |
|
|
616
|
+
| Spark | Official |
|
|
617
|
+
| SQLite | Official |
|
|
618
|
+
| StarRocks | Official |
|
|
619
|
+
| Tableau | Official |
|
|
620
|
+
| Teradata | Community |
|
|
621
|
+
| Trino | Official |
|
|
622
|
+
| TSQL | Official |
|
|
623
|
+
|
|
624
|
+
**Official Dialects** are maintained by the core SQLGlot team with higher priority for bug fixes and feature additions.
|
|
625
|
+
|
|
626
|
+
**Community Dialects** are developed and maintained primarily through community contributions. These are fully functional but may receive lower priority for issue resolution compared to officially supported dialects. We welcome and encourage community contributions to improve these dialects.
|
|
@@ -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=ajw9kWYWGubzKizjYwTc7fCRm3mKMWSeBdumU45KcDc,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=h_bK-KD-wGVNekA7ya4mdZbc9cS9P01gulgYGm6YIFA,250240
|
|
8
|
+
sqlglot/generator.py,sha256=jS270aRZjI04N1boPyRwni-_B0qyG3EWDFsyWpuTOwg,221954
|
|
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=K0Lx-PyjMgpzGXz7qmnLdWDV4GYNc7oW7wJJMXLHQTk,330514
|
|
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
|
|
@@ -18,39 +18,39 @@ sqlglot/time.py,sha256=Q62gv6kL40OiRBF6BMESxKJcMVn7ZLNw7sv8H34z5FI,18400
|
|
|
18
18
|
sqlglot/tokens.py,sha256=ibw_XDjfMgX80ScCwXXrxKLyKCSmHWwZhxPkmKF7q3I,48937
|
|
19
19
|
sqlglot/transforms.py,sha256=utNDsCBsA7hPUK3-aby3DDgiY_XVMAKQqeoLm1EyihI,41218
|
|
20
20
|
sqlglot/trie.py,sha256=v27uXMrHfqrXlJ6GmeTSMovsB_3o0ctnlKhdNt7W6fI,2245
|
|
21
|
-
sqlglot/dialects/__init__.py,sha256=
|
|
21
|
+
sqlglot/dialects/__init__.py,sha256=e3K2NHrZO7oXfBzEpRsvgWAgJ_UCEyg7SlUCRqvnPj4,3799
|
|
22
22
|
sqlglot/dialects/athena.py,sha256=ofArmayYLev4qZQ15GM8mevG04qqR5WGFb2ZcuYm6x4,10966
|
|
23
|
-
sqlglot/dialects/bigquery.py,sha256=
|
|
24
|
-
sqlglot/dialects/clickhouse.py,sha256=
|
|
25
|
-
sqlglot/dialects/databricks.py,sha256=
|
|
26
|
-
sqlglot/dialects/dialect.py,sha256=
|
|
27
|
-
sqlglot/dialects/doris.py,sha256=
|
|
28
|
-
sqlglot/dialects/dremio.py,sha256=
|
|
23
|
+
sqlglot/dialects/bigquery.py,sha256=7zDye1IusAN3F6yWzL04n22X1y-R_iMLoOewEU44V9U,64120
|
|
24
|
+
sqlglot/dialects/clickhouse.py,sha256=OuaDWpvVrHCF9N-u3ZmHZUCs7DSKq_aaRt8yOh2CtaY,58301
|
|
25
|
+
sqlglot/dialects/databricks.py,sha256=761qPlGOFHa9V8mdQYNAEw0pv4HUJYMkGEuFsdsLC7s,4714
|
|
26
|
+
sqlglot/dialects/dialect.py,sha256=02W-j8nYJduA78_BMxMTMGXv2i9mcAGAmXBt1YsH0CQ,73055
|
|
27
|
+
sqlglot/dialects/doris.py,sha256=NvDGHIKGJDVp0b4oOnMu1fyAprJPOiC8J6M85V75iuU,25136
|
|
28
|
+
sqlglot/dialects/dremio.py,sha256=o9wqHnUXlEetOuGUWBZLER1whId9U4l1xledme7qGsg,7392
|
|
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=vCIjZV9lszyXt-hNylVyUdHHlD_F9zsYznzcZLaqGDg,52241
|
|
32
32
|
sqlglot/dialects/dune.py,sha256=gALut-fFfN2qMsr8LvZ1NQK3F3W9z2f4PwMvTMXVVVg,375
|
|
33
|
-
sqlglot/dialects/exasol.py,sha256=
|
|
33
|
+
sqlglot/dialects/exasol.py,sha256=ay3g_VyT5WvHTgNyJuCQu0nBt4bpllLZ9IdMBizEgYM,15761
|
|
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=tQHedJthtXdjgHi3cDfdt71kJ4w6ju6J8kD4_MYFwyE,47308
|
|
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
|
-
sqlglot/dialects/redshift.py,sha256=
|
|
42
|
+
sqlglot/dialects/redshift.py,sha256=_sQTom4CGozFDZXW9y6bHQcZ-KiQ7QJjjQqM5rVagSc,15889
|
|
43
43
|
sqlglot/dialects/risingwave.py,sha256=BqWwW1iT_OIVMwfRamaww79snnBwIgCfr22Go-ggO68,3289
|
|
44
|
-
sqlglot/dialects/singlestore.py,sha256=
|
|
44
|
+
sqlglot/dialects/singlestore.py,sha256=x6QUI_lsbQKJVwzF9q2PNg3gKrCbBBXxR05Tk58Zo64,41703
|
|
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=
|
|
53
|
-
sqlglot/dialects/tsql.py,sha256=
|
|
52
|
+
sqlglot/dialects/trino.py,sha256=Z7prRhCxIBh0KCxIQpWmVOIGHCJM9Xl5oRlqySxln4Y,4350
|
|
53
|
+
sqlglot/dialects/tsql.py,sha256=kfzHDyKdciqwre6mjZaRHP9tnqfPSPjcM9SP9C045VA,54075
|
|
54
54
|
sqlglot/executor/__init__.py,sha256=FslewzYQtQdDNg_0Ju2UaiP4vo4IMUgkfkmFsYUhcN0,2958
|
|
55
55
|
sqlglot/executor/context.py,sha256=WJHJdYQCOeVXwLw0uSSrWSc25eBMn5Ix108RCvdsKRQ,3386
|
|
56
56
|
sqlglot/executor/env.py,sha256=tQhU5PpTBMcxgZIFddFqxWMNPtHN0vOOz72voncY3KY,8276
|
|
@@ -71,13 +71,13 @@ sqlglot/optimizer/optimizer.py,sha256=vXEXDWHvbO-vJmSI7UqJuydM2WrD1xko7rETq2EtVJ
|
|
|
71
71
|
sqlglot/optimizer/pushdown_predicates.py,sha256=HGjs3Z4V3-X2d1VTfWhyByY3aL5SmKnVvt3aDXiiBM0,8414
|
|
72
72
|
sqlglot/optimizer/pushdown_projections.py,sha256=7NoK5NAUVYVhs0YnYyo6WuXfaO-BShSwS6lA8Y-ATQ4,6668
|
|
73
73
|
sqlglot/optimizer/qualify.py,sha256=oAPfwub7dEkrlCrsptcJWpLya4BgKhN6M5SwIs_86LY,4002
|
|
74
|
-
sqlglot/optimizer/qualify_columns.py,sha256=
|
|
74
|
+
sqlglot/optimizer/qualify_columns.py,sha256=EweCIUeb9iDuv3Lo0iYHCrqva4G31CwCfrOg_N3IV_8,43936
|
|
75
75
|
sqlglot/optimizer/qualify_tables.py,sha256=dA4ZazL7ShQh2JgBwpHuG-4c5lBw1TNzCnuN7m0iVTA,6645
|
|
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.9.0.dist-info/licenses/LICENSE,sha256=p1Yk0B4oa0l8Rh-_dYyy75d8spjPd_vTloXfz4FWxys,1065
|
|
80
|
+
sqlglot-27.9.0.dist-info/METADATA,sha256=1kzKJ_pmJY6MWnkGONHCA4nETXxcWclkGSwjYu-sXjk,20681
|
|
81
|
+
sqlglot-27.9.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
82
|
+
sqlglot-27.9.0.dist-info/top_level.txt,sha256=5kRskCGA_gVADF9rSfSzPdLHXqvfMusDYeHePfNY2nQ,8
|
|
83
|
+
sqlglot-27.9.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|