sqlglotc 30.22.0__tar.gz → 30.24.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. {sqlglotc-30.22.0/sqlglotc.egg-info → sqlglotc-30.24.0}/PKG-INFO +2 -2
  2. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/setup.py +17 -0
  3. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/anonymize.py +1 -0
  4. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/array.py +1 -5
  5. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/builders.py +54 -5
  6. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/constraints.py +1 -0
  7. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/core.py +13 -3
  8. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/ddl.py +2 -0
  9. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/json.py +1 -0
  10. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/properties.py +17 -0
  11. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/query.py +17 -0
  12. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generator.py +44 -2
  13. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/athena.py +5 -1
  14. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/bigquery.py +142 -1
  15. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/clickhouse.py +35 -2
  16. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/doris.py +6 -0
  17. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/duckdb.py +45 -42
  18. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/fabric.py +5 -0
  19. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/hive.py +4 -0
  20. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/mysql.py +3 -0
  21. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/oracle.py +22 -0
  22. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/postgres.py +8 -3
  23. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/presto.py +16 -8
  24. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/snowflake.py +15 -7
  25. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/spark2.py +24 -2
  26. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/starrocks.py +56 -4
  27. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/teradata.py +30 -1
  28. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/helper.py +17 -0
  29. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/optimizer/annotate_types.py +24 -16
  30. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/optimizer/qualify_columns.py +36 -12
  31. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/optimizer/qualify_tables.py +4 -1
  32. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/optimizer/scope.py +8 -7
  33. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/optimizer/simplify.py +23 -5
  34. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parser.py +177 -44
  35. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/athena.py +8 -0
  36. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/clickhouse.py +11 -1
  37. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/doris.py +40 -0
  38. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/dremio.py +3 -0
  39. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/drill.py +3 -0
  40. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/duckdb.py +41 -8
  41. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/hive.py +13 -0
  42. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/mysql.py +84 -3
  43. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/oracle.py +80 -3
  44. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/postgres.py +4 -1
  45. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/presto.py +2 -0
  46. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/prql.py +2 -8
  47. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/redshift.py +3 -1
  48. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/singlestore.py +3 -0
  49. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/snowflake.py +4 -4
  50. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/spark2.py +11 -5
  51. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/sqlite.py +14 -1
  52. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/starrocks.py +145 -11
  53. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/teradata.py +59 -0
  54. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/trino.py +6 -1
  55. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/tokenizer_core.py +4 -1
  56. {sqlglotc-30.22.0 → sqlglotc-30.24.0/sqlglotc.egg-info}/PKG-INFO +2 -2
  57. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglotc.egg-info/requires.txt +1 -1
  58. sqlglotc-30.24.0/sqlglotc.egg-info/scm_version.json +8 -0
  59. sqlglotc-30.22.0/sqlglotc.egg-info/scm_version.json +0 -8
  60. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/MANIFEST.in +0 -0
  61. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/pyproject.toml +0 -0
  62. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/setup.cfg +0 -0
  63. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/errors.py +0 -0
  64. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/executor/table.py +0 -0
  65. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/aggregate.py +0 -0
  66. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/datatypes.py +0 -0
  67. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/dml.py +0 -0
  68. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/functions.py +0 -0
  69. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/math.py +0 -0
  70. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/string.py +0 -0
  71. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/expressions/temporal.py +0 -0
  72. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/databricks.py +0 -0
  73. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/dax.py +0 -0
  74. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/dremio.py +0 -0
  75. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/drill.py +0 -0
  76. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/druid.py +0 -0
  77. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/dune.py +0 -0
  78. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/exasol.py +0 -0
  79. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/materialize.py +0 -0
  80. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/prql.py +0 -0
  81. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/python.py +0 -0
  82. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/redshift.py +0 -0
  83. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/risingwave.py +0 -0
  84. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/singlestore.py +0 -0
  85. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/solr.py +0 -0
  86. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/spark.py +0 -0
  87. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/sqlite.py +0 -0
  88. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/tableau.py +0 -0
  89. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/trino.py +0 -0
  90. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/generators/tsql.py +0 -0
  91. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/lineage.py +0 -0
  92. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/optimizer/canonicalize_internal_names.py +0 -0
  93. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
  94. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
  95. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/optimizer/qualify.py +0 -0
  96. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/optimizer/resolver.py +0 -0
  97. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/base.py +0 -0
  98. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/bigquery.py +0 -0
  99. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/databricks.py +0 -0
  100. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/dax.py +0 -0
  101. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/druid.py +0 -0
  102. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/dune.py +0 -0
  103. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/exasol.py +0 -0
  104. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/fabric.py +0 -0
  105. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/materialize.py +0 -0
  106. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/risingwave.py +0 -0
  107. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/solr.py +0 -0
  108. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/spark.py +0 -0
  109. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/tableau.py +0 -0
  110. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/parsers/tsql.py +0 -0
  111. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/serde.py +0 -0
  112. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/time.py +0 -0
  113. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglot/trie.py +0 -0
  114. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglotc.egg-info/SOURCES.txt +0 -0
  115. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglotc.egg-info/dependency_links.txt +0 -0
  116. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglotc.egg-info/scm_file_list.json +0 -0
  117. {sqlglotc-30.22.0 → sqlglotc-30.24.0}/sqlglotc.egg-info/top_level.txt +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglotc
