sqlglot 27.27.0__py3-none-any.whl → 28.4.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.
Files changed (68) hide show
  1. sqlglot/__init__.py +1 -0
  2. sqlglot/__main__.py +6 -4
  3. sqlglot/_version.py +2 -2
  4. sqlglot/dialects/bigquery.py +118 -279
  5. sqlglot/dialects/clickhouse.py +73 -5
  6. sqlglot/dialects/databricks.py +38 -1
  7. sqlglot/dialects/dialect.py +354 -275
  8. sqlglot/dialects/dremio.py +4 -1
  9. sqlglot/dialects/duckdb.py +754 -25
  10. sqlglot/dialects/exasol.py +243 -10
  11. sqlglot/dialects/hive.py +8 -8
  12. sqlglot/dialects/mysql.py +14 -4
  13. sqlglot/dialects/oracle.py +29 -0
  14. sqlglot/dialects/postgres.py +60 -26
  15. sqlglot/dialects/presto.py +47 -16
  16. sqlglot/dialects/redshift.py +16 -0
  17. sqlglot/dialects/risingwave.py +3 -0
  18. sqlglot/dialects/singlestore.py +12 -3
  19. sqlglot/dialects/snowflake.py +239 -218
  20. sqlglot/dialects/spark.py +15 -4
  21. sqlglot/dialects/spark2.py +11 -48
  22. sqlglot/dialects/sqlite.py +10 -0
  23. sqlglot/dialects/starrocks.py +3 -0
  24. sqlglot/dialects/teradata.py +5 -8
  25. sqlglot/dialects/trino.py +6 -0
  26. sqlglot/dialects/tsql.py +61 -22
  27. sqlglot/diff.py +4 -2
  28. sqlglot/errors.py +69 -0
  29. sqlglot/executor/__init__.py +5 -10
  30. sqlglot/executor/python.py +1 -29
  31. sqlglot/expressions.py +637 -100
  32. sqlglot/generator.py +160 -43
  33. sqlglot/helper.py +2 -44
  34. sqlglot/lineage.py +10 -4
  35. sqlglot/optimizer/annotate_types.py +247 -140
  36. sqlglot/optimizer/canonicalize.py +6 -1
  37. sqlglot/optimizer/eliminate_joins.py +1 -1
  38. sqlglot/optimizer/eliminate_subqueries.py +2 -2
  39. sqlglot/optimizer/merge_subqueries.py +5 -5
  40. sqlglot/optimizer/normalize.py +20 -13
  41. sqlglot/optimizer/normalize_identifiers.py +17 -3
  42. sqlglot/optimizer/optimizer.py +4 -0
  43. sqlglot/optimizer/pushdown_predicates.py +1 -1
  44. sqlglot/optimizer/qualify.py +18 -10
  45. sqlglot/optimizer/qualify_columns.py +122 -275
  46. sqlglot/optimizer/qualify_tables.py +128 -76
  47. sqlglot/optimizer/resolver.py +374 -0
  48. sqlglot/optimizer/scope.py +27 -16
  49. sqlglot/optimizer/simplify.py +1075 -959
  50. sqlglot/optimizer/unnest_subqueries.py +12 -2
  51. sqlglot/parser.py +296 -170
  52. sqlglot/planner.py +2 -2
  53. sqlglot/schema.py +15 -4
  54. sqlglot/tokens.py +42 -7
  55. sqlglot/transforms.py +77 -22
  56. sqlglot/typing/__init__.py +316 -0
  57. sqlglot/typing/bigquery.py +376 -0
  58. sqlglot/typing/hive.py +12 -0
  59. sqlglot/typing/presto.py +24 -0
  60. sqlglot/typing/snowflake.py +505 -0
  61. sqlglot/typing/spark2.py +58 -0
  62. sqlglot/typing/tsql.py +9 -0
  63. {sqlglot-27.27.0.dist-info → sqlglot-28.4.0.dist-info}/METADATA +2 -2
  64. sqlglot-28.4.0.dist-info/RECORD +92 -0
  65. sqlglot-27.27.0.dist-info/RECORD +0 -84
  66. {sqlglot-27.27.0.dist-info → sqlglot-28.4.0.dist-info}/WHEEL +0 -0
  67. {sqlglot-27.27.0.dist-info → sqlglot-28.4.0.dist-info}/licenses/LICENSE +0 -0
  68. {sqlglot-27.27.0.dist-info → sqlglot-28.4.0.dist-info}/top_level.txt +0 -0
sqlglot/parser.py CHANGED
@@ -7,7 +7,14 @@ import typing as t
7
7
  from collections import defaultdict
8
8
 
9
9
  from sqlglot import exp
10
- from sqlglot.errors import ErrorLevel, ParseError, TokenError, concat_messages, merge_errors
10
+ from sqlglot.errors import (
11
+ ErrorLevel,
12
+ ParseError,
13
+ TokenError,
14
+ concat_messages,
15
+ highlight_sql,
16
+ merge_errors,
17
+ )
11
18
  from sqlglot.helper import apply_index_offset, ensure_list, seq_get
12
19
  from sqlglot.time import format_time
13
20
  from sqlglot.tokens import Token, Tokenizer, TokenType
@@ -97,6 +104,8 @@ def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Di
97
104
  )
98
105
  if len(args) > 2 and expr_type is exp.JSONExtract:
99
106
  expression.set("expressions", args[2:])
107
+ if expr_type is exp.JSONExtractScalar:
108
+ expression.set("scalar_only", dialect.JSON_EXTRACT_SCALAR_SCALAR_ONLY)
100
109
 
101
110
  return expression
102
111
 
@@ -226,7 +235,12 @@ class Parser(metaclass=_Parser):
226
235
  end=seq_get(args, 1),
227
236
  step=seq_get(args, 2) or exp.Interval(this=exp.Literal.string(1), unit=exp.var("DAY")),
228
237
  ),
238
+ "GENERATE_UUID": lambda args, dialect: exp.Uuid(
239
+ is_string=dialect.UUID_IS_STRING_TYPE or None
240
+ ),
229
241
  "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
242
+ "GREATEST": lambda args: exp.Greatest(this=seq_get(args, 0), expressions=args[1:]),
243
+ "LEAST": lambda args: exp.Least(this=seq_get(args, 0), expressions=args[1:]),
230
244
  "HEX": build_hex,
231
245
  "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
232
246
  "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
@@ -265,6 +279,7 @@ class Parser(metaclass=_Parser):
265
279
  ),
266
280
  "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
267
281
  "UPPER": build_upper,
282
+ "UUID": lambda args, dialect: exp.Uuid(is_string=dialect.UUID_IS_STRING_TYPE or None),
268
283
  "VAR_MAP": build_var_map,
269
284
  }
270
285
 
@@ -274,9 +289,13 @@ class Parser(metaclass=_Parser):
274
289
  TokenType.CURRENT_TIME: exp.CurrentTime,
275
290
  TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
276
291
  TokenType.CURRENT_USER: exp.CurrentUser,
292
+ TokenType.LOCALTIME: exp.Localtime,
293
+ TokenType.LOCALTIMESTAMP: exp.Localtimestamp,
294
+ TokenType.CURRENT_ROLE: exp.CurrentRole,
277
295
  }
278
296
 
