sqlglot 27.14.0__py3-none-any.whl → 27.15.1__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 CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '27.14.0'
32
- __version_tuple__ = version_tuple = (27, 14, 0)
31
+ __version__ = version = '27.15.1'
32
+ __version_tuple__ = version_tuple = (27, 15, 1)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -863,6 +863,9 @@ class BigQuery(Dialect):
863
863
  "TRANSLATE": lambda self: self._parse_translate(),
864
864
  "FEATURES_AT_TIME": lambda self: self._parse_features_at_time(),
865
865
  "GENERATE_EMBEDDING": lambda self: self._parse_ml(exp.GenerateEmbedding),
866
+ "GENERATE_TEXT_EMBEDDING": lambda self: self._parse_ml(
867
+ exp.GenerateEmbedding, is_text=True
868
+ ),
866
869
  "VECTOR_SEARCH": lambda self: self._parse_vector_search(),
867
870
  "FORECAST": lambda self: self._parse_ml(exp.MLForecast),
868
871
  }
@@ -894,8 +897,6 @@ class BigQuery(Dialect):
894
897
  RANGE_PARSERS = parser.Parser.RANGE_PARSERS.copy()
895
898
  RANGE_PARSERS.pop(TokenType.OVERLAPS)
896
899
 
897
- NULL_TOKENS = {TokenType.NULL, TokenType.UNKNOWN}
898
-
899
900
  DASHED_TABLE_PART_FOLLOW_TOKENS = {TokenType.DOT, TokenType.L_PAREN, TokenType.R_PAREN}
900
901
 
901
902
  STATEMENT_PARSERS = {
@@ -1148,7 +1149,7 @@ class BigQuery(Dialect):
1148
1149
 
1149
1150
  return expr
1150
1151
 
1151
- def _parse_ml(self, expr_type: t.Type[E]) -> E:
1152
+ def _parse_ml(self, expr_type: t.Type[E], **kwargs) -> E:
1152
1153
  self._match_text_seq("MODEL")
1153
1154
  this = self._parse_table()
1154
1155
 
@@ -1167,6 +1168,7 @@ class BigQuery(Dialect):
1167
1168
  this=this,
1168
1169
  expression=expression,
1169
1170
  params_struct=self._parse_bitwise(),
1171
+ **kwargs,
1170
1172
  )
1171
1173
 
1172
1174
  def _parse_translate(self) -> exp.Translate | exp.MLTranslate:
sqlglot/dialects/mysql.py CHANGED
@@ -191,10 +191,8 @@ class MySQL(Dialect):
191
191
 
192
192
  KEYWORDS = {
193
193
  **tokens.Tokenizer.KEYWORDS,
194
- "CHARSET": TokenType.CHARACTER_SET,
195
- # The DESCRIBE and EXPLAIN statements are synonyms.
196
- # https://dev.mysql.com/doc/refman/8.4/en/explain.html
197
194
  "BLOB": TokenType.BLOB,
195
+ "CHARSET": TokenType.CHARACTER_SET,
198
196
  "DISTINCTROW": TokenType.DISTINCT,
199
197
  "EXPLAIN": TokenType.DESCRIBE,
200
198
  "FORCE": TokenType.FORCE,
@@ -204,17 +202,19 @@ class MySQL(Dialect):
204
202
  "LONGBLOB": TokenType.LONGBLOB,
205
203
  "LONGTEXT": TokenType.LONGTEXT,
206
204
  "MEDIUMBLOB": TokenType.MEDIUMBLOB,
207
- "TINYBLOB": TokenType.TINYBLOB,
208
- "TINYTEXT": TokenType.TINYTEXT,
209
- "MEDIUMTEXT": TokenType.MEDIUMTEXT,
210
205
  "MEDIUMINT": TokenType.MEDIUMINT,
206
+ "MEDIUMTEXT": TokenType.MEDIUMTEXT,
211
207
  "MEMBER OF": TokenType.MEMBER_OF,
208
+ "MOD": TokenType.MOD,
212
209
  "SEPARATOR": TokenType.SEPARATOR,
213
210
  "SERIAL": TokenType.SERIAL,
214
- "START": TokenType.BEGIN,
215
211
  "SIGNED": TokenType.BIGINT,
216
212
  "SIGNED INTEGER": TokenType.BIGINT,
213
+ "SOUNDS LIKE": TokenType.SOUNDS_LIKE,
214
+ "START": TokenType.BEGIN,
217
215
  "TIMESTAMP": TokenType.TIMESTAMPTZ,
216
+ "TINYBLOB": TokenType.TINYBLOB,
217
+ "TINYTEXT": TokenType.TINYTEXT,
218
218
  "UNLOCK TABLES": TokenType.COMMAND,
219
219
  "UNSIGNED": TokenType.UBIGINT,
220
220
  "UNSIGNED INTEGER": TokenType.UBIGINT,
@@ -271,6 +271,7 @@ class MySQL(Dialect):
271
271
  FUNC_TOKENS = {
272
272
  *parser.Parser.FUNC_TOKENS,
273
273
  TokenType.DATABASE,
274
+ TokenType.MOD,
274
275
  TokenType.SCHEMA,
275
276
  TokenType.VALUES,
276
277
  }
@@ -292,6 +293,11 @@ class MySQL(Dialect):
292
293
 
293
294
  RANGE_PARSERS = {
294
295
  **parser.Parser.RANGE_PARSERS,
296
+ TokenType.SOUNDS_LIKE: lambda self, this: self.expression(
297
+ exp.EQ,
298
+ this=self.expression(exp.Soundex, this=this),
299
+ expression=self.expression(exp.Soundex, this=self._parse_term()),
300
+ ),
295
301
  TokenType.MEMBER_OF: lambda self, this: self.expression(
296
302
  exp.JSONArrayContains,
297
303
  this=this,
@@ -359,6 +365,7 @@ class MySQL(Dialect):
359
365
  exp.Anonymous, this="VALUES", expressions=[self._parse_id_var()]
360
366
  ),
361
367
  "JSON_VALUE": lambda self: self._parse_json_value(),
368
+ "SUBSTR": lambda self: self._parse_substring(),
362
369
  }
363
370
 
364
371
  STATEMENT_PARSERS = {
@@ -424,6 +424,11 @@ class Postgres(Dialect):
424
424
  FUNCTION_PARSERS = {
425
425
  **parser.Parser.FUNCTION_PARSERS,
426
426
  "DATE_PART": lambda self: self._parse_date_part(),
427
+ "JSON_AGG": lambda self: self.expression(
428
+ exp.JSONArrayAgg,
429
+ this=self._parse_bitwise(),
430
+ order=self._parse_order(),
431
+ ),
427
432
  "JSONB_EXISTS": lambda self: self._parse_jsonb_exists(),
428
433
  }
429
434
 
@@ -608,6 +613,11 @@ class Postgres(Dialect):
608
613
  self, e, func_name="STRING_AGG", within_group=False
609
614
  ),
610
615
  exp.IntDiv: rename_func("DIV"),
616
+ exp.JSONArrayAgg: lambda self, e: self.func(
617
+ "JSON_AGG",
618
+ self.sql(e, "this"),
619
+ suffix=f"{self.sql(e, 'order')})",
620
+ ),
611
621
  exp.JSONExtract: _json_extract_sql("JSON_EXTRACT_PATH", "->"),
612
622
  exp.JSONExtractScalar: _json_extract_sql("JSON_EXTRACT_PATH_TEXT", "->>"),
613
623
  exp.JSONBExtract: lambda self, e: self.binary(e, "#>"),
@@ -527,6 +527,7 @@ class SingleStore(MySQL):
527
527
  e.expression,
528
528
  self.func("SUBSTRING", e.this, e.args.get("start") + e.args.get("length")),
529
529
  ),