3
- Version: 30.22.0
3
+ Version: 30.24.0
4
4
  Summary: mypyc-compiled extensions for sqlglot
5
5
  Author-email: Toby Mao <toby.mao@gmail.com>
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://sqlglot.com/
8
8
  Project-URL: Repository, https://github.com/tobymao/sqlglot
9
9
  Requires-Python: >=3.10
10
- Requires-Dist: sqlglot==30.22.0
10
+ Requires-Dist: sqlglot==30.24.0
11
11
  Provides-Extra: dev
12
12
  Requires-Dist: setuptools>=61.0; extra == "dev"
13
13
  Requires-Dist: setuptools_scm; extra == "dev"
@@ -90,6 +90,16 @@ def _source_paths():
90
90
 
91
91
 
92
92
  class build_ext(_build_ext):
93
+ def _remove_obsolete_extensions(self, directory, expected):
94
+ if self.dry_run:
95
+ return
96
+ expected = {os.path.abspath(path) for path in expected}
97
+ for root, _, files in os.walk(directory):
98
+ for filename in files:
99
+ path = os.path.join(root, filename)
100
+ if filename.endswith((".so", ".pyd")) and os.path.abspath(path) not in expected:
101
+ self.execute(os.remove, (path,), f"removing obsolete extension {path}")
102
+
93
103
  def finalize_options(self):
94
104
  super().finalize_options()
95
105
  # Compile in parallel by default; builds driven by pip (wheel/sdist installs)
@@ -97,8 +107,13 @@ class build_ext(_build_ext):
97
107
  if self.parallel is None:
98
108
  self.parallel = os.cpu_count() or 1
99
109
 
110
+ def build_extensions(self):
111
+ self._remove_obsolete_extensions(self.build_lib, self.get_outputs())
112
+ super().build_extensions()
113
+
100
114
  def copy_extensions_to_source(self):
101
115
  """For editable installs, put sqlglot.* .so files in the sqlglot source dir."""
116
+ expected = []
102
117
  for ext in self.extensions:
103
118
  fullname = self.get_ext_fullname(ext.name)
104
119
  filename = self.get_ext_filename(fullname)
@@ -112,7 +127,9 @@ class build_ext(_build_ext):
112
127
  # Place the mypyc runtime helper (e.g., HASH__mypyc) inside sqlglot/.
113
128
  # sqlglot/__init__.py bootstraps it into sys.modules for editable installs.
114
129
  dst = os.path.join(SQLGLOT_SRC, os.path.basename(filename))
130
+ expected.append(dst)
115
131
  self.copy_file(src, dst, level=self.verbose)
132
+ self._remove_obsolete_extensions(SQLGLOT_SRC, expected)
116
133
 
117
134
 
118
135
  class sdist(_sdist):