279
297
  STRUCT_TYPE_TOKENS = {
298
+ TokenType.FILE,
280
299
  TokenType.NESTED,
281
300
  TokenType.OBJECT,
282
301
  TokenType.STRUCT,
@@ -316,6 +335,7 @@ class Parser(metaclass=_Parser):
316
335
  TokenType.UINT,
317
336
  TokenType.BIGINT,
318
337
  TokenType.UBIGINT,
338
+ TokenType.BIGNUM,
319
339
  TokenType.INT128,
320
340
  TokenType.UINT128,
321
341
  TokenType.INT256,
@@ -346,6 +366,7 @@ class Parser(metaclass=_Parser):
346
366
  TokenType.TINYTEXT,
347
367
  TokenType.TIME,
348
368
  TokenType.TIMETZ,
369
+ TokenType.TIME_NS,
349
370
  TokenType.TIMESTAMP,
350
371
  TokenType.TIMESTAMP_S,
351
372
  TokenType.TIMESTAMP_MS,
@@ -376,6 +397,7 @@ class Parser(metaclass=_Parser):
376
397
  TokenType.DECIMAL64,
377
398
  TokenType.DECIMAL128,
378
399
  TokenType.DECIMAL256,
400
+ TokenType.DECFLOAT,
379
401
  TokenType.UDECIMAL,
380
402
  TokenType.BIGDECIMAL,
381
403
  TokenType.UUID,
@@ -485,6 +507,7 @@ class Parser(metaclass=_Parser):
485
507
  # Tokens that can represent identifiers
486
508
  ID_VAR_TOKENS = {
487
509
  TokenType.ALL,
510
+ TokenType.ANALYZE,
488
511
  TokenType.ATTACH,
489
512
  TokenType.VAR,
490
513
  TokenType.ANTI,
@@ -532,12 +555,14 @@ class Parser(metaclass=_Parser):
532
555
  TokenType.LIMIT,
533
556
  TokenType.LOAD,
534
557
  TokenType.LOCK,
558
+ TokenType.MATCH,
535
559
  TokenType.MERGE,
536
560
  TokenType.NATURAL,
537
561
  TokenType.NEXT,
538
562
  TokenType.OFFSET,
539
563
  TokenType.OPERATOR,
540
564
  TokenType.ORDINALITY,
565
+ TokenType.OVER,
541
566
  TokenType.OVERLAPS,
542
567
  TokenType.OVERWRITE,
543
568
  TokenType.PARTITION,
@@ -614,6 +639,7 @@ class Parser(metaclass=_Parser):
614
639
  TokenType.CURRENT_TIMESTAMP,
615
640
  TokenType.CURRENT_TIME,
616
641
  TokenType.CURRENT_USER,
642
+ TokenType.CURRENT_CATALOG,
617
643
  TokenType.FILTER,
618
644
  TokenType.FIRST,
619
645
  TokenType.FORMAT,
@@ -625,6 +651,8 @@ class Parser(metaclass=_Parser):
625
651
  TokenType.ILIKE,
626
652
  TokenType.INSERT,
627
653
  TokenType.LIKE,
654
+ TokenType.LOCALTIME,
655
+ TokenType.LOCALTIMESTAMP,
628
656
  TokenType.MERGE,
629
657
  TokenType.NEXT,
630
658
  TokenType.OFFSET,
@@ -633,6 +661,7 @@ class Parser(metaclass=_Parser):
633
661
  TokenType.REPLACE,
634
662
  TokenType.RLIKE,
635
663
  TokenType.ROW,
664
+ TokenType.SESSION_USER,
636
665
  TokenType.UNNEST,
637
666
  TokenType.VAR,
638
667
  TokenType.LEFT,
@@ -746,7 +775,7 @@ class Parser(metaclass=_Parser):
746
775
  TokenType.ARROW: lambda self, expressions: self.expression(
747
776
  exp.Lambda,
748
777
  this=self._replace_lambda(
749
- self._parse_assignment(),
778
+ self._parse_disjunction(),
750
779
  expressions,
751
780
  ),
752
781
  expressions=expressions,
@@ -754,7 +783,7 @@ class Parser(metaclass=_Parser):
754
783
  TokenType.FARROW: lambda self, expressions: self.expression(
755
784
  exp.Kwarg,
756
785
  this=exp.var(expressions[0].name),
757
- expression=self._parse_assignment(),
786
+ expression=self._parse_disjunction(),
758
787
  ),
759
788
  }
760
789
 
@@ -779,6 +808,7 @@ class Parser(metaclass=_Parser):
779
808
  this=this,
780
809
  expression=self.dialect.to_json_path(path),
781
810
  only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
811
+ scalar_only=self.dialect.JSON_EXTRACT_SCALAR_SCALAR_ONLY,
782
812
  ),
783
813
  TokenType.HASH_ARROW: lambda self, this, path: self.expression(
784
814
  exp.JSONBExtract,
@@ -806,7 +836,7 @@ class Parser(metaclass=_Parser):
806
836
  exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
807
837
  exp.Column: lambda self: self._parse_column(),
808
838
  exp.ColumnDef: lambda self: self._parse_column_def(self._parse_column()),
809
- exp.Condition: lambda self: self._parse_assignment(),
839
+ exp.Condition: lambda self: self._parse_disjunction(),
810
840
  exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
811
841
  exp.Expression: lambda self: self._parse_expression(),
812
842
  exp.From: lambda self: self._parse_from(joins=True),
@@ -881,33 +911,33 @@ class Parser(metaclass=_Parser):
881
911
  }
882
912
 
883
913
  STRING_PARSERS = {
884
- TokenType.HEREDOC_STRING: lambda self, token: self.expression(
885
- exp.RawString, this=token.text
886
- ),
887
- TokenType.NATIONAL_STRING: lambda self, token: self.expression(
888
- exp.National, this=token.text
889
- ),
890
- TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
914
+ TokenType.HEREDOC_STRING: lambda self, token: self.expression(exp.RawString, token=token),
915
+ TokenType.NATIONAL_STRING: lambda self, token: self.expression(exp.National, token=token),
916
+ TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, token=token),
891
917
  TokenType.STRING: lambda self, token: self.expression(
892
- exp.Literal, this=token.text, is_string=True
918
+ exp.Literal, token=token, is_string=True
893
919
  ),
894
920
  TokenType.UNICODE_STRING: lambda self, token: self.expression(
895
921
  exp.UnicodeString,
896
- this=token.text,
922
+ token=token,
897
923
  escape=self._match_text_seq("UESCAPE") and self._parse_string(),
898
924
  ),
899
925
  }
900
926
 
901
927
  NUMERIC_PARSERS = {
902
- TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
903
- TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
928
+ TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, token=token),
929
+ TokenType.BYTE_STRING: lambda self, token: self.expression(
930
+ exp.ByteString,
931
+ token=token,
932
+ is_bytes=self.dialect.BYTE_STRING_IS_BYTES_TYPE or None,
933
+ ),
904
934
  TokenType.HEX_STRING: lambda self, token: self.expression(
905
935
  exp.HexString,
906
- this=token.text,
936
+ token=token,
907
937
  is_integer=self.dialect.HEX_STRING_IS_INTEGER_TYPE or None,
908
938
  ),
909
939
  TokenType.NUMBER: lambda self, token: self.expression(
910
- exp.Literal, this=token.text, is_string=False
940
+ exp.Literal, token=token, is_string=False
911
941
  ),
912
942
  }
913
943
 
@@ -1243,6 +1273,7 @@ class Parser(metaclass=_Parser):
1243
1273
  "EXTRACT": lambda self: self._parse_extract(),
1244
1274
  "FLOOR": lambda self: self._parse_ceil_floor(exp.Floor),
1245
1275
  "GAP_FILL": lambda self: self._parse_gap_fill(),
1276
+ "INITCAP": lambda self: self._parse_initcap(),
1246
1277
  "JSON_OBJECT": lambda self: self._parse_json_object(),
1247
1278
  "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
1248
1279
  "JSON_TABLE": lambda self: self._parse_json_table(),
@@ -1442,6 +1473,8 @@ class Parser(metaclass=_Parser):
1442
1473
  # The style options for the DESCRIBE statement
1443
1474
  DESCRIBE_STYLES = {"ANALYZE", "EXTENDED", "FORMATTED", "HISTORY"}
1444
1475
 
1476
+ SET_ASSIGNMENT_DELIMITERS = {"=", ":=", "TO"}
1477
+
1445
1478
  # The style options for the ANALYZE statement