530
+ exp.National: lambda self, e: self.national_sql(e, prefix=""),
530
531
  exp.Reduce: unsupported_args("finish")(
531
532
  lambda self, e: self.func(
532
533
  "REDUCE", e.args.get("initial"), e.this, e.args.get("merge")
@@ -1862,3 +1863,9 @@ class SingleStore(MySQL):
1862
1863
  collate = self.sql(expression, "collate")
1863
1864
  collate = f" COLLATE {collate}" if collate else ""
1864
1865
  return f"{alter}{collate}"
1866
+
1867
+ def computedcolumnconstraint_sql(self, expression: exp.ComputedColumnConstraint) -> str:
1868
+ this = self.sql(expression, "this")
1869
+ not_null = " NOT NULL" if expression.args.get("not_null") else ""
1870
+ type = self.sql(expression, "data_type") or "AUTO"
1871
+ return f"AS {this} PERSISTED {type}{not_null}"
@@ -6,6 +6,7 @@ from sqlglot import exp, generator, jsonpath, parser, tokens, transforms
6
6
  from sqlglot.dialects.dialect import (
7
7
  Dialect,
8
8
  NormalizationStrategy,
9
+ annotate_with_type_lambda,
9
10
  build_timetostr_or_tochar,
10
11
  binary_from_function,
11
12
  build_default_decimal_type,
@@ -377,6 +378,7 @@ def _qualify_unnested_columns(expression: exp.Expression) -> exp.Expression:
377
378
 
378
379
  taken_source_names = set(scope.sources)
379
380
  column_source: t.Dict[str, exp.Identifier] = {}
381
+ unnest_to_identifier: t.Dict[exp.Unnest, exp.Identifier] = {}
380
382
 
381
383
  unnest_identifier: t.Optional[exp.Identifier] = None
382
384
  orig_expression = expression.copy()
@@ -429,6 +431,7 @@ def _qualify_unnested_columns(expression: exp.Expression) -> exp.Expression:
429
431
  if not isinstance(unnest_identifier, exp.Identifier):
430
432
  return orig_expression
431
433
 
434
+ unnest_to_identifier[unnest] = unnest_identifier
432
435
  column_source.update({c.lower(): unnest_identifier for c in unnest_columns})
433
436
 
434
437
  for column in scope.columns:
@@ -442,6 +445,15 @@ def _qualify_unnested_columns(expression: exp.Expression) -> exp.Expression:
442
445
  and len(scope.sources) == 1
443
446
  and column.name.lower() != unnest_identifier.name.lower()
444
447
  ):
448
+ unnest_ancestor = column.find_ancestor(exp.Unnest, exp.Select)
449
+ ancestor_identifier = unnest_to_identifier.get(unnest_ancestor)
450
+ if (
451
+ isinstance(unnest_ancestor, exp.Unnest)
452
+ and ancestor_identifier
453
+ and ancestor_identifier.name.lower() == unnest_identifier.name.lower()
454
+ ):
455
+ continue
456
+
445
457
  table = unnest_identifier
446
458
 
447
459
  column.set("table", table and table.copy())
@@ -506,8 +518,49 @@ class Snowflake(Dialect):
506
518
  ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False
507
519
  TRY_CAST_REQUIRES_STRING = True
508
520
 
521
+ TYPE_TO_EXPRESSIONS = {
522
+ **Dialect.TYPE_TO_EXPRESSIONS,
523
+ exp.DataType.Type.INT: {
524
+ *Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.INT],
525
+ exp.Length,
526
+ },
527
+ exp.DataType.Type.VARCHAR: {
528
+ *Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.VARCHAR],
529
+ exp.MD5,
530
+ exp.AIAgg,
531
+ exp.AISummarizeAgg,
532
+ exp.RegexpExtract,
533
+ exp.RegexpReplace,
534
+ exp.Repeat,
535
+ exp.Replace,
536
+ exp.SHA,
537
+ exp.SHA2,
538
+ exp.Space,
539
+ exp.Uuid,
540
+ },
541
+ exp.DataType.Type.BINARY: {
542
+ *Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.BINARY],
543
+ exp.MD5Digest,
544
+ exp.SHA1Digest,
545
+ exp.SHA2Digest,
546
+ },
547
+ exp.DataType.Type.BIGINT: {
548
+ *Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.BIGINT],
549
+ exp.MD5NumberLower64,
550
+ exp.MD5NumberUpper64,
551
+ },
552
+ exp.DataType.Type.ARRAY: {
553
+ exp.Split,
554
+ },
555
+ }
556
+
509
557
  ANNOTATORS = {
510
558
  **Dialect.ANNOTATORS,
559
+ **{
560
+ expr_type: annotate_with_type_lambda(data_type)
561
+ for data_type, expressions in TYPE_TO_EXPRESSIONS.items()
562
+ for expr_type in expressions
563
+ },
511
564
  **{
512
565
  expr_type: lambda self, e: self._annotate_by_args(e, "this")
513
566
  for expr_type in (
@@ -517,10 +570,7 @@ class Snowflake(Dialect):
517
570
  )
518
571
  },
519
572
  exp.ConcatWs: lambda self, e: self._annotate_by_args(e, "expressions"),
520
- exp.Length: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.INT),
521
- exp.Replace: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.VARCHAR),
522
573
  exp.Reverse: _annotate_reverse,