@@ -15,6 +15,7 @@ ANONYMIZED_TYPES = {
15
15
  TokenType.HEX_STRING,
16
16
  TokenType.HEREDOC_STRING,
17
17
  TokenType.IDENTIFIER,
18
+ TokenType.NATIONAL_RAW_STRING,
18
19
  TokenType.NATIONAL_STRING,
19
20
  TokenType.NUMBER,
20
21
  TokenType.RAW_STRING,
@@ -98,17 +98,13 @@ class ArraySlice(Expression, Func):
98
98
 
99
99
 
100
100
  class ArraySort(Expression, Func):
101
- arg_types = {"this": True, "expression": False}
101
+ arg_types = {"this": True, "expression": False, "asc": False, "nulls_first": False}
102
102
 
103
103
 
104
104
  class Shuffle(Expression, Func):
105
105
  pass
106
106
 
107
107
 
108
- class SortArray(Expression, Func):
109
- arg_types = {"this": True, "asc": False, "nulls_first": False}
110
-
111
-
112
108
  # Array predicates / search
113
109
 
114
110
 
@@ -10,14 +10,25 @@ from sqlglot.errors import ParseError, TokenError
10
10
  from sqlglot.expressions.core import (
11
11
  Alias,
12
12
  Anonymous,
13
+ AtTimeZone,
14
+ Between,
15
+ Binary,
16
+ BitwiseNot,
13
17
  Boolean,
18
+ Bracket,
14
19
  Column,
15
20
  Condition,
21
+ Dot,
16
22
  EQ,
17
23
  Expr,
24
+ Func,
18
25
  Identifier,
26
+ In,
19
27
  Literal,
28
+ Neg,
29
+ Not,
20
30
  Null,
31
+ Paren,
21
32
  Placeholder,
22
33
  TABLE_PARTS,
23
34
  Var,
@@ -36,6 +47,8 @@ from sqlglot.expressions.query import (
36
47
  From,
37
48
  Schema,
38
49
  Select,
50
+ SetOperation,
51
+ Subquery,
39
52
  Table,
40
53
  TableAlias,
41
54
  Tuple,
@@ -44,7 +57,7 @@ from sqlglot.expressions.query import (
44
57
  With,
45
58
  Query,
46
59
  )
47
- from sqlglot.expressions.ddl import Alter, AlterRename, RenameColumn
60
+ from sqlglot.expressions.ddl import Alter, AlterRename, Create, RenameColumn
48
61
  from sqlglot.expressions.dml import Delete, Insert, Merge, Update, When, Whens
49
62
  from sqlglot.expressions.functions import Case, Cast
50
63
  from sqlglot.expressions.array import Array
@@ -53,11 +66,10 @@ from sqlglot.expressions.array import Array
53
66
  if t.TYPE_CHECKING:
54
67
  from collections.abc import Sequence, Iterable, Iterator
55
68
  from sqlglot.dialects.dialect import DialectType
56
- from sqlglot.expressions.core import ExpOrStr, Func
69
+ from sqlglot.expressions.core import ExpOrStr
57
70
  from sqlglot.expressions.datatypes import DATA_TYPE
58
71
  from sqlglot._typing import ParserArgs, ParserNoDialectArgs, E, P
59
72
  from typing_extensions import Unpack, Concatenate
60
- from sqlglot.expressions.core import Dot
61
73
 
62
74
 
63
75
  def select(
@@ -849,6 +861,43 @@ def replace_tables(
849
861
  return expression.transform(_replace_tables, copy=copy) # type: ignore
850
862
 
851
863
 
864
+ OPERATORS = (AtTimeZone, Between, Binary, BitwiseNot, In, Neg, Not)
865
+
866
+
867
+ def _is_operand(placeholder: Placeholder) -> bool:
868
+ parent = placeholder.parent
869
+ if isinstance(parent, (Bracket, In)):
870
+ return placeholder.arg_key == "this"
871
+ return isinstance(parent, OPERATORS)
872
+
873
+
874
+ def _takes_query(placeholder: Placeholder) -> bool:
875
+ parent = placeholder.parent
876
+ if isinstance(parent, In):
877
+ return placeholder.arg_key == "expressions" and len(parent.expressions) == 1
878
+ if isinstance(parent, Func):
879
+ return len(list(parent.iter_expressions())) == 1
880
+ if isinstance(parent, Table):
881
+ return isinstance(parent.parent, (Create, Subquery))
882
+ return not parent or isinstance(parent, (CTE, Paren, SetOperation))
883
+
884
+
885
+ def _replace_placeholder(placeholder: Placeholder, expression: Expr) -> Expr:
886
+ if (
887
+ isinstance(expression, Query)
888
+ and not isinstance(expression, Subquery)
889
+ and not _takes_query(placeholder)
890
+ ):
891
+ return expression.subquery(copy=False)
892
+ if (
893
+ _is_operand(placeholder)
894
+ and isinstance(expression, OPERATORS)
895
+ and not isinstance(expression, Dot)
896
+ ):
897
+ return Paren(this=expression)
898
+ return expression
899
+
900
+
852
901
  def replace_placeholders(expression: Expr, *args: object, **kwargs: t.Any) -> Expr:
853
902
  """Replace placeholders in an expression.
854
903
 
@@ -874,10 +923,10 @@ def replace_placeholders(expression: Expr, *args: object, **kwargs: t.Any) -> Ex
874
923
  if node.this:
875
924
  new_name = kwargs.get(node.this)
876
925
  if new_name is not None:
877
- return convert(new_name)
926
+ return _replace_placeholder(node, convert(new_name))
878
927
  else:
879
928
  try:
880
- return convert(next(args))
929
+ return _replace_placeholder(node, convert(next(args)))
881
930
  except StopIteration:
882
931
  pass
883
932
  return node
@@ -208,6 +208,7 @@ class Constraint(Expression):
208
208
 
209
209
  class ForeignKey(Expression):
210
210
  arg_types = {
211
+ "this": False,
211
212
  "expressions": False,
212
213
  "reference": False,
213
214
  "delete": False,
@@ -867,7 +867,7 @@ class Expression(Expr):
867
867
  for k in sorted(node.args):
868
868
  v = node.args[k]
869
869
  if v:
870
- hash_ = hash((hash_, k, v))
870
+ hash_ = hash((hash_, k, tuple(v) if type(v) is list else v))
871
871
  else:
872
872
  for k in sorted(node.args):
873
873
  v = node.args[k]
@@ -1595,7 +1595,14 @@ class Uncache(Expression):
1595
1595
 
1596
1596
 
1597
1597
  class Refresh(Expression):
1598
- arg_types = {"this": True, "kind": True}
1598
+ arg_types = {
1599
+ "this": True,
1600
+ "kind": True,
1601
+ "partition_start": False,
1602
+ "partition_end": False,
1603
+ "force": False,
1604
+ "mode": False,
1605
+ }
1599
1606
 
1600
1607
 
1601
1608
  class LockingStatement(Expression):
@@ -1859,6 +1866,7 @@ class SessionParameter(Expression, Condition):
1859
1866
 
1860
1867
  class Placeholder(Expression, Condition):
1861
1868
  arg_types = {"this": False, "kind": False, "widget": False, "jdbc": False}
1869
+ _hash_raw_args = True
1862
1870
 
1863
1871
  @property
1864
1872
  def name(self) -> str:
@@ -1994,6 +2002,7 @@ class Typeof(Expression, Func):
1994
2002
 
1995
2003
  class ParameterizedAgg(Expression, AggFunc):
1996
2004
  arg_types = {"this": True, "expressions": True, "params": True}
2005
+ _hash_raw_args = True
1997
2006
 
1998
2007
 
1999
2008
  class Anonymous(Expression, Func):
@@ -2008,6 +2017,7 @@ class Anonymous(Expression, Func):
2008
2017
  class AnonymousAggFunc(Expression, AggFunc):
2009
2018
  arg_types = {"this": True, "expressions": False}
2010
2019
  is_var_len_args = True
2020
+ _hash_raw_args = True
2011
2021
 
2012
2022
 
2013
2023
  class CombinedAggFunc(AnonymousAggFunc):
@@ -2211,7 +2221,7 @@ class Like(Expression, Binary, Predicate):
2211
2221
 
2212
2222
 
2213
2223
  class Match(Expression, Binary, Predicate):
2214
- pass
2224
+ arg_types = {"this": True, "expression": True, "kind": False, "analyzer": False}
2215
2225
 
2216
2226
 
2217
2227
  class LT(Expression, Binary, Predicate):
@@ -176,6 +176,7 @@ class Set(Expression):
176
176
 
177
177
  class Heredoc(Expression):
178
178
  arg_types = {"this": True, "tag": False}
179
+ _hash_raw_args = True
179
180
 
180
181
 
181
182
  class SetItem(Expression):
@@ -382,6 +383,7 @@ class Undrop(Expression):
382
383
 
383
384
  class Command(Expression):
384
385
  arg_types = {"this": True, "expression": False}
386
+ _hash_raw_args = True
385
387
 
386
388
 
387
389
  class Transaction(Expression):
@@ -100,6 +100,7 @@ class JSONExists(Expression, Func):
100
100
  "on_condition": False,
101
101
  "from_dcolonqmark": False,
102
102
  }
103
+ _hash_raw_args = True
103
104
 
104
105
 
105
106
  class JSONExtract(Expression, Binary, Func):
@@ -25,6 +25,10 @@ class AllowedValuesProperty(Expression):
25
25
  arg_types = {"expressions": True}
26
26
 
27
27
 
28
+ class AggregateKeyProperty(Property):
29
+ arg_types = {"expressions": True}
30
+
31
+
28
32
  class AlgorithmProperty(Property):
29
33
  arg_types = {"this": True}
30
34
 
@@ -123,6 +127,7 @@ class DatabaseProperty(Property):
123
127
 
124
128
  class DefinerProperty(Property):
125
129
  arg_types = {"this": True}
130
+ _hash_raw_args = True
126
131
 
127
132
 
128
133
  class DistKeyProperty(Property):
@@ -390,6 +395,10 @@ class PartitionedOfProperty(Property):
390
395
  arg_types = {"this": True, "expression": True}
391
396
 
392
397
 
398
+ class PhysicalProperty(Property):
399
+ arg_types = {"this": True, "value": False}
400
+
401
+
393
402
  class StreamingTableProperty(Property):
394
403
  arg_types = {}
395
404
 
@@ -497,6 +506,10 @@ class StorageHandlerProperty(Property):
497
506
  arg_types = {"this": True}
498
507
 
499
508
 
509
+ class StorageProperty(Property):
510
+ arg_types = {"expressions": True}
511
+
512
+
500
513
  class UsingProperty(Property):
501
514
  # kind: JAR, FILE, or ARCHIVE; this: the resource path (string literal)
502
515
  arg_types = {"this": True, "kind": True}
@@ -522,6 +535,10 @@ class Tags(Property, ColumnConstraintKind):
522
535
  arg_types = {"expressions": True}
523
536
 
524
537
 
538
+ class TableSpaceProperty(Property):
539
+ arg_types = {"this": True}
540
+
541
+
525
542
  class PropertiesLocation(AutoName):
526
543
  POST_CREATE = auto()
527
544
  POST_NAME = auto()
@@ -500,14 +500,17 @@ class HexString(Expression, Condition):
500
500
  class ByteString(Expression, Condition):
501
501
  arg_types = {"this": True, "is_bytes": False}
502
502
  is_primitive = True
503
+ _hash_raw_args = True
503
504
 
504
505
 
505
506
  class RawString(Expression, Condition):
506
507
  is_primitive = True
508
+ _hash_raw_args = True
507
509
 
508
510
 
509
511
  class UnicodeString(Expression, Condition):
510
512
  arg_types = {"this": True, "escape": False}
513
+ _hash_raw_args = True
511
514
 
512
515
 
513
516
  class ColumnPosition(Expression):
@@ -599,6 +602,7 @@ class Introducer(Expression):
599
602
 
600
603
  class National(Expression):
601
604
  is_primitive = True
605
+ _hash_raw_args = True
602
606
 
603
607
 
604
608
  class Partition(Expression):
@@ -1934,6 +1938,10 @@ class WindowSpec(Expression):
1934
1938
  }
1935
1939
 
1936
1940
 
1941
+ class PartitionByExcluding(Expression):
1942
+ arg_types = {"expressions": True}
1943
+
1944
+
1937
1945
  class PreWhere(Expression):
1938
1946
  pass
1939
1947
 
@@ -2016,6 +2024,10 @@ class DropPartition(Expression):
2016
2024
  arg_types = {"expressions": True, "exists": False}
2017
2025
 
2018
2026
 
2027
+ class ReplaceColumns(Expression):
2028
+ arg_types = {"expressions": True}
2029
+
2030
+
2019
2031
  class ReplacePartition(Expression):
2020
2032
  arg_types = {"expression": True, "source": True}
2021
2033
 
@@ -2047,14 +2059,17 @@ class JSONPathPart(Expression):
2047
2059
 
2048
2060
  class JSONPathFilter(JSONPathPart):
2049
2061
  arg_types = {"this": True}
2062
+ _hash_raw_args = True
2050
2063
 
2051
2064
 
2052
2065
  class JSONPathKey(JSONPathPart):
2053
2066
  arg_types = {"this": True, "quoted": False}
2067
+ _hash_raw_args = True
2054
2068
 
2055
2069
 
2056
2070
  class JSONPathRecursive(JSONPathPart):
2057
2071
  arg_types = {"this": False}
2072
+ _hash_raw_args = True
2058
2073
 
2059
2074
 
2060
2075
  class JSONPathRoot(JSONPathPart):
@@ -2063,6 +2078,7 @@ class JSONPathRoot(JSONPathPart):
2063
2078
 
2064
2079
  class JSONPathScript(JSONPathPart):
2065
2080
  arg_types = {"this": True}
2081
+ _hash_raw_args = True
2066
2082
 
2067
2083
 
2068
2084
  class JSONPathSlice(JSONPathPart):
@@ -2079,6 +2095,7 @@ class JSONPathSubscript(JSONPathPart):
2079
2095
 
2080
2096
  class JSONPathUnion(JSONPathPart):
2081
2097
  arg_types = {"expressions": True}
2098
+ _hash_raw_args = True
2082
2099
 
2083
2100
 
2084
2101
  class JSONPathWildcard(JSONPathPart):
@@ -706,6 +706,7 @@ class Generator:
706
706
  EXPRESSION_PRECEDES_PROPERTIES_CREATABLES: t.ClassVar[set[str]] = set()
707
707
 
708
708
  PROPERTIES_LOCATION: t.ClassVar = {
709
+ exp.AggregateKeyProperty: exp.Properties.Location.POST_SCHEMA,
709
710
  exp.AllowedValuesProperty: exp.Properties.Location.POST_SCHEMA,
710
711
  exp.AlgorithmProperty: exp.Properties.Location.POST_CREATE,
711
712
  exp.ApiProperty: exp.Properties.Location.POST_CREATE,
@@ -773,6 +774,7 @@ class Generator:
773
774
  exp.OutputModelProperty: exp.Properties.Location.POST_SCHEMA,
774
775
  exp.PartitionedByProperty: exp.Properties.Location.POST_WITH,
775
776
  exp.PartitionedOfProperty: exp.Properties.Location.POST_SCHEMA,
777
+ exp.PhysicalProperty: exp.Properties.Location.UNSUPPORTED,
776
778
  exp.PrimaryKey: exp.Properties.Location.POST_SCHEMA,
777
779
  exp.Property: exp.Properties.Location.POST_WITH,
778
780
  exp.RefreshTriggerProperty: exp.Properties.Location.POST_SCHEMA,
@@ -800,9 +802,11 @@ class Generator:
800
802
  exp.SqlSecurityProperty: exp.Properties.Location.POST_SCHEMA,
801
803
  exp.StabilityProperty: exp.Properties.Location.POST_SCHEMA,
802
804
  exp.StorageHandlerProperty: exp.Properties.Location.POST_SCHEMA,
805
+ exp.StorageProperty: exp.Properties.Location.UNSUPPORTED,
803
806
  exp.StreamingTableProperty: exp.Properties.Location.POST_CREATE,
804
807
  exp.StrictProperty: exp.Properties.Location.POST_SCHEMA,
805
808
  exp.Tags: exp.Properties.Location.POST_WITH,
809
+ exp.TableSpaceProperty: exp.Properties.Location.UNSUPPORTED,
806
810
  exp.TemporaryProperty: exp.Properties.Location.POST_CREATE,
807
811
  exp.ToTableProperty: exp.Properties.Location.POST_SCHEMA,
808
812
  exp.TransientProperty: exp.Properties.Location.POST_CREATE,
@@ -2174,6 +2178,7 @@ class Generator:
2174
2178
  property_name = exp.Properties.PROPERTY_TO_NAME.get(property_cls)
2175
2179
  if not property_name:
2176
2180
  self.unsupported(f"Unsupported property {expression.key}")
2181
+ return ""
2177
2182
 
2178
2183
  return f"{property_name}={self.sql(expression, 'this')}"
2179
2184
 
@@ -2315,6 +2320,10 @@ class Generator:
2315
2320
  override = " OVERRIDE" if expression.args.get("override") else ""
2316
2321
  return f"LOCKING {kind}{this}{for_or_in} {lock_type}{override}"
2317
2322
 
2323
+ def lockingstatement_sql(self, expression: exp.LockingStatement) -> str:
2324
+ self.unsupported("LOCKING request modifier is not supported")
2325
+ return self.sql(expression, "expression")
2326
+
2318
2327
  def withdataproperty_sql(self, expression: exp.WithDataProperty) -> str:
2319
2328
  data_sql = f"WITH {'NO ' if expression.args.get('no') else ''}DATA"
2320
2329
  statistics = expression.args.get("statistics")
@@ -2557,6 +2566,10 @@ class Generator:
2557
2566
  expression: exp.TableSample,
2558
2567
  tablesample_keyword: str | None = None,
2559
2568
  ) -> str:
2569
+ if expression.expressions:
2570
+ self.unsupported("Multiple sample sets are not supported")
2571
+ return ""
2572
+
2560
2573
  method = self.sql(expression, "method")
2561
2574
  method = f"{method} " if method and self.TABLESAMPLE_WITH_METHOD else ""
2562
2575
  numerator = self.sql(expression, "bucket_numerator")
@@ -3634,6 +3647,9 @@ class Generator:
3634
3647
  partition = self.expressions(expression, key="partition_by", flat=True)
3635
3648
  return f"PARTITION BY {partition}" if partition else ""
3636
3649
 
3650
+ def partitionbyexcluding_sql(self, expression: exp.PartitionByExcluding) -> str:
3651
+ return f"EXCLUDING {self.expressions(expression, flat=True)}"
3652
+
3637
3653
  def windowspec_sql(self, expression: exp.WindowSpec) -> str:
3638
3654
  kind = self.sql(expression, "kind")
3639
3655
  start = csv(self.sql(expression, "start"), self.sql(expression, "start_side"), sep=" ")
@@ -3840,6 +3856,8 @@ class Generator:
3840
3856
  return f"CHECK ({this})"
3841
3857
 
3842
3858
  def foreignkey_sql(self, expression: exp.ForeignKey) -> str:
3859
+ this = self.sql(expression, "this")
3860
+ this = f" {this}" if this else ""
3843
3861
  expressions = self.expressions(expression, flat=True)
3844
3862
  expressions = f" ({expressions})" if expressions else ""
3845
3863
  reference = self.sql(expression, "reference")
@@ -3850,7 +3868,7 @@ class Generator:
3850
3868
  update = f" ON UPDATE {update}" if update else ""
3851
3869
  options = self.expressions(expression, key="options", flat=True, sep=" ")
3852
3870
  options = f" {options}" if options else ""
3853
- return f"FOREIGN KEY{expressions}{reference}{delete}{update}{options}"
3871
+ return f"FOREIGN KEY{this}{expressions}{reference}{delete}{update}{options}"
3854
3872
 
3855
3873
  def primarykey_sql(self, expression: exp.PrimaryKey) -> str:
3856
3874
  this = self.sql(expression, "this")
@@ -4511,6 +4529,9 @@ class Generator:
4511
4529
  def addconstraint_sql(self, expression: exp.AddConstraint) -> str:
4512
4530
  return f"ADD {self.expressions(expression, indent=False)}"
4513
4531
 
4532
+ def replacecolumns_sql(self, expression: exp.ReplaceColumns) -> str:
4533
+ return f"REPLACE COLUMNS ({self.expressions(expression, flat=True)})"
4534
+
4514
4535
  def addpartition_sql(self, expression: exp.AddPartition) -> str:
4515
4536
  exists = "IF NOT EXISTS " if expression.args.get("exists") else ""
4516
4537
  location = self.sql(expression, "location")
@@ -4688,6 +4709,8 @@ class Generator:
4688
4709
  return self._like_sql(expression)
4689
4710
 
4690
4711
  def match_sql(self, expression: exp.Match) -> str:
4712
+ if expression.args.get("kind") or expression.args.get("analyzer"):
4713
+ self.unsupported("MATCH variants and USING ANALYZER are not supported in this dialect")
4691
4714
  return self.binary(expression, "MATCH")
4692
4715
 
4693
4716
  def similarto_sql(self, expression: exp.SimilarTo) -> str:
@@ -4763,14 +4786,22 @@ class Generator:
4763
4786
  sqls: list[str] = []
4764
4787
  stack: list[None | str | exp.Expr] = [expression]
4765
4788
  binary_type = type(expression)
4789
+ is_is = binary_type is exp.Is and op in ("IS", "IS NOT")
4790
+ negate = expression.args.get("negate")
4766
4791
 
4767
4792
  while stack:
4768
4793
  node = stack.pop()
4769
4794
 
4770
- if type(node) is binary_type:
4795
+ if type(node) is binary_type and (
4796
+ node is expression
4797
+ or (is_is and not isinstance(node.expression, exp.Boolean))
4798
+ or node.args.get("negate") == negate
4799
+ ):
4771
4800
  op_func = node.args.get("operator")
4772
4801
  if op_func:
4773
4802
  op = f"OPERATOR({self.sql(op_func)})"
4803
+ elif is_is:
4804
+ op = "IS NOT" if node.args.get("negate") else "IS"
4774
4805
 
4775
4806
  stack.append(node.args.get("expression"))
4776
4807
  stack.append(f" {self.maybe_comment(op, comments=node.comments)} ")
@@ -5043,6 +5074,9 @@ class Generator:
5043
5074
  def dictsubproperty_sql(self, expression: exp.DictSubProperty) -> str:
5044
5075
  return f"{self.sql(expression, 'this')} {self.sql(expression, 'value')}"
5045
5076
 
5077
+ def aggregatekeyproperty_sql(self, expression: exp.AggregateKeyProperty) -> str:
5078
+ return f"AGGREGATE KEY ({self.expressions(expression, flat=True)})"
5079
+
5046
5080
  def duplicatekeyproperty_sql(self, expression: exp.DuplicateKeyProperty) -> str:
5047
5081
  return f"DUPLICATE KEY ({self.expressions(expression, flat=True)})"
5048
5082
 
@@ -5281,6 +5315,7 @@ class Generator:
5281
5315
  expression_sql = self.sql(expression, "expression")
5282
5316
  return f"FOR {this} DO {expression_sql}"
5283
5317
 
5318
+ @unsupported_args("partition_start", "partition_end", "force", "mode")
5284
5319
  def refresh_sql(self, expression: exp.Refresh) -> str:
5285
5320
  this = self.sql(expression, "this")
5286
5321
  kind = "" if isinstance(expression.this, exp.Literal) else f"{expression.text('kind')} "
@@ -6041,6 +6076,13 @@ class Generator:
6041
6076
  exp.TimestampDiff(this=expression.this, expression=start_ts, unit=exp.var("SECONDS"))
6042
6077
  )
6043
6078
 
6079
+ def arraysort_sql(self, expression: exp.ArraySort) -> str:
6080
+ asc = expression.args.get("asc")
6081
+ nulls_first = expression.args.get("nulls_first")
6082
+ if (asc and asc != exp.true()) or (nulls_first and nulls_first != exp.false()):
6083
+ self.unsupported("ARRAY_SORT only sorts ascending with NULLs last")
6084
+ return self.func("ARRAY_SORT", expression.this, expression.expression)
6085
+
6044
6086
  def arraysize_sql(self, expression: exp.ArraySize) -> str:
6045
6087
  dim = expression.expression
6046
6088
 
@@ -54,7 +54,11 @@ def _generate_as_hive(expression: exp.Expr) -> bool:
54
54
 
55
55
  # Any CREATE TABLE other than CREATE TABLE ... As <query> is Hive
56
56
  if not isinstance(expression.expression, exp.Query):
57
- return True
57
+ # CTAS with a leading USING EXTERNAL FUNCTION clause is Trino
58
+ return not (
59
+ isinstance(expression.expression, exp.Command)
60
+ and expression.expression.text("this").upper() == "USING"
61
+ )
58
62
  else:
59
63
  # CREATE VIEW is Trino, but CREATE SCHEMA, CREATE DATABASE, etc, is Hive
60
64
  return expression.kind != "VIEW"