1446
1479
  ANALYZE_STYLES = {
1447
1480
  "BUFFER_USAGE_LIMIT",
@@ -1473,7 +1506,7 @@ class Parser(metaclass=_Parser):
1473
1506
 
1474
1507
  RECURSIVE_CTE_SEARCH_KIND = {"BREADTH", "DEPTH", "CYCLE"}
1475
1508
 
1476
- MODIFIABLES = (exp.Query, exp.Table, exp.TableFromRows)
1509
+ MODIFIABLES = (exp.Query, exp.Table, exp.TableFromRows, exp.Values)
1477
1510
 
1478
1511
  STRICT_CAST = True
1479
1512
 
@@ -1716,15 +1749,15 @@ class Parser(metaclass=_Parser):
1716
1749
  error level setting.
1717
1750
  """
1718
1751
  token = token or self._curr or self._prev or Token.string("")
1719
- start = token.start
1720
- end = token.end + 1
1721
- start_context = self.sql[max(start - self.error_message_context, 0) : start]
1722
- highlight = self.sql[start:end]
1723
- end_context = self.sql[end : end + self.error_message_context]
1752
+ formatted_sql, start_context, highlight, end_context = highlight_sql(
1753
+ sql=self.sql,
1754
+ positions=[(token.start, token.end)],
1755
+ context_length=self.error_message_context,
1756
+ )
1757
+ formatted_message = f"{message}. Line {token.line}, Col: {token.col}.\n {formatted_sql}"
1724
1758
 
1725
1759
  error = ParseError.new(
1726
- f"{message}. Line {token.line}, Col: {token.col}.\n"
1727
- f" {start_context}\033[4m{highlight}\033[0m{end_context}",
1760
+ formatted_message,
1728
1761
  description=message,
1729
1762
  line=token.line,
1730
1763
  col=token.col,
@@ -1739,7 +1772,11 @@ class Parser(metaclass=_Parser):
1739
1772
  self.errors.append(error)
1740
1773
 
1741
1774
  def expression(
1742
- self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1775
+ self,
1776
+ exp_class: t.Type[E],
1777
+ token: t.Optional[Token] = None,
1778
+ comments: t.Optional[t.List[str]] = None,
1779
+ **kwargs,
1743
1780
  ) -> E:
1744
1781
  """
1745
1782
  Creates a new, validated Expression.
@@ -1752,7 +1789,11 @@ class Parser(metaclass=_Parser):
1752
1789
  Returns:
1753
1790
  The target expression.
1754
1791
  """
1755
- instance = exp_class(**kwargs)
1792
+ if token:
1793
+ instance = exp_class(this=token.text, **kwargs)
1794
+ instance.update_positions(token)
1795
+ else:
1796
+ instance = exp_class(**kwargs)
1756
1797
  instance.add_comments(comments) if comments else self._add_comments(instance)
1757
1798
  return self.validate_expression(instance)
1758
1799
 
@@ -2246,7 +2287,10 @@ class Parser(metaclass=_Parser):
2246
2287
  return self._parse_sortkey(compound=True)
2247
2288
 
2248
2289
  if self._match_text_seq("SQL", "SECURITY"):
2249
- return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
2290
+ return self.expression(
2291
+ exp.SqlSecurityProperty,
2292
+ this=self._match_texts(("DEFINER", "INVOKER")) and self._prev.text.upper(),
2293
+ )
2250
2294
 
2251
2295
  index = self._index
2252
2296
 
@@ -2365,10 +2409,8 @@ class Parser(metaclass=_Parser):
2365
2409
  self._match(TokenType.EQ)
2366
2410
  prop = self.expression(
2367
2411
  exp.WithSystemVersioningProperty,
2368
- **{ # type: ignore
2369
- "on": True,
2370
- "with": with_,
2371
- },
2412
+ on=True,
2413
+ with_=with_,
2372
2414
  )
2373
2415
 
2374
2416
  if self._match_text_seq("OFF"):
@@ -2683,7 +2725,7 @@ class Parser(metaclass=_Parser):
2683
2725
 
2684
2726
  def _parse_partition_by(self) -> t.List[exp.Expression]:
2685
2727
  if self._match(TokenType.PARTITION_BY):
2686
- return self._parse_csv(self._parse_assignment)
2728
+ return self._parse_csv(self._parse_disjunction)
2687
2729
  return []
2688
2730
 
2689
2731
  def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
@@ -2941,15 +2983,9 @@ class Parser(metaclass=_Parser):
2941
2983
  self._match(TokenType.TABLE)
2942
2984
  is_function = self._match(TokenType.FUNCTION)
2943
2985
 
2944
- this = (
2945
- self._parse_table(schema=True, parse_partition=True)
2946
- if not is_function
2947
- else self._parse_function()
2948
- )
2949
- if isinstance(this, exp.Table) and self._match(TokenType.ALIAS, advance=False):
2950
- this.set("alias", self._parse_table_alias())
2986
+ this = self._parse_function() if is_function else self._parse_insert_table()
2951
2987
 
2952
- returning = self._parse_returning()
2988
+ returning = self._parse_returning() # TSQL allows RETURNING before source
2953
2989
 
2954
2990
  return self.expression(
2955
2991
  exp.Insert,
@@ -2960,7 +2996,8 @@ class Parser(metaclass=_Parser):
2960
2996
  stored=self._match_text_seq("STORED") and self._parse_stored(),
2961
2997
  by_name=self._match_text_seq("BY", "NAME"),
2962
2998
  exists=self._parse_exists(),
2963
- where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
2999
+ where=self._match_pair(TokenType.REPLACE, TokenType.WHERE)
3000
+ and self._parse_disjunction(),
2964
3001
  partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
2965
3002
  settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
2966
3003
  default=self._match_text_seq("DEFAULT", "VALUES"),
@@ -2973,6 +3010,12 @@ class Parser(metaclass=_Parser):
2973
3010
  source=self._match(TokenType.TABLE) and self._parse_table(),
2974
3011
  )
2975
3012
 
3013
+ def _parse_insert_table(self) -> t.Optional[exp.Expression]:
3014
+ this = self._parse_table(schema=True, parse_partition=True)
3015
+ if isinstance(this, exp.Table) and self._match(TokenType.ALIAS, advance=False):
3016
+ this.set("alias", self._parse_table_alias())
3017
+ return this
3018
+
2976
3019
  def _parse_kill(self) -> exp.Kill:
2977
3020
  kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2978
3021
 
@@ -3039,10 +3082,8 @@ class Parser(metaclass=_Parser):
3039
3082
  return None
3040
3083
  return self.expression(
3041
3084
  exp.SerdeProperties,
3042
- **{ # type: ignore
3043
- "expressions": self._parse_wrapped_properties(),
3044
- "with": with_,
3045
- },
3085
+ expressions=self._parse_wrapped_properties(),
3086
+ with_=with_,
3046
3087
  )
3047
3088
 
3048
3089
  def _parse_row_format(
@@ -3117,6 +3158,7 @@ class Parser(metaclass=_Parser):
3117
3158
  cluster=self._match(TokenType.ON) and self._parse_on_property(),
3118
3159
  where=self._parse_where(),
3119
3160
  returning=returning or self._parse_returning(),
3161
+ order=self._parse_order(),
3120
3162
  limit=self._parse_limit(),
3121
3163
  )
3122
3164
 
@@ -3130,7 +3172,7 @@ class Parser(metaclass=_Parser):
3130
3172
  elif self._match(TokenType.RETURNING, advance=False):
3131
3173
  kwargs["returning"] = self._parse_returning()
3132
3174
  elif self._match(TokenType.FROM, advance=False):
3133
- kwargs["from"] = self._parse_from(joins=True)
3175
+ kwargs["from_"] = self._parse_from(joins=True)
3134
3176
  elif self._match(TokenType.WHERE, advance=False):
3135
3177
  kwargs["where"] = self._parse_where()
3136
3178
  elif self._match(TokenType.ORDER_BY, advance=False):
@@ -3187,7 +3229,7 @@ class Parser(metaclass=_Parser):
3187
3229
  return self.expression(
3188
3230
  exp.Partition,
3189
3231
  subpartition=self._prev.text.upper() == "SUBPARTITION",
3190
- expressions=self._parse_wrapped_csv(self._parse_assignment),
3232
+ expressions=self._parse_wrapped_csv(self._parse_disjunction),
3191
3233
  )
3192
3234
 
3193
3235
  def _parse_value(self, values: bool = True) -> t.Optional[exp.Tuple]:
@@ -3220,11 +3262,12 @@ class Parser(metaclass=_Parser):
3220
3262
  # Support parentheses for duckdb FROM-first syntax
3221
3263
  select = self._parse_select(from_=from_)
3222
3264
  if select:
3223
- if not select.args.get("from"):
3224
- select.set("from", from_)
3265
+ if not select.args.get("from_"):
3266
+ select.set("from_", from_)
3225
3267
  this = select
3226
3268
  else:
3227
3269
  this = exp.select("*").from_(t.cast(exp.From, from_))
3270
+ this = self._parse_query_modifiers(self._parse_set_operations(this))
3228
3271
  else:
3229
3272
  this = (
3230
3273
  self._parse_table(consume_pipe=True)
@@ -3283,8 +3326,11 @@ class Parser(metaclass=_Parser):
3283
3326
  self.raise_error("Failed to parse any statement following CTE")
3284
3327
  return cte
3285
3328
 
3286
- if "with" in this.arg_types:
3287
- this.set("with", cte)
3329
+ while isinstance(this, exp.Subquery) and this.is_wrapper:
3330
+ this = this.this
3331
+
3332
+ if "with_" in this.arg_types:
3333
+ this.set("with_", cte)
3288
3334
  else:
3289
3335
  self.raise_error(f"{this.key} does not support CTE")
3290
3336
  this = cte
@@ -3293,7 +3339,7 @@ class Parser(metaclass=_Parser):
3293
3339
 
3294
3340
  # duckdb supports leading with FROM x
3295
3341
  from_ = (
3296
- self._parse_from(consume_pipe=True)
3342
+ self._parse_from(joins=True, consume_pipe=True)
3297
3343
  if self._match(TokenType.FROM, advance=False)
3298
3344
  else None
3299
3345
  )
@@ -3350,7 +3396,7 @@ class Parser(metaclass=_Parser):
3350
3396
  from_ = self._parse_from()
3351
3397
 
3352
3398
  if from_:
3353
- this.set("from", from_)
3399
+ this.set("from_", from_)
3354
3400
 
3355
3401
  this = self._parse_query_modifiers(this)
3356
3402
  elif (table or nested) and self._match(TokenType.L_PAREN):
@@ -3370,12 +3416,6 @@ class Parser(metaclass=_Parser):
3370
3416
  return self.expression(exp.Summarize, this=this, table=table)
3371
3417
  elif self._match(TokenType.DESCRIBE):
3372
3418
  this = self._parse_describe()
3373
- elif self._match_text_seq("STREAM"):
3374
- this = self._parse_function()
3375
- if this:
3376
- this = self.expression(exp.Stream, this=this)
3377
- else:
3378
- self._retreat(self._index - 1)
3379
3419
  else:
3380
3420
  this = None
3381
3421
 
@@ -3522,7 +3562,7 @@ class Parser(metaclass=_Parser):
3522
3562
  def _implicit_unnests_to_explicit(self, this: E) -> E:
3523
3563
  from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
3524
3564
 
3525
- refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
3565
+ refs = {_norm(this.args["from_"].this.copy(), dialect=self.dialect).alias_or_name}
3526
3566
  for i, join in enumerate(this.args.get("joins") or []):
3527
3567
  table = join.this
3528
3568
  normalized_table = table.copy()
@@ -3587,7 +3627,7 @@ class Parser(metaclass=_Parser):
3587
3627
  continue
3588
3628
  break
3589
3629
 
3590
- if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
3630
+ if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from_"):
3591
3631
  this = self._implicit_unnests_to_explicit(this)
3592
3632
 
3593
3633
  return this
@@ -3807,6 +3847,16 @@ class Parser(metaclass=_Parser):
3807
3847
  ordinality=ordinality,
3808
3848
  )
3809
3849
 
3850
+ def _parse_stream(self) -> t.Optional[exp.Stream]:
3851
+ index = self._index
3852
+ if self._match_text_seq("STREAM"):
3853
+ this = self._try_parse(self._parse_table)
3854
+ if this:
3855
+ return self.expression(exp.Stream, this=this)
3856
+
3857
+ self._retreat(index)
3858
+ return None
3859
+
3810
3860
  def _parse_join_parts(
3811
3861
  self,
3812
3862
  ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
@@ -3862,11 +3912,11 @@ class Parser(metaclass=_Parser):
3862
3912
  )
3863
3913
 
3864
3914
  if method:
3865
- kwargs["method"] = method.text
3915
+ kwargs["method"] = method.text.upper()
3866
3916
  if side:
3867
- kwargs["side"] = side.text
3917
+ kwargs["side"] = side.text.upper()
3868
3918
  if kind:
3869
- kwargs["kind"] = kind.text
3919
+ kwargs["kind"] = kind.text.upper()
3870
3920
  if hint:
3871
3921
  kwargs["hint"] = hint
3872
3922
 
@@ -3874,7 +3924,7 @@ class Parser(metaclass=_Parser):
3874
3924
  kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
3875
3925
 
3876
3926
  if self._match(TokenType.ON):
3877
- kwargs["on"] = self._parse_assignment()
3927
+ kwargs["on"] = self._parse_disjunction()
3878
3928
  elif self._match(TokenType.USING):
3879
3929
  kwargs["using"] = self._parse_using_identifiers()
3880
3930
  elif (
@@ -3887,7 +3937,7 @@ class Parser(metaclass=_Parser):
3887
3937
  joins: t.Optional[list] = list(self._parse_joins())
3888
3938
 
3889
3939
  if joins and self._match(TokenType.ON):
3890
- kwargs["on"] = self._parse_assignment()
3940
+ kwargs["on"] = self._parse_disjunction()
3891
3941
  elif joins and self._match(TokenType.USING):
3892
3942
  kwargs["using"] = self._parse_using_identifiers()
3893
3943
  else:
@@ -3913,7 +3963,7 @@ class Parser(metaclass=_Parser):
3913
3963
  return self.expression(exp.Join, comments=comments, **kwargs)
3914
3964
 
3915
3965
  def _parse_opclass(self) -> t.Optional[exp.Expression]:
3916
- this = self._parse_assignment()
3966
+ this = self._parse_disjunction()
3917
3967
 
3918
3968
  if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
3919
3969
  return this
@@ -4099,6 +4149,10 @@ class Parser(metaclass=_Parser):
4099
4149
  parse_partition: bool = False,
4100
4150
  consume_pipe: bool = False,
4101
4151
  ) -> t.Optional[exp.Expression]:
4152
+ stream = self._parse_stream()
4153
+ if stream:
4154
+ return stream
4155
+
4102
4156
  lateral = self._parse_lateral()
4103
4157
  if lateral:
4104
4158
  return lateral
@@ -4161,6 +4215,11 @@ class Parser(metaclass=_Parser):
4161
4215
  if alias:
4162
4216
  this.set("alias", alias)
4163
4217
 
4218
+ if self._match(TokenType.INDEXED_BY):
4219
+ this.set("indexed", self._parse_table_parts())
4220
+ elif self._match_text_seq("NOT", "INDEXED"):
4221
+ this.set("indexed", False)
4222
+
4164
4223
  if isinstance(this, exp.Table) and self._match_text_seq("AT"):
4165
4224
  return self.expression(
4166
4225
  exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
@@ -4400,7 +4459,7 @@ class Parser(metaclass=_Parser):
4400
4459
  expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
4401
4460
  into = self._parse_unpivot_columns()
4402
4461
  using = self._match(TokenType.USING) and self._parse_csv(
4403
- lambda: self._parse_alias(self._parse_function())
4462
+ lambda: self._parse_alias(self._parse_column())
4404
4463
  )
4405
4464
  group = self._parse_group()
4406
4465
 
@@ -4429,16 +4488,18 @@ class Parser(metaclass=_Parser):
4429
4488
 
4430
4489
  value = self._parse_column()
4431
4490
 
4432
- if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
4433
- self.raise_error("Expecting IN (")
4491
+ if not self._match(TokenType.IN):
4492
+ self.raise_error("Expecting IN")
4434
4493
 
4435
- if self._match(TokenType.ANY):
4436
- exprs: t.List[exp.Expression] = ensure_list(exp.PivotAny(this=self._parse_order()))
4437
- else:
4438
- exprs = self._parse_csv(_parse_aliased_expression)
4494
+ if self._match(TokenType.L_PAREN):
4495
+ if self._match(TokenType.ANY):
4496
+ exprs: t.List[exp.Expression] = ensure_list(exp.PivotAny(this=self._parse_order()))
4497
+ else:
4498
+ exprs = self._parse_csv(_parse_aliased_expression)
4499
+ self._match_r_paren()
4500
+ return self.expression(exp.In, this=value, expressions=exprs)
4439
4501
 
4440
- self._match_r_paren()
4441
- return self.expression(exp.In, this=value, expressions=exprs)
4502
+ return self.expression(exp.In, this=value, field=self._parse_id_var())
4442
4503
 
4443
4504
  def _parse_pivot_aggregation(self) -> t.Optional[exp.Expression]:
4444
4505
  func = self._parse_function()
@@ -4558,7 +4619,7 @@ class Parser(metaclass=_Parser):
4558
4619
  return None
4559
4620
 
4560
4621
  return self.expression(
4561
- exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
4622
+ exp.PreWhere, comments=self._prev_comments, this=self._parse_disjunction()
4562
4623
  )
4563
4624
 
4564
4625
  def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
@@ -4566,7 +4627,7 @@ class Parser(metaclass=_Parser):
4566
4627
  return None
4567
4628
 
4568
4629
  return self.expression(
4569
- exp.Where, comments=self._prev_comments, this=self._parse_assignment()
4630
+ exp.Where, comments=self._prev_comments, this=self._parse_disjunction()
4570
4631
  )
4571
4632
 
4572
4633
  def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
@@ -4591,7 +4652,7 @@ class Parser(metaclass=_Parser):
4591
4652
  self._parse_csv(
4592
4653
  lambda: None
4593
4654
  if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
4594
- else self._parse_assignment()
4655
+ else self._parse_disjunction()
4595
4656
  )
4596
4657
  )
4597
4658
 
@@ -4624,7 +4685,7 @@ class Parser(metaclass=_Parser):
4624
4685
  return None
4625
4686
 
4626
4687
  return self.expression(
4627
- kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_column)
4688
+ kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_bitwise)
4628
4689
  )
4629
4690
 
4630
4691
  def _parse_grouping_sets(self) -> t.Optional[exp.GroupingSets]:
@@ -4641,19 +4702,19 @@ class Parser(metaclass=_Parser):
4641
4702
  if not skip_having_token and not self._match(TokenType.HAVING):
4642
4703
  return None
4643
4704
  return self.expression(
4644
- exp.Having, comments=self._prev_comments, this=self._parse_assignment()
4705
+ exp.Having, comments=self._prev_comments, this=self._parse_disjunction()
4645
4706
  )
4646
4707
 
4647
4708
  def _parse_qualify(self) -> t.Optional[exp.Qualify]:
4648
4709
  if not self._match(TokenType.QUALIFY):
4649
4710
  return None
4650
- return self.expression(exp.Qualify, this=self._parse_assignment())
4711
+ return self.expression(exp.Qualify, this=self._parse_disjunction())
4651
4712
 
4652
4713
  def _parse_connect_with_prior(self) -> t.Optional[exp.Expression]:
4653
4714
  self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
4654
4715
  exp.Prior, this=self._parse_bitwise()
4655
4716
  )
4656
- connect = self._parse_assignment()
4717
+ connect = self._parse_disjunction()
4657
4718
  self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
4658
4719
  return connect
4659
4720
 
@@ -4661,7 +4722,7 @@ class Parser(metaclass=_Parser):
4661
4722
  if skip_start_token:
4662
4723
  start = None
4663
4724
  elif self._match(TokenType.START_WITH):
4664
- start = self._parse_assignment()
4725
+ start = self._parse_disjunction()
4665
4726
  else:
4666
4727
  return None
4667
4728
 
@@ -4670,14 +4731,14 @@ class Parser(metaclass=_Parser):
4670
4731
  connect = self._parse_connect_with_prior()
4671
4732
 
4672
4733
  if not start and self._match(TokenType.START_WITH):
4673
- start = self._parse_assignment()
4734
+ start = self._parse_disjunction()
4674
4735
 
4675
4736
  return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
4676
4737
 
4677
4738
  def _parse_name_as_expression(self) -> t.Optional[exp.Expression]:
4678
4739
  this = self._parse_id_var(any_token=True)
4679
4740
  if self._match(TokenType.ALIAS):
4680
- this = self.expression(exp.Alias, alias=this, this=self._parse_assignment())
4741
+ this = self.expression(exp.Alias, alias=this, this=self._parse_disjunction())
4681
4742
  return this
4682
4743
 
4683
4744
  def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
@@ -4711,7 +4772,7 @@ class Parser(metaclass=_Parser):
4711
4772
  def _parse_ordered(
4712
4773
  self, parse_method: t.Optional[t.Callable] = None
4713
4774
  ) -> t.Optional[exp.Ordered]:
4714
- this = parse_method() if parse_method else self._parse_assignment()
4775
+ this = parse_method() if parse_method else self._parse_disjunction()
4715
4776
  if not this:
4716
4777
  return None
4717
4778
 
@@ -4740,12 +4801,10 @@ class Parser(metaclass=_Parser):
4740
4801
  if self._match_text_seq("WITH", "FILL"):
4741
4802
  with_fill = self.expression(
4742
4803
  exp.WithFill,
4743
- **{ # type: ignore
4744
- "from": self._match(TokenType.FROM) and self._parse_bitwise(),
4745
- "to": self._match_text_seq("TO") and self._parse_bitwise(),
4746
- "step": self._match_text_seq("STEP") and self._parse_bitwise(),
4747
- "interpolate": self._parse_interpolate(),
4748
- },
4804
+ from_=self._match(TokenType.FROM) and self._parse_bitwise(),
4805
+ to=self._match_text_seq("TO") and self._parse_bitwise(),
4806
+ step=self._match_text_seq("STEP") and self._parse_bitwise(),
4807
+ interpolate=self._parse_interpolate(),
4749
4808
  )
4750
4809
  else:
4751
4810
  with_fill = None
@@ -4784,8 +4843,13 @@ class Parser(metaclass=_Parser):
4784
4843
  # Parsing LIMIT x% (i.e x PERCENT) as a term leads to an error, since
4785
4844
  # we try to build an exp.Mod expr. For that matter, we backtrack and instead
4786
4845
  # consume the factor plus parse the percentage separately
4787
- expression = self._try_parse(self._parse_term) or self._parse_factor()
4788
-
4846
+ index = self._index
4847
+ expression = self._try_parse(self._parse_term)
4848
+ if isinstance(expression, exp.Mod):
4849
+ self._retreat(index)
4850
+ expression = self._parse_factor()
4851
+ elif not expression:
4852
+ expression = self._parse_factor()
4789
4853
  limit_options = self._parse_limit_options()
4790
4854
 
4791
4855
  if self._match(TokenType.COMMA):
@@ -5009,7 +5073,7 @@ class Parser(metaclass=_Parser):
5009
5073
  return this
5010
5074
 
5011
5075
  this = expression
5012
- elif self._match(TokenType.ISNULL):
5076
+ elif self._match(TokenType.ISNULL) or (negate and self._match(TokenType.NULL)):
5013
5077
  this = self.expression(exp.Is, this=this, expression=exp.Null())
5014
5078
 
5015
5079
  # Postgres supports ISNULL and NOTNULL for conditions.
@@ -5053,10 +5117,13 @@ class Parser(metaclass=_Parser):
5053
5117
  unique = self._match(TokenType.UNIQUE)
5054
5118
  self._match_text_seq("KEYS")
5055
5119
  expression: t.Optional[exp.Expression] = self.expression(
5056
- exp.JSON, **{"this": kind, "with": _with, "unique": unique}
5120
+ exp.JSON,
5121
+ this=kind,
5122
+ with_=_with,
5123
+ unique=unique,
5057
5124
  )
5058
5125
  else:
5059
- expression = self._parse_primary() or self._parse_null()
5126
+ expression = self._parse_null() or self._parse_bitwise()
5060
5127
  if not expression:
5061
5128
  self._retreat(index)
5062
5129
  return None
@@ -5113,7 +5180,9 @@ class Parser(metaclass=_Parser):
5113
5180
  def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5114
5181
  if not self._match(TokenType.ESCAPE):
5115
5182
  return this
5116
- return self.expression(exp.Escape, this=this, expression=self._parse_string())
5183
+ return self.expression(
5184
+ exp.Escape, this=this, expression=self._parse_string() or self._parse_null()
5185
+ )
5117
5186
 
5118
5187
  def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
5119
5188
  index = self._index
@@ -5261,7 +5330,7 @@ class Parser(metaclass=_Parser):
5261
5330
 
5262
5331
  def _parse_factor(self) -> t.Optional[exp.Expression]:
5263
5332
  parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
5264
- this = parse_method()
5333
+ this = self._parse_at_time_zone(parse_method())
5265
5334
 
5266
5335
  while self._match_set(self.FACTOR):
5267
5336
  klass = self.FACTOR[self._prev.token_type]
@@ -5286,14 +5355,14 @@ class Parser(metaclass=_Parser):
5286
5355
  def _parse_unary(self) -> t.Optional[exp.Expression]:
5287
5356
  if self._match_set(self.UNARY_PARSERS):
5288
5357
  return self.UNARY_PARSERS[self._prev.token_type](self)
5289
- return self._parse_at_time_zone(self._parse_type())
5358
+ return self._parse_type()
5290
5359
 
5291
5360
  def _parse_type(
5292
5361
  self, parse_interval: bool = True, fallback_to_identifier: bool = False
5293
5362
  ) -> t.Optional[exp.Expression]:
5294
5363
  interval = parse_interval and self._parse_interval()
5295
5364
  if interval:
5296
- return interval
5365
+ return self._parse_column_ops(interval)
5297
5366
 
5298
5367
  index = self._index
5299
5368
  data_type = self._parse_types(check_func=True, allow_identifiers=False)
@@ -5499,7 +5568,7 @@ class Parser(metaclass=_Parser):
5499
5568
  self.raise_error("Expecting >")
5500
5569
 
5501
5570
  if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
5502
- values = self._parse_csv(self._parse_assignment)
5571
+ values = self._parse_csv(self._parse_disjunction)
5503
5572
  if not values and is_struct:
5504
5573
  values = None
5505
5574
  self._retreat(self._index - 1)
@@ -5591,12 +5660,14 @@ class Parser(metaclass=_Parser):
5591
5660
  break
5592
5661
 
5593
5662
  matched_array = False
5594
- values = self._parse_csv(self._parse_assignment) or None
5663
+ values = self._parse_csv(self._parse_disjunction) or None
5595
5664
  if (
5596
5665
  values
5597
5666
  and not schema
5598
5667
  and (
5599
- not self.dialect.SUPPORTS_FIXED_SIZE_ARRAYS or datatype_token == TokenType.ARRAY
5668
+ not self.dialect.SUPPORTS_FIXED_SIZE_ARRAYS
5669
+ or datatype_token == TokenType.ARRAY
5670
+ or not self._match(TokenType.R_BRACKET, advance=False)
5600
5671
  )
5601
5672
  ):
5602
5673
  # Retreating here means that we should not parse the following values as part of the data type, e.g. in DuckDB
@@ -5654,7 +5725,9 @@ class Parser(metaclass=_Parser):
5654
5725
  def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5655
5726
  if not self._match_text_seq("AT", "TIME", "ZONE"):
5656
5727
  return this
5657
- return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
5728
+ return self._parse_at_time_zone(
5729
+ self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
5730
+ )
5658
5731
 
5659
5732
  def _parse_column(self) -> t.Optional[exp.Expression]:
5660
5733
  this = self._parse_column_reference()
@@ -5814,7 +5887,7 @@ class Parser(metaclass=_Parser):
5814
5887
  this = self.expression(exp.Tuple)
5815
5888
  elif isinstance(this, exp.UNWRAPPED_QUERIES):
5816
5889
  this = self._parse_subquery(this=this, parse_alias=False)
5817
- elif isinstance(this, exp.Subquery):
5890
+ elif isinstance(this, (exp.Subquery, exp.Values)):
5818
5891
  this = self._parse_subquery(
5819
5892
  this=self._parse_query_modifiers(self._parse_set_operations(this)),
5820
5893
  parse_alias=False,
@@ -5845,7 +5918,9 @@ class Parser(metaclass=_Parser):
5845
5918
  expressions.append(exp.Literal.string(self._prev.text))
5846
5919
 
5847
5920
  if len(expressions) > 1:
5848
- return self.expression(exp.Concat, expressions=expressions)
5921
+ return self.expression(
5922
+ exp.Concat, expressions=expressions, coalesce=self.dialect.CONCAT_COALESCE
5923
+ )
5849
5924
 
5850
5925
  return primary
5851
5926
 
@@ -6061,7 +6136,7 @@ class Parser(metaclass=_Parser):
6061
6136
  def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
6062
6137
  literal = self._parse_primary()
6063
6138
  if literal:
6064
- return self.expression(exp.Introducer, this=token.text, expression=literal)
6139
+ return self.expression(exp.Introducer, token=token, expression=literal)
6065
6140
 
6066
6141
  return self._identifier_expression(token)
6067
6142
 
@@ -6100,7 +6175,7 @@ class Parser(metaclass=_Parser):
6100
6175
 
6101
6176
  if self._match(TokenType.DISTINCT):
6102
6177
  this = self.expression(
6103
- exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
6178
+ exp.Distinct, expressions=self._parse_csv(self._parse_disjunction)
6104
6179
  )
6105
6180
  else:
6106
6181
  this = self._parse_select_or_expression(alias=alias)
@@ -6148,7 +6223,7 @@ class Parser(metaclass=_Parser):
6148
6223
  ):
6149
6224
  persisted = self._prev.text.upper() == "MATERIALIZED"
6150
6225
  constraint_kind = exp.ComputedColumnConstraint(
6151
- this=self._parse_assignment(),
6226
+ this=self._parse_disjunction(),
6152
6227
  persisted=persisted or self._match_text_seq("PERSISTED"),
6153
6228
  data_type=exp.Var(this="AUTO")
6154
6229
  if self._match_text_seq("AUTO")
@@ -6463,6 +6538,14 @@ class Parser(metaclass=_Parser):
6463
6538
  and self._prev.token_type == TokenType.DESC
6464
6539
  )
6465
6540
 
6541
+ this = None
6542
+ if (
6543
+ self._curr.text.upper() not in self.CONSTRAINT_PARSERS
6544
+ and self._next
6545
+ and self._next.token_type == TokenType.L_PAREN
6546
+ ):
6547
+ this = self._parse_id_var()
6548
+
6466
6549
  if not in_props and not self._match(TokenType.L_PAREN, advance=False):
6467
6550
  return self.expression(
6468
6551
  exp.PrimaryKeyColumnConstraint,
@@ -6476,13 +6559,14 @@ class Parser(metaclass=_Parser):
6476
6559
 
6477
6560
  return self.expression(
6478
6561
  exp.PrimaryKey,
6562
+ this=this,
6479
6563
  expressions=expressions,
6480
6564
  include=self._parse_index_params(),
6481
6565
  options=self._parse_key_constraint_options(),
6482
6566
  )
6483
6567
 
6484
6568
  def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
6485
- return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
6569
+ return self._parse_slice(self._parse_alias(self._parse_disjunction(), explicit=True))
6486
6570
 
6487
6571
  def _parse_odbc_datetime_literal(self) -> exp.Expression:
6488
6572
  """
@@ -6562,9 +6646,16 @@ class Parser(metaclass=_Parser):
6562
6646
  return self._parse_bracket(this)
6563
6647
 
6564
6648
  def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6565
- if self._match(TokenType.COLON):
6566
- return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
6567
- return this
6649
+ if not self._match(TokenType.COLON):
6650
+ return this
6651
+
6652
+ if self._match_pair(TokenType.DASH, TokenType.COLON, advance=False):
6653
+ self._advance()
6654
+ end: t.Optional[exp.Expression] = -exp.Literal.number("1")
6655
+ else:
6656
+ end = self._parse_unary()
6657
+ step = self._parse_unary() if self._match(TokenType.COLON) else None
6658
+ return self.expression(exp.Slice, this=this, expression=end, step=step)
6568
6659
 
6569
6660
  def _parse_case(self) -> t.Optional[exp.Expression]:
6570
6661
  if self._match(TokenType.DOT, advance=False):
@@ -6576,16 +6667,16 @@ class Parser(metaclass=_Parser):
6576
6667
  default = None
6577
6668
 
6578
6669
  comments = self._prev_comments
6579
- expression = self._parse_assignment()
6670
+ expression = self._parse_disjunction()
6580
6671
 
6581
6672
  while self._match(TokenType.WHEN):
6582
- this = self._parse_assignment()
6673
+ this = self._parse_disjunction()
6583
6674
  self._match(TokenType.THEN)
6584
- then = self._parse_assignment()
6675
+ then = self._parse_disjunction()
6585
6676
  ifs.append(self.expression(exp.If, this=this, true=then))
6586
6677
 
6587
6678
  if self._match(TokenType.ELSE):
6588
- default = self._parse_assignment()
6679
+ default = self._parse_disjunction()
6589
6680
 
6590
6681
  if not self._match(TokenType.END):
6591
6682
  if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
@@ -6610,15 +6701,15 @@ class Parser(metaclass=_Parser):
6610
6701
  if self.NO_PAREN_IF_COMMANDS and index == 0:
6611
6702
  return self._parse_as_command(self._prev)
6612
6703
 
6613
- condition = self._parse_assignment()
6704
+ condition = self._parse_disjunction()
6614
6705
 
6615
6706
  if not condition:
6616
6707
  self._retreat(index)
6617
6708
  return None
6618
6709
 
6619
6710
  self._match(TokenType.THEN)
6620
- true = self._parse_assignment()
6621
- false = self._parse_assignment() if self._match(TokenType.ELSE) else None
6711
+ true = self._parse_disjunction()
6712
+ false = self._parse_disjunction() if self._match(TokenType.ELSE) else None
6622
6713
  self._match(TokenType.END)
6623
6714
  this = self.expression(exp.If, this=condition, true=true, false=false)
6624
6715
 
@@ -6657,7 +6748,7 @@ class Parser(metaclass=_Parser):
6657
6748
  return self.validate_expression(gap_fill, args)
6658
6749
 
6659
6750
  def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
6660
- this = self._parse_assignment()
6751
+ this = self._parse_disjunction()
6661
6752
 
6662
6753
  if not self._match(TokenType.ALIAS):
6663
6754
  if self._match(TokenType.COMMA):
@@ -6717,12 +6808,12 @@ class Parser(metaclass=_Parser):
6717
6808
  def _parse_string_agg(self) -> exp.GroupConcat:
6718
6809
  if self._match(TokenType.DISTINCT):
6719
6810
  args: t.List[t.Optional[exp.Expression]] = [
6720
- self.expression(exp.Distinct, expressions=[self._parse_assignment()])
6811
+ self.expression(exp.Distinct, expressions=[self._parse_disjunction()])
6721
6812
  ]
6722
6813
  if self._match(TokenType.COMMA):
6723
- args.extend(self._parse_csv(self._parse_assignment))
6814
+ args.extend(self._parse_csv(self._parse_disjunction))
6724
6815
  else:
6725
- args = self._parse_csv(self._parse_assignment) # type: ignore
6816
+ args = self._parse_csv(self._parse_disjunction) # type: ignore
6726
6817
 
6727
6818
  if self._match_text_seq("ON", "OVERFLOW"):
6728
6819
  # trino: LISTAGG(expression [, separator] [ON OVERFLOW overflow_behavior])
@@ -6827,7 +6918,7 @@ class Parser(metaclass=_Parser):
6827
6918
  return namespaces
6828
6919
 
6829
6920
  def _parse_decode(self) -> t.Optional[exp.Decode | exp.DecodeCase]:
6830
- args = self._parse_csv(self._parse_assignment)
6921
+ args = self._parse_csv(self._parse_disjunction)
6831
6922
 
6832
6923
  if len(args) < 3:
6833
6924
  return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
@@ -7253,7 +7344,7 @@ class Parser(metaclass=_Parser):
7253
7344
  "value": (
7254
7345
  (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
7255
7346
  or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
7256
- or self._parse_type()
7347
+ or self._parse_bitwise()
7257
7348
  ),
7258
7349
  "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
7259
7350
  }
@@ -7396,7 +7487,7 @@ class Parser(metaclass=_Parser):
7396
7487
  if self._match(TokenType.L_PAREN, advance=False):
7397
7488
  return self._parse_wrapped_csv(self._parse_expression)
7398
7489
 
7399
- expression = self._parse_alias(self._parse_assignment(), explicit=True)
7490
+ expression = self._parse_alias(self._parse_disjunction(), explicit=True)
7400
7491
  return [expression] if expression else None
7401
7492
 
7402
7493
  def _parse_csv(
@@ -7505,9 +7596,19 @@ class Parser(metaclass=_Parser):
7505
7596
 
7506
7597
  return self.expression(exp.Commit, chain=chain)
7507
7598
 
7508
- def _parse_refresh(self) -> exp.Refresh:
7509
- self._match(TokenType.TABLE)
7510
- return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
7599
+ def _parse_refresh(self) -> exp.Refresh | exp.Command:
7600
+ if self._match(TokenType.TABLE):
7601
+ kind = "TABLE"
7602
+ elif self._match_text_seq("MATERIALIZED", "VIEW"):
7603
+ kind = "MATERIALIZED VIEW"
7604
+ else:
7605
+ kind = ""
7606
+
7607
+ this = self._parse_string() or self._parse_table()
7608
+ if not kind and not isinstance(this, exp.Literal):
7609
+ return self._parse_as_command(self._prev)
7610
+
7611
+ return self.expression(exp.Refresh, this=this, kind=kind)
7511
7612
 
7512
7613
  def _parse_column_def_with_exists(self):
7513
7614
  start = self._index
@@ -7604,7 +7705,7 @@ class Parser(metaclass=_Parser):
7604
7705
  if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
7605
7706
  return self.expression(exp.AlterColumn, this=column, drop=True)
7606
7707
  if self._match_pair(TokenType.SET, TokenType.DEFAULT):
7607
- return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
7708
+ return self.expression(exp.AlterColumn, this=column, default=self._parse_disjunction())
7608
7709
  if self._match(TokenType.COMMENT):
7609
7710
  return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
7610
7711
  if self._match_text_seq("DROP", "NOT", "NULL"):
@@ -7633,7 +7734,7 @@ class Parser(metaclass=_Parser):
7633
7734
  this=column,
7634
7735
  dtype=self._parse_types(),
7635
7736
  collate=self._match(TokenType.COLLATE) and self._parse_term(),
7636
- using=self._match(TokenType.USING) and self._parse_assignment(),
7737
+ using=self._match(TokenType.USING) and self._parse_disjunction(),
7637
7738
  )
7638
7739
 
7639
7740
  def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
@@ -7960,14 +8061,12 @@ class Parser(metaclass=_Parser):
7960
8061
  self._match(TokenType.USING)
7961
8062
  using = self._parse_table()
7962
8063
 
7963
- self._match(TokenType.ON)
7964
- on = self._parse_assignment()
7965
-
7966
8064
  return self.expression(
7967
8065
  exp.Merge,
7968
8066
  this=target,
7969
8067
  using=using,
7970
- on=on,
8068
+ on=self._match(TokenType.ON) and self._parse_disjunction(),
8069
+ using_cond=self._match(TokenType.USING) and self._parse_using_identifiers(),
7971
8070
  whens=self._parse_when_matched(),
7972
8071
  returning=self._parse_returning(),
7973
8072
  )
@@ -7983,7 +8082,7 @@ class Parser(metaclass=_Parser):
7983
8082
  if self._match_text_seq("BY", "TARGET")
7984
8083
  else self._match_text_seq("BY", "SOURCE")
7985
8084
  )