523
- exp.Space: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.VARCHAR),
524
574
  }
525
575
 
526
576
  TIME_MAPPING = {
@@ -640,6 +690,10 @@ class Snowflake(Dialect):
640
690
  ),
641
691
  "HEX_DECODE_BINARY": exp.Unhex.from_arg_list,
642
692
  "IFF": exp.If.from_arg_list,
693
+ "MD5_HEX": exp.MD5.from_arg_list,
694
+ "MD5_BINARY": exp.MD5Digest.from_arg_list,
695
+ "MD5_NUMBER_LOWER64": exp.MD5NumberLower64.from_arg_list,
696
+ "MD5_NUMBER_UPPER64": exp.MD5NumberUpper64.from_arg_list,
643
697
  "LAST_DAY": lambda args: exp.LastDay(
644
698
  this=seq_get(args, 0), unit=map_date_part(seq_get(args, 1))
645
699
  ),
@@ -647,12 +701,17 @@ class Snowflake(Dialect):
647
701
  "LENGTH": lambda args: exp.Length(this=seq_get(args, 0), binary=True),
648
702
  "NULLIFZERO": _build_if_from_nullifzero,
649
703
  "OBJECT_CONSTRUCT": _build_object_construct,
704
+ "OCTET_LENGTH": exp.ByteLength.from_arg_list,
650
705
  "REGEXP_EXTRACT_ALL": _build_regexp_extract(exp.RegexpExtractAll),
651
706
  "REGEXP_REPLACE": _build_regexp_replace,
652
707
  "REGEXP_SUBSTR": _build_regexp_extract(exp.RegexpExtract),
653
708
  "REGEXP_SUBSTR_ALL": _build_regexp_extract(exp.RegexpExtractAll),
654
709
  "REPLACE": build_replace_with_optional_replacement,
655
710
  "RLIKE": exp.RegexpLike.from_arg_list,
711
+ "SHA1_BINARY": exp.SHA1Digest.from_arg_list,
712
+ "SHA1_HEX": exp.SHA.from_arg_list,
713
+ "SHA2_BINARY": exp.SHA2Digest.from_arg_list,
714
+ "SHA2_HEX": exp.SHA2.from_arg_list,
656
715
  "SQUARE": lambda args: exp.Pow(this=seq_get(args, 0), expression=exp.Literal.number(2)),
657
716
  "TABLE": lambda args: exp.TableFromRows(this=seq_get(args, 0)),
658
717
  "TIMEADD": _build_date_time_add(exp.TimeAdd),
@@ -1318,6 +1377,8 @@ class Snowflake(Dialect):
1318
1377
  ),
1319
1378
  exp.SHA: rename_func("SHA1"),
1320
1379
  exp.MD5Digest: rename_func("MD5_BINARY"),
1380
+ exp.MD5NumberLower64: rename_func("MD5_NUMBER_LOWER64"),
1381
+ exp.MD5NumberUpper64: rename_func("MD5_NUMBER_UPPER64"),
1321
1382
  exp.LowerHex: rename_func("TO_CHAR"),
1322
1383
  exp.SortArray: rename_func("ARRAY_SORT"),
1323
1384
  exp.StarMap: rename_func("OBJECT_CONSTRUCT"),
@@ -1356,6 +1417,7 @@ class Snowflake(Dialect):
1356
1417
  exp.VarMap: lambda self, e: var_map_sql(self, e, "OBJECT_CONSTRUCT"),
1357
1418
  exp.WeekOfYear: rename_func("WEEKOFYEAR"),
1358
1419
  exp.Xor: rename_func("BOOLXOR"),
1420
+ exp.ByteLength: rename_func("OCTET_LENGTH"),
1359
1421
  }
1360
1422
 
1361
1423
  SUPPORTED_JSON_PATH_PARTS = {
sqlglot/dialects/tsql.py CHANGED
@@ -650,6 +650,16 @@ class TSQL(Dialect):
650
650
  "NEXT": lambda self: self._parse_next_value_for(),
651
651
  }
652
652
 
653
+ FUNCTION_PARSERS: t.Dict[str, t.Callable] = {
654
+ **parser.Parser.FUNCTION_PARSERS,
655
+ "JSON_ARRAYAGG": lambda self: self.expression(
656
+ exp.JSONArrayAgg,
657
+ this=self._parse_bitwise(),
658
+ order=self._parse_order(),
659
+ null_handling=self._parse_on_handling("NULL", "NULL", "ABSENT"),
660
+ ),
661
+ }
662
+
653
663
  # The DCOLON (::) operator serves as a scope resolution (exp.ScopeResolution) operator in T-SQL