7986
- condition = self._parse_assignment() if self._match(TokenType.AND) else None
8085
+ condition = self._parse_disjunction() if self._match(TokenType.AND) else None
7987
8086
 
7988
8087
  self._match(TokenType.THEN)
7989
8088
 
@@ -8040,7 +8139,7 @@ class Parser(metaclass=_Parser):
8040
8139
  return self._parse_set_transaction(global_=kind == "GLOBAL")
8041
8140
 
8042
8141
  left = self._parse_primary() or self._parse_column()
8043
- assignment_delimiter = self._match_texts(("=", "TO"))
8142
+ assignment_delimiter = self._match_texts(self.SET_ASSIGNMENT_DELIMITERS)
8044
8143
 
8045
8144
  if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
8046
8145
  self._retreat(index)
@@ -8062,7 +8161,7 @@ class Parser(metaclass=_Parser):
8062
8161
  exp.SetItem,
8063
8162
  expressions=characteristics,
8064
8163
  kind="TRANSACTION",
8065
- **{"global": global_}, # type: ignore
8164
+ global_=global_,
8066
8165
  )
8067
8166
 
8068
8167
  def _parse_set_item(self) -> t.Optional[exp.Expression]:
@@ -8160,15 +8259,18 @@ class Parser(metaclass=_Parser):
8160
8259
  ) -> t.Optional[exp.Comprehension]:
8161
8260
  index = self._index
8162
8261
  expression = self._parse_column()
8262
+ position = self._match(TokenType.COMMA) and self._parse_column()
8263
+
8163
8264
  if not self._match(TokenType.IN):
8164
8265
  self._retreat(index - 1)
8165
8266
  return None
8166
8267
  iterator = self._parse_column()
8167
- condition = self._parse_assignment() if self._match_text_seq("IF") else None
8268
+ condition = self._parse_disjunction() if self._match_text_seq("IF") else None
8168
8269
  return self.expression(
8169
8270
  exp.Comprehension,
8170
8271
  this=this,
8171
8272
  expression=expression,
8273
+ position=position,
8172
8274
  iterator=iterator,
8173
8275
  condition=condition,
8174
8276
  )
@@ -8443,8 +8545,15 @@ class Parser(metaclass=_Parser):
8443
8545
  elif prev == "FILE_FORMAT":
8444
8546
  # T-SQL's external file format case
8445
8547
  param.set("expression", self._parse_field())
8548
+ elif (
8549
+ prev == "FORMAT"
8550
+ and self._prev.token_type == TokenType.ALIAS
8551
+ and self._match_texts(("AVRO", "JSON"))
8552
+ ):
8553
+ param.set("this", exp.var(f"FORMAT AS {self._prev.text.upper()}"))
8554
+ param.set("expression", self._parse_field())
8446
8555
  else:
8447
- param.set("expression", self._parse_unquoted_field())
8556
+ param.set("expression", self._parse_unquoted_field() or self._parse_bracket())
8448
8557
 
8449
8558
  options.append(param)
8450
8559
  self._match(sep)
@@ -8465,7 +8574,10 @@ class Parser(metaclass=_Parser):
8465
8574
  if self._match_text_seq("ENCRYPTION"):
8466
8575
  expr.set("encryption", self._parse_wrapped_options())
8467
8576
  if self._match_text_seq("IAM_ROLE"):
8468
- expr.set("iam_role", self._parse_field())
8577
+ expr.set(
8578
+ "iam_role",
8579
+ exp.var(self._prev.text) if self._match(TokenType.DEFAULT) else self._parse_field(),
8580
+ )
8469
8581
  if self._match_text_seq("REGION"):
8470
8582
  expr.set("region", self._parse_field())
8471
8583
 
@@ -8542,11 +8654,9 @@ class Parser(metaclass=_Parser):
8542
8654
 
8543
8655
  return self.expression(
8544
8656
  exp.Star,
8545
- **{ # type: ignore
8546
- "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
8547
- "replace": self._parse_star_op("REPLACE"),
8548
- "rename": self._parse_star_op("RENAME"),
8549
- },
8657
+ except_=self._parse_star_op("EXCEPT", "EXCLUDE"),
8658
+ replace=self._parse_star_op("REPLACE"),
8659
+ rename=self._parse_star_op("RENAME"),
8550
8660
  ).update_positions(star_token)