654
664
  COLUMN_OPERATORS = {
655
665
  **parser.Parser.COLUMN_OPERATORS,
sqlglot/expressions.py CHANGED
@@ -134,7 +134,7 @@ class Expression(metaclass=_Expression):
134
134
 
135
135
  return hash((self.__class__, self.hashable_args))
136
136
 
137
- def __reduce__(self) -> t.Tuple[t.Callable, t.Tuple[t.Dict[str, t.Any]]]:
137
+ def __reduce__(self) -> t.Tuple[t.Callable, t.Tuple[t.List[t.Dict[str, t.Any]]]]:
138
138
  from sqlglot.serde import dump, load
139
139
 
140
140
  return (load, (dump(self),))
@@ -264,7 +264,7 @@ class Expression(metaclass=_Expression):
264
264
  return self.type is not None and self.type.is_type(*dtypes)
265
265
 
266
266
  def is_leaf(self) -> bool:
267
- return not any(isinstance(v, (Expression, list)) for v in self.args.values())
267
+ return not any(isinstance(v, (Expression, list)) and v for v in self.args.values())
268
268
 
269
269
  @property
270
270
  def meta(self) -> t.Dict[str, t.Any]:
@@ -2065,7 +2065,7 @@ class ProjectionPolicyColumnConstraint(ColumnConstraintKind):
2065
2065
  # computed column expression
2066
2066
  # https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver16
2067
2067
  class ComputedColumnConstraint(ColumnConstraintKind):
2068
- arg_types = {"this": True, "persisted": False, "not_null": False}
2068
+ arg_types = {"this": True, "persisted": False, "not_null": False, "data_type": False}
2069
2069
 
2070
2070
 
2071
2071
  class Constraint(Expression):
@@ -5766,6 +5766,15 @@ class ArrayUniqueAgg(AggFunc):
5766
5766
  pass
5767
5767
 
5768
5768
 
5769
+ class AIAgg(AggFunc):
5770
+ arg_types = {"this": True, "expression": True}
5771
+ _sql_names = ["AI_AGG"]
5772
+
5773
+
5774
+ class AISummarizeAgg(AggFunc):
5775
+ _sql_names = ["AI_SUMMARIZE_AGG"]
5776
+
5777
+
5769
5778
  class ArrayAll(Func):
5770
5779
  arg_types = {"this": True, "expression": True}
5771
5780
 
@@ -6951,6 +6960,16 @@ class MD5Digest(Func):
6951
6960
  _sql_names = ["MD5_DIGEST"]
6952
6961
 
6953
6962
 
6963
+ # https://docs.snowflake.com/en/sql-reference/functions/md5_number_lower64
6964
+ class MD5NumberLower64(Func):
6965
+ pass
6966
+
6967
+
6968
+ # https://docs.snowflake.com/en/sql-reference/functions/md5_number_upper64
6969
+ class MD5NumberUpper64(Func):
6970
+ pass
6971
+
6972
+
6954
6973
  class Median(AggFunc):
6955
6974
  pass
6956
6975
 
@@ -7001,7 +7020,7 @@ class FeaturesAtTime(Func):
7001
7020
 
7002
7021
  # https://cloud.google.com/bigquery/docs/reference/standard-sql/bigqueryml-syntax-generate-embedding
7003
7022
  class GenerateEmbedding(Func):
7004
- arg_types = {"this": True, "expression": True, "params_struct": False}
7023
+ arg_types = {"this": True, "expression": True, "params_struct": False, "is_text": False}
7005
7024
 
7006
7025
 
7007
7026
  class MLForecast(Func):
@@ -7201,6 +7220,16 @@ class SHA2(Func):
7201
7220
  arg_types = {"this": True, "length": False}
7202
7221
 
7203
7222
 
7223
+ # Represents the variant of the SHA1 function that returns a binary value
7224
+ class SHA1Digest(Func):
7225
+ pass
7226
+
7227
+
7228
+ # Represents the variant of the SHA2 function that returns a binary value
7229
+ class SHA2Digest(Func):
7230
+ arg_types = {"this": True, "length": False}
7231
+
7232
+
7204
7233
  class Sign(Func):
7205
7234
  _sql_names = ["SIGN", "SIGNUM"]
7206
7235
 
sqlglot/generator.py CHANGED
@@ -4235,7 +4235,8 @@ class Generator(metaclass=_Generator):
4235
4235
  return self._ml_sql(expression, "PREDICT")
4236
4236
 
4237
4237
  def generateembedding_sql(self, expression: exp.GenerateEmbedding) -> str:
4238
- return self._ml_sql(expression, "GENERATE_EMBEDDING")
4238
+ name = "GENERATE_TEXT_EMBEDDING" if expression.args.get("is_text") else "GENERATE_EMBEDDING"
4239
+ return self._ml_sql(expression, name)
4239
4240
 
4240
4241
  def mltranslate_sql(self, expression: exp.MLTranslate) -> str:
4241
4242
  return self._ml_sql(expression, "TRANSLATE")
@@ -593,14 +593,18 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
593
593
  def _annotate_struct_value(
594
594
  self, expression: exp.Expression
595
595
  ) -> t.Optional[exp.DataType] | exp.ColumnDef:
596
- alias = expression.args.get("alias")
597
- if alias:
596
+ # Case: STRUCT(key AS value)
597
+ if alias := expression.args.get("alias"):
598
598
  return exp.ColumnDef(this=alias.copy(), kind=expression.type)
599
599
 
600
- # Case: key = value or key := value
600
+ # Case: STRUCT(key = value) or STRUCT(key := value)
601
601
  if expression.expression:
602
602
  return exp.ColumnDef(this=expression.this.copy(), kind=expression.expression.type)
603
603
 
604
+ # Case: STRUCT(c)
605
+ if isinstance(expression, exp.Column):
606
+ return exp.ColumnDef(this=expression.this.copy(), kind=expression.type)
607
+
604
608
  return expression.type
605
609
 
606
610
  def _annotate_struct(self, expression: exp.Struct) -> exp.Struct:
@@ -351,11 +351,15 @@ def _expand_alias_refs(
351
351
  alias_to_expression[projection.alias] = (projection.this, i + 1)
352
352
 
353
353
  parent_scope = scope
354
- while parent_scope.is_union:
354
+ on_right_sub_tree = False
355
+ while parent_scope and not parent_scope.is_cte:
356
+ if parent_scope.is_union:
357
+ on_right_sub_tree = parent_scope.parent.expression.right is parent_scope.expression
355
358
  parent_scope = parent_scope.parent
356
359
 
357
360
  # We shouldn't expand aliases if they match the recursive CTE's columns
358
- if parent_scope.is_cte:
361
+ # and we are in the recursive part (right sub tree) of the CTE
362
+ if parent_scope and on_right_sub_tree:
359
363
  cte = parent_scope.expression.parent
360
364
  if cte.find_ancestor(exp.With).recursive:
361
365
  for recursive_cte_column in cte.args["alias"].columns or cte.this.selects:
sqlglot/parser.py CHANGED
@@ -1427,8 +1427,6 @@ class Parser(metaclass=_Parser):
1427
1427
 
1428
1428
  DISTINCT_TOKENS = {TokenType.DISTINCT}
1429
1429
 
1430
- NULL_TOKENS = {TokenType.NULL}
1431
-
1432
1430
  UNNEST_OFFSET_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - SET_OPERATIONS
1433
1431
 
1434
1432
  SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
@@ -6079,6 +6077,9 @@ class Parser(metaclass=_Parser):
6079
6077
  constraint_kind = exp.ComputedColumnConstraint(
6080
6078
  this=self._parse_assignment(),
6081
6079
  persisted=persisted or self._match_text_seq("PERSISTED"),
6080
+ data_type=exp.Var(this="AUTO")
6081
+ if self._match_text_seq("AUTO")
6082
+ else self._parse_types(),
6082
6083
  not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
6083
6084
  )
6084
6085
  constraints.append(self.expression(exp.ColumnConstraint, kind=constraint_kind))
@@ -6974,16 +6975,27 @@ class Parser(metaclass=_Parser):
6974
6975
 
6975
6976
  def _parse_substring(self) -> exp.Substring:
6976
6977
  # Postgres supports the form: substring(string [from int] [for int])
6978
+ # (despite being undocumented, the reverse order also works)
6977
6979
  # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
6978
6980
 
6979
6981
  args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
6980
6982
 
6981
- if self._match(TokenType.FROM):
6982
- args.append(self._parse_bitwise())
6983
- if self._match(TokenType.FOR):
6984
- if len(args) == 1:
6985
- args.append(exp.Literal.number(1))
6986
- args.append(self._parse_bitwise())
6983
+ start, length = None, None
6984
+
6985
+ while self._curr:
6986
+ if self._match(TokenType.FROM):
6987
+ start = self._parse_bitwise()
6988
+ elif self._match(TokenType.FOR):
6989
+ if not start:
6990
+ start = exp.Literal.number(1)
6991
+ length = self._parse_bitwise()
6992
+ else:
6993
+ break
6994
+
6995
+ if start:
6996
+ args.append(start)
6997
+ if length:
6998
+ args.append(length)
6987
6999
 
6988
7000
  return self.validate_expression(exp.Substring.from_arg_list(args), args)
6989
7001
 
@@ -7274,7 +7286,7 @@ class Parser(metaclass=_Parser):
7274
7286
  return self._parse_primary() or self._parse_var(any_token=True)
7275
7287
 
7276
7288
  def _parse_null(self) -> t.Optional[exp.Expression]:
7277
- if self._match_set(self.NULL_TOKENS):
7289
+ if self._match_set((TokenType.NULL, TokenType.UNKNOWN)):
7278
7290
  return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
7279
7291
  return self._parse_placeholder()
7280
7292
 
@@ -7308,7 +7320,7 @@ class Parser(metaclass=_Parser):
7308
7320
  if self._match(TokenType.L_PAREN, advance=False):
7309
7321
  return self._parse_wrapped_csv(self._parse_expression)
7310
7322
 
7311
- expression = self._parse_expression()
7323
+ expression = self._parse_alias(self._parse_assignment(), explicit=True)
7312
7324
  return [expression] if expression else None
7313
7325
 
7314
7326
  def _parse_csv(
sqlglot/serde.py CHANGED
@@ -5,105 +5,113 @@ import typing as t
5
5
  from sqlglot import expressions as exp
6
6
 
7
7
 
8
- def dump(expr: exp.Expression) -> t.Dict[str, t.Any]:
8
+ INDEX = "i"
9
+ ARG_KEY = "k"
10
+ IS_ARRAY = "a"
11
+ CLASS = "c"
12
+ TYPE = "t"
13
+ COMMENTS = "o"
14
+ META = "m"
15
+ VALUE = "v"
16
+ DATA_TYPE = "DataType.Type"
17
+
18
+
19
+ def dump(expression: exp.Expression) -> t.List[t.Dict[str, t.Any]]:
9
20
  """
10
- Dump an Expression into a JSON serializable dict.
21
+ Dump an Expression into a JSON serializable List.
11
22
  """
12
-
13
- root: t.Dict[str, t.Any] = {}
14
- stack = [(expr, root)]
23
+ i = 0
24
+ payloads = []
25
+ stack: t.List[t.Tuple[t.Any, t.Optional[int], t.Optional[str], bool]] = [
26
+ (expression, None, None, False)
27
+ ]
15
28
 
16
29
  while stack:
17
- node, payload = stack.pop()
18
-
19
- klass = node.__class__.__qualname__
20
-
21
- if node.__class__.__module__ != exp.__name__:
22
- klass = f"{node.__module__}.{klass}"
23
-
24
- payload["class"] = klass
25
-
26
- if node.type:
27
- payload["type"] = dump(node.type)
28
- if node.comments:
29
- payload["comments"] = node.comments
30
- if node._meta is not None:
31
- payload["meta"] = node._meta
32
- if node.args:
33
- args: t.Dict[str, t.Any] = {}
34
- payload["args"] = args
35
-
36
- for k, vs in node.args.items():
37
- if vs is None or vs == []:
38
- continue
39
- if hasattr(vs, "parent"):
40
- args[k] = {}
41
- stack.append((vs, args[k]))
42
- elif type(vs) is list:
43
- expressions: t.List[t.Any] = []
44
- args[k] = expressions
45
-
46
- for v in vs:
47
- if hasattr(v, "parent"):
48
- expressions.append({})
49
- stack.append((v, expressions[-1]))
50
- else:
51
- expressions.append(v)
52
- elif isinstance(vs, exp.DataType.Type):
53
- args[k] = {"class": "DataType.Type", "value": vs.value}
54
- else:
55
- args[k] = vs
30
+ node, index, arg_key, is_array = stack.pop()
56
31
 
57
- return root
32
+ payload: t.Dict[str, t.Any] = {}
33
+
34
+ if index is not None:
35
+ payload[INDEX] = index
36
+ if arg_key is not None:
37
+ payload[ARG_KEY] = arg_key
38
+ if is_array:
39
+ payload[IS_ARRAY] = is_array
40
+
41
+ payloads.append(payload)
42
+
43
+ if hasattr(node, "parent"):
44
+ klass = node.__class__.__qualname__
45
+
46
+ if node.__class__.__module__ != exp.__name__:
47
+ klass = f"{node.__module__}.{klass}"
48
+
49
+ payload[CLASS] = klass
50
+
51
+ if node.type:
52
+ payload[TYPE] = dump(node.type)
53
+ if node.comments:
54
+ payload[COMMENTS] = node.comments
55
+ if node._meta is not None:
56
+ payload[META] = node._meta
57
+ if node.args:
58
+ for k, vs in reversed(node.args.items()):
59
+ if type(vs) is list:
60
+ for v in reversed(vs):
61
+ stack.append((v, i, k, True))
62
+ elif vs is not None:
63
+ stack.append((vs, i, k, False))
64
+ elif type(node) is exp.DataType.Type:
65
+ payload[CLASS] = DATA_TYPE
66
+ payload[VALUE] = node.value
67
+ else:
68
+ payload[VALUE] = node
69
+
70
+ i += 1
71
+
72
+ return payloads
58
73
 
59
74
 
60
75
  @t.overload
61
- def load(expression: None) -> None: ...
76
+ def load(payloads: None) -> None: ...
62
77
 
63
78
 
64
79
  @t.overload
65
- def load(expression: t.Dict[str, t.Any]) -> exp.Expression: ...
80
+ def load(payloads: t.List[t.Dict[str, t.Any]]) -> exp.Expression: ...
66
81
 
67
82
 
68
- def load(expression):
83
+ def load(payloads):
69
84
  """
70
- Load a dict generated by dump into an Expression.
85
+ Load a list of dicts generated by dump into an Expression.
71
86
  """
72
- if expression is None:
87
+
88
+ if not payloads:
73
89
  return None
74
90
 
75
- root = _load(expression)
76
- stack = [(root, expression.get("args"))]
91
+ payload, *tail = payloads
92
+ root = _load(payload)
93
+ nodes = [root]
94
+ for payload in tail:
95
+ node = _load(payload)
96
+ nodes.append(node)
97
+ parent = nodes[payload[INDEX]]
98
+ arg_key = payload[ARG_KEY]
99
+
100
+ if payload.get(IS_ARRAY):
101
+ parent.append(arg_key, node)
102
+ else:
103
+ parent.set(arg_key, node)
77
104
 
78
- while stack:
79
- obj, args = stack.pop()
80
-
81
- if args:
82
- for k, vs in args.items():
83
- if isinstance(vs, list):
84
- array = []
85
- for v in vs:
86
- if isinstance(v, dict):
87
- child = _load(v)
88
- array.append(child)
89
- stack.append((child, v.get("args")))
90
- else:
91
- array.append(v)
92
- obj.set(k, array)
93
- elif isinstance(vs, dict):
94
- child = _load(vs)
95
- stack.append((child, vs.get("args")))
96
- obj.set(k, child)
97
- else:
98
- obj.set(k, vs)
99
105
  return root
100
106
 
101
107
 
102
108
  def _load(payload: t.Dict[str, t.Any]) -> exp.Expression | exp.DataType.Type:
103
- class_name = payload["class"]
109
+ class_name = payload.get(CLASS)
104
110
 
105
- if class_name == "DataType.Type":
106
- return exp.DataType.Type(payload["value"])
111
+ if not class_name:
112
+ return payload[VALUE]
113
+ if class_name == DATA_TYPE:
114
+ return exp.DataType.Type(payload[VALUE])
107
115
 
108
116
  if "." in class_name:
109
117
  module_path, class_name = class_name.rsplit(".", maxsplit=1)
@@ -112,7 +120,7 @@ def _load(payload: t.Dict[str, t.Any]) -> exp.Expression | exp.DataType.Type:
112
120
  module = exp
113
121
 
114
122
  expression = getattr(module, class_name)()
115
- expression.type = load(payload.get("type"))
116
- expression.comments = payload.get("comments")
117
- expression._meta = payload.get("meta")
123
+ expression.type = load(payload.get(TYPE))
124
+ expression.comments = payload.get(COMMENTS)
125
+ expression._meta = payload.get(META)
118
126
  return expression
sqlglot/tokens.py CHANGED
@@ -398,6 +398,7 @@ class TokenType(AutoName):
398
398
  SIMILAR_TO = auto()
399
399
  SOME = auto()
400
400
  SORT_BY = auto()
401
+ SOUNDS_LIKE = auto()
401
402
  START_WITH = auto()
402
403
  STORAGE_INTEGRATION = auto()
403
404
  STRAIGHT_JOIN = auto()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 27.14.0
3
+ Version: 27.15.1
4
4
  Summary: An easily customizable SQL parser and transpiler
5
5
  Author-email: Toby Mao <toby.mao@gmail.com>
6
6
  License-Expression: MIT
@@ -1,26 +1,26 @@
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=dO3zbTXGDFSvRTydZPKWrc0n8_OL2jG2s0_3yJeMyuY,708
4
+ sqlglot/_version.py,sha256=uBjOfOPRa2Q_ZQoGTa7Z6DXUQYBsQngq3pkSoTX6oxQ,708
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=LteUkI-eNj_xG4AvHTGuzqcZb2elWXygT5dR1FcxudI,254734
8
- sqlglot/generator.py,sha256=5A8fDNIE6u_SuTiSLR4tLDfmoA5LRG9nHIEMqVutaMg,225102
7
+ sqlglot/expressions.py,sha256=P9Da86Bo1Ufv1oZFs3ESJ1WDlc6tjvr-qz5BAd8_ek8,255449
8
+ sqlglot/generator.py,sha256=m4UHZpDrh52RZzv_iBqMnhv_j4DmhtpY1CtVyiGIJ8k,225187
9
9
  sqlglot/helper.py,sha256=9nZjFVRBtMKFC3EdzpDQ6jkazFO19po6BF8xHiNGZIo,15111
10
10
  sqlglot/jsonpath.py,sha256=SQgaxzaEYBN7At9dkTK4N1Spk6xHxvHL6QtCIP6iM30,7905
11
11
  sqlglot/lineage.py,sha256=Qj5ykuDNcATppb9vOjoIKBqRVLbu3OMPiZk9f3iyv40,15312
12
- sqlglot/parser.py,sha256=YECjuYjATlMIqgHyEyRDjG7Xm0Of2fHfsm2UgLCYNP0,334925
12
+ sqlglot/parser.py,sha256=7qwpwjE1P40aaXE83uS1sEyty901Iu6y2m4sgJPZ2Ew,335358
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
16
- sqlglot/serde.py,sha256=MFPE_7FgJx_kAZZFoaobj38jCjT6jfGghJUjzZBEUMs,3426
16
+ sqlglot/serde.py,sha256=nWpBFUjwZh06Li4qBuNb0YRU_QyflzSVyWkFxujM0WM,3175
17
17
  sqlglot/time.py,sha256=Q62gv6kL40OiRBF6BMESxKJcMVn7ZLNw7sv8H34z5FI,18400
18
- sqlglot/tokens.py,sha256=_Esqa2AB1PI7o7EUkupGUQYCvriE71O8J7BQiYySHC0,49146
18
+ sqlglot/tokens.py,sha256=fHH_44_p4-AH9o0scLPkF6bqKT-Tyc-Fk_ba-Gvp5-E,49171
19
19
  sqlglot/transforms.py,sha256=utNDsCBsA7hPUK3-aby3DDgiY_XVMAKQqeoLm1EyihI,41218
20
20
  sqlglot/trie.py,sha256=v27uXMrHfqrXlJ6GmeTSMovsB_3o0ctnlKhdNt7W6fI,2245
21
21
  sqlglot/dialects/__init__.py,sha256=e3K2NHrZO7oXfBzEpRsvgWAgJ_UCEyg7SlUCRqvnPj4,3799
22
22
  sqlglot/dialects/athena.py,sha256=ofArmayYLev4qZQ15GM8mevG04qqR5WGFb2ZcuYm6x4,10966
23
- sqlglot/dialects/bigquery.py,sha256=Oz9_pYUhVHBjHschYvar4V9hgz8KywokEV0y4hNXi7w,72371
23
+ sqlglot/dialects/bigquery.py,sha256=9Q-oCXcpa2vrT2eMgVGHWwEvECMm4RQeV1XkjJj0nPA,72483
24
24
  sqlglot/dialects/clickhouse.py,sha256=OzcDAS7pWs889gu0aLYn_HIjTLiPRjGFG61p6-84stE,58574
25
25
  sqlglot/dialects/databricks.py,sha256=H4QTq7gg6tJylKc_YWsGp6049KydoI_wlQUHM7iCJtI,4753
26
26
  sqlglot/dialects/dialect.py,sha256=BU4-x1d8tRCSAfdpeP5b86me0wXfgpcEPdyk27wLgg4,73293
@@ -34,15 +34,15 @@ sqlglot/dialects/exasol.py,sha256=ay3g_VyT5WvHTgNyJuCQu0nBt4bpllLZ9IdMBizEgYM,15
34
34
  sqlglot/dialects/fabric.py,sha256=BdkvzM8s-m5DIdBwdjEYskp32ub7aHCAex_xlhQn92I,10222
35
35
  sqlglot/dialects/hive.py,sha256=UGIkXjMCk5a9ndUXQtvfG560oi3emdpqOYLQCmGabBk,32046
36
36
  sqlglot/dialects/materialize.py,sha256=LD2q1kTRrCwkIu1BfoBvnjTGbupDtoQ8JQMDCIYAXHg,3533
37
- sqlglot/dialects/mysql.py,sha256=YuLyZBrEw4qSacd_1LGLJX4n-P99alnhQmANBlSFT4o,49408
37
+ sqlglot/dialects/mysql.py,sha256=0s7RIpWPCaBYvxgR8Z6JWPub1BHBB_0Th7KHCIXVfms,49702
38
38
  sqlglot/dialects/oracle.py,sha256=zWPCpzGiTlgCJ5E6FjfX3Rszjcw4SnHg6xeVboMYIyo,15972
39
- sqlglot/dialects/postgres.py,sha256=Zr5b0Yl5yXDKANcvUtnRsWUXLkbeEBZjwzFDAGtuub0,34296
39
+ sqlglot/dialects/postgres.py,sha256=KcvDIfl99EqOZ7nQ1Ey1IqcQMkAuXiN4SJqyvo95c2g,34674
40
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=FIwtP3yEg-way9pa32kxCJc6IaFkHVIvgYKZA-Ilmi0,15919
43
43
  sqlglot/dialects/risingwave.py,sha256=BqWwW1iT_OIVMwfRamaww79snnBwIgCfr22Go-ggO68,3289
44
- sqlglot/dialects/singlestore.py,sha256=GJrMoUK366JsQZyS_L8oGVkMkiVty1tijy7zqWAJ6Ck,61290
45
- sqlglot/dialects/snowflake.py,sha256=mmBa0iHgBDSo9M508cdluWzEjvMbTotLRERS3-ybsVI,73091
44
+ sqlglot/dialects/singlestore.py,sha256=0QqNYOucNklPQuyeGcsisLI97qPGx_RfWKOFarJz2qw,61711
45
+ sqlglot/dialects/snowflake.py,sha256=tgUJ77_Ntm1QcCbwlvI-j0_R96s0l6zFUUqysHIEez8,75351
46
46
  sqlglot/dialects/spark.py,sha256=PzyhkelDzbCMgJ3RVHD6yyzLIFp9NdZfwVas5IymowM,10147
47
47
  sqlglot/dialects/spark2.py,sha256=qz36FT9k4iuiqboRpyG4VpKGkPR0P2fifmqgZ9gNUEU,14851
48
48
  sqlglot/dialects/sqlite.py,sha256=zzXEbnaLjJeg6hPLHricjpfSkuf8tpXECnjcHtoqIbw,13263
@@ -50,14 +50,14 @@ sqlglot/dialects/starrocks.py,sha256=2gav0PSNgRdAGXzawdznZliBpglJoQ0wBxPI7ZIMsRw
50
50
  sqlglot/dialects/tableau.py,sha256=oIawDzUITxGCWaEMB8OaNMPWhbC3U-2y09pYPm4eazc,2190
51
51
  sqlglot/dialects/teradata.py,sha256=7LxCcRwP0Idd_OnCzA57NCdheVjHcKC2aFAKG5N49IU,18202
52
52
  sqlglot/dialects/trino.py,sha256=Z7prRhCxIBh0KCxIQpWmVOIGHCJM9Xl5oRlqySxln4Y,4350
53
- sqlglot/dialects/tsql.py,sha256=kfzHDyKdciqwre6mjZaRHP9tnqfPSPjcM9SP9C045VA,54075
53
+ sqlglot/dialects/tsql.py,sha256=7pVL3H-qNLCnoHqBEVSIVKhlTqoPmiYBRtg_HVv8zH4,54462
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
57
57
  sqlglot/executor/python.py,sha256=09GYRzrPn3lZGfDJY9pbONOvmYxsRyeSWjUiqkSRHGo,16661
58
58
  sqlglot/executor/table.py,sha256=xkuJlgLVNYUXsSUaX0zTcnFekldXLLU8LqDyjR5K9wY,4419
59
59
  sqlglot/optimizer/__init__.py,sha256=FdAvVz6rQLLkiiH21-SD4RxB5zS3WDeU-s03PZkJ-F4,343
60
- sqlglot/optimizer/annotate_types.py,sha256=RuBjs-mnWjH-wa02UKPMPq-3ymjQ_X7_t7Vz9xNhNOA,26202
60
+ sqlglot/optimizer/annotate_types.py,sha256=E3oqbGWD7Lb8DhGakLG8R_be8MIaBWTBXLk0RxCQFro,26400
61
61
  sqlglot/optimizer/canonicalize.py,sha256=RJpUbWDudjknRMtO_Kf8MGZ5Hv1twpPWac2u5kpV4Vw,7719
62
62
  sqlglot/optimizer/eliminate_ctes.py,sha256=fUBM0RUnPrm2sYptEWBux98B7fcx7W-BM1zVqfgDz9c,1448
63
63
  sqlglot/optimizer/eliminate_joins.py,sha256=2iYtG93aJGxvURqm1BVPosrnnnQ_IXI14RcD4pM8eHc,5942
@@ -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=LUlHSSyKshgWIhn4es2PzR1iAvMoSkwHY2t8h07Y32I,45037
74
+ sqlglot/optimizer/qualify_columns.py,sha256=7aabZhD-dKNiwIW_ZjOEr0RPbWfhSbuR-WI6NnVCZAA,45298
75
75
  sqlglot/optimizer/qualify_tables.py,sha256=dA4ZazL7ShQh2JgBwpHuG-4c5lBw1TNzCnuN7m0iVTA,6645
76
76
  sqlglot/optimizer/scope.py,sha256=UOTrbwqcTc5iRQf0WStgYWXpE24w6riZy-tJYA18yTw,31229
77
77
  sqlglot/optimizer/simplify.py,sha256=-_yus42OYwqjQ9a2TSGhtG2G0pSkInUry1z7hEMz2pY,51062
78
78
  sqlglot/optimizer/unnest_subqueries.py,sha256=kzWUVDlxs8z9nmRx-8U-pHXPtVZhEIwkKqmKhr2QLvc,10908
79
- sqlglot-27.14.0.dist-info/licenses/LICENSE,sha256=p1Yk0B4oa0l8Rh-_dYyy75d8spjPd_vTloXfz4FWxys,1065
80
- sqlglot-27.14.0.dist-info/METADATA,sha256=BYDS9AxQRhQ_DsItPkMNCkZR3NfunsRSWM7kkNoPCDY,20682
81
- sqlglot-27.14.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
- sqlglot-27.14.0.dist-info/top_level.txt,sha256=5kRskCGA_gVADF9rSfSzPdLHXqvfMusDYeHePfNY2nQ,8
83
- sqlglot-27.14.0.dist-info/RECORD,,
79
+ sqlglot-27.15.1.dist-info/licenses/LICENSE,sha256=p1Yk0B4oa0l8Rh-_dYyy75d8spjPd_vTloXfz4FWxys,1065
80
+ sqlglot-27.15.1.dist-info/METADATA,sha256=8AtINMRFBT71fI3AeuKwjYmOPm3PRDtPEnjqBauQHas,20682
81
+ sqlglot-27.15.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
+ sqlglot-27.15.1.dist-info/top_level.txt,sha256=5kRskCGA_gVADF9rSfSzPdLHXqvfMusDYeHePfNY2nQ,8
83
+ sqlglot-27.15.1.dist-info/RECORD,,