8551
8661
 
8552
8662
  def _parse_grant_privilege(self) -> t.Optional[exp.GrantPrivilege]:
@@ -8644,14 +8754,17 @@ class Parser(metaclass=_Parser):
8644
8754
  )
8645
8755
 
8646
8756
  def _parse_overlay(self) -> exp.Overlay:
8757
+ def _parse_overlay_arg(text: str) -> t.Optional[exp.Expression]:
8758
+ return (
8759
+ self._match(TokenType.COMMA) or self._match_text_seq(text)
8760
+ ) and self._parse_bitwise()
8761
+
8647
8762
  return self.expression(
8648
8763
  exp.Overlay,
8649
- **{ # type: ignore
8650
- "this": self._parse_bitwise(),
8651
- "expression": self._match_text_seq("PLACING") and self._parse_bitwise(),
8652
- "from": self._match_text_seq("FROM") and self._parse_bitwise(),
8653
- "for": self._match_text_seq("FOR") and self._parse_bitwise(),
8654
- },
8764
+ this=self._parse_bitwise(),
8765
+ expression=_parse_overlay_arg("PLACING"),
8766
+ from_=_parse_overlay_arg("FROM"),
8767
+ for_=_parse_overlay_arg("FOR"),
8655
8768
  )
8656
8769
 
8657
8770
  def _parse_format_name(self) -> exp.Property:
@@ -8679,10 +8792,7 @@ class Parser(metaclass=_Parser):
8679
8792
  def _identifier_expression(
8680
8793
  self, token: t.Optional[Token] = None, **kwargs: t.Any
8681
8794
  ) -> exp.Identifier:
8682
- token = token or self._prev
8683
- expression = self.expression(exp.Identifier, this=token.text, **kwargs)
8684
- expression.update_positions(token)
8685
- return expression
8795
+ return self.expression(exp.Identifier, token=token or self._prev, **kwargs)
8686
8796
 
8687
8797
  def _build_pipe_cte(
8688
8798
  self,
@@ -8697,12 +8807,12 @@ class Parser(metaclass=_Parser):
8697
8807
  self._pipe_cte_counter += 1
8698
8808
  new_cte = f"__tmp{self._pipe_cte_counter}"
8699
8809
 
8700
- with_ = query.args.get("with")
8810
+ with_ = query.args.get("with_")
8701
8811
  ctes = with_.pop() if with_ else None
8702
8812
 
8703
8813
  new_select = exp.select(*expressions, copy=False).from_(new_cte, copy=False)
8704
8814
  if ctes:
8705
- new_select.set("with", ctes)
8815
+ new_select.set("with_", ctes)
8706
8816
 
8707
8817
  return new_select.with_(new_cte, as_=query, copy=False)
8708
8818
 
@@ -8730,7 +8840,7 @@ class Parser(metaclass=_Parser):
8730
8840
  return query
8731
8841
 
8732
8842
  def _parse_pipe_syntax_aggregate_fields(self) -> t.Optional[exp.Expression]:
8733
- this = self._parse_assignment()
8843
+ this = self._parse_disjunction()
8734
8844
  if self._match_text_seq("GROUP", "AND", advance=False):
8735
8845
  return this
8736
8846
 
@@ -8797,7 +8907,7 @@ class Parser(metaclass=_Parser):
8797
8907
  ]
8798
8908
 
8799
8909
  query = self._build_pipe_cte(query=query, expressions=[exp.Star()])
8800
- with_ = query.args.get("with")
8910
+ with_ = query.args.get("with_")
8801
8911
  ctes = with_.pop() if with_ else None
8802
8912
 
8803
8913
  if isinstance(first_setop, exp.Union):
@@ -8807,7 +8917,7 @@ class Parser(metaclass=_Parser):
8807
8917
  else:
8808
8918
  query = query.intersect(*setops, copy=False, **first_setop.args)
8809
8919
 
8810
- query.set("with", ctes)
8920
+ query.set("with_", ctes)
8811
8921
 
8812
8922
  return self._build_pipe_cte(query=query, expressions=[exp.Star()])
8813
8923
 
@@ -8826,7 +8936,7 @@ class Parser(metaclass=_Parser):
8826
8936
  if not pivots:
8827
8937
  return query
8828
8938
 
8829
- from_ = query.args.get("from")
8939
+ from_ = query.args.get("from_")
8830
8940
  if from_:
8831
8941
  from_.this.set("pivots", pivots)
8832
8942
 
@@ -8840,7 +8950,7 @@ class Parser(metaclass=_Parser):
8840
8950
  def _parse_pipe_syntax_tablesample(self, query: exp.Select) -> exp.Select:
8841
8951
  sample = self._parse_table_sample()
8842
8952
 
8843
- with_ = query.args.get("with")
8953
+ with_ = query.args.get("with_")
8844
8954
  if with_:
8845
8955
  with_.expressions[-1].this.set("sample", sample)
8846
8956
  else:
@@ -8852,7 +8962,7 @@ class Parser(metaclass=_Parser):
8852
8962
  if isinstance(query, exp.Subquery):
8853
8963
  query = exp.select("*").from_(query, copy=False)
8854
8964
 
8855
- if not query.args.get("from"):
8965
+ if not query.args.get("from_"):
8856
8966
  query = exp.select("*").from_(query.subquery(copy=False), copy=False)
8857
8967
 
8858
8968
  while self._match(TokenType.PIPE_GT):
@@ -8925,13 +9035,20 @@ class Parser(metaclass=_Parser):
8925
9035
  ) -> exp.Expression:
8926
9036
  if isinstance(node, exp.Distinct) and len(node.expressions) > 1:
8927
9037
  concat_exprs = [
8928
- self.expression(exp.Concat, expressions=node.expressions, safe=True)
9038
+ self.expression(
9039
+ exp.Concat,
9040
+ expressions=node.expressions,
9041
+ safe=True,
9042
+ coalesce=self.dialect.CONCAT_COALESCE,
9043
+ )
8929
9044
  ]
8930
9045
  node.set("expressions", concat_exprs)
8931
9046
  return node
8932
9047
  if len(exprs) == 1:
8933
9048
  return exprs[0]
8934
- return self.expression(exp.Concat, expressions=args, safe=True)
9049
+ return self.expression(
9050
+ exp.Concat, expressions=args, safe=True, coalesce=self.dialect.CONCAT_COALESCE
9051
+ )
8935
9052
 
8936
9053
  args = self._parse_csv(self._parse_lambda)
8937
9054
 
@@ -8951,3 +9068,12 @@ class Parser(metaclass=_Parser):
8951
9068
  separator = self._parse_field() if self._match(TokenType.SEPARATOR) else None
8952
9069
 
8953
9070
  return self.expression(exp.GroupConcat, this=this, separator=separator)
9071
+
9072
+ def _parse_initcap(self) -> exp.Initcap:
9073
+ expr = exp.Initcap.from_arg_list(self._parse_function_args())
9074
+
9075
+ # attach dialect's default delimiters
9076
+ if expr.args.get("expression") is None:
9077
+ expr.set("expression", exp.Literal.string(self.dialect.INITCAP_DEFAULT_DELIMITER_CHARS))
9078
+
9079
+ return expr