sqlglotc 30.18.0__tar.gz → 30.19.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 (118) hide show
  1. {sqlglotc-30.18.0/sqlglotc.egg-info → sqlglotc-30.19.0}/PKG-INFO +2 -2
  2. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/aggregate.py +6 -0
  3. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/array.py +6 -1
  4. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/core.py +4 -0
  5. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/json.py +4 -0
  6. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/query.py +20 -5
  7. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/string.py +1 -0
  8. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generator.py +23 -14
  9. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/clickhouse.py +10 -0
  10. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/databricks.py +1 -1
  11. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/doris.py +15 -0
  12. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/duckdb.py +12 -12
  13. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/fabric.py +5 -5
  14. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/mysql.py +12 -2
  15. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/python.py +10 -1
  16. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/singlestore.py +11 -0
  17. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/spark.py +3 -0
  18. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/sqlite.py +52 -25
  19. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/teradata.py +1 -0
  20. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/trino.py +41 -0
  21. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/tsql.py +61 -3
  22. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/lineage.py +1 -1
  23. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/optimizer/annotate_types.py +5 -4
  24. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/optimizer/canonicalize_internal_names.py +4 -4
  25. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/optimizer/qualify_columns.py +57 -13
  26. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/optimizer/resolver.py +23 -7
  27. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/optimizer/scope.py +27 -21
  28. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/optimizer/simplify.py +73 -43
  29. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parser.py +49 -36
  30. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/bigquery.py +0 -6
  31. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/hive.py +6 -0
  32. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/mysql.py +53 -7
  33. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/redshift.py +2 -0
  34. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/snowflake.py +7 -2
  35. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/sqlite.py +5 -0
  36. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/trino.py +0 -6
  37. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/tsql.py +2 -2
  38. {sqlglotc-30.18.0 → sqlglotc-30.19.0/sqlglotc.egg-info}/PKG-INFO +2 -2
  39. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglotc.egg-info/requires.txt +1 -1
  40. sqlglotc-30.19.0/sqlglotc.egg-info/scm_version.json +8 -0
  41. sqlglotc-30.18.0/sqlglotc.egg-info/scm_version.json +0 -8
  42. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/MANIFEST.in +0 -0
  43. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/pyproject.toml +0 -0
  44. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/setup.cfg +0 -0
  45. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/setup.py +0 -0
  46. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/anonymize.py +0 -0
  47. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/errors.py +0 -0
  48. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/executor/table.py +0 -0
  49. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/builders.py +0 -0
  50. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/constraints.py +0 -0
  51. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/datatypes.py +0 -0
  52. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/ddl.py +0 -0
  53. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/dml.py +0 -0
  54. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/functions.py +0 -0
  55. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/math.py +0 -0
  56. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/properties.py +0 -0
  57. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/expressions/temporal.py +0 -0
  58. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/athena.py +0 -0
  59. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/bigquery.py +0 -0
  60. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/dax.py +0 -0
  61. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/dremio.py +0 -0
  62. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/drill.py +0 -0
  63. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/druid.py +0 -0
  64. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/dune.py +0 -0
  65. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/exasol.py +0 -0
  66. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/hive.py +0 -0
  67. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/materialize.py +0 -0
  68. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/oracle.py +0 -0
  69. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/postgres.py +0 -0
  70. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/presto.py +0 -0
  71. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/prql.py +0 -0
  72. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/redshift.py +0 -0
  73. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/risingwave.py +0 -0
  74. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/snowflake.py +0 -0
  75. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/solr.py +0 -0
  76. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/spark2.py +0 -0
  77. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/starrocks.py +0 -0
  78. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/generators/tableau.py +0 -0
  79. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/helper.py +0 -0
  80. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
  81. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
  82. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/optimizer/qualify.py +0 -0
  83. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/optimizer/qualify_tables.py +0 -0
  84. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/athena.py +0 -0
  85. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/base.py +0 -0
  86. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/clickhouse.py +0 -0
  87. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/databricks.py +0 -0
  88. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/dax.py +0 -0
  89. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/doris.py +0 -0
  90. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/dremio.py +0 -0
  91. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/drill.py +0 -0
  92. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/druid.py +0 -0
  93. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/duckdb.py +0 -0
  94. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/dune.py +0 -0
  95. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/exasol.py +0 -0
  96. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/fabric.py +0 -0
  97. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/materialize.py +0 -0
  98. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/oracle.py +0 -0
  99. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/postgres.py +0 -0
  100. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/presto.py +0 -0
  101. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/prql.py +0 -0
  102. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/risingwave.py +0 -0
  103. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/singlestore.py +0 -0
  104. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/solr.py +0 -0
  105. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/spark.py +0 -0
  106. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/spark2.py +0 -0
  107. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/starrocks.py +0 -0
  108. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/tableau.py +0 -0
  109. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/parsers/teradata.py +0 -0
  110. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/schema.py +0 -0
  111. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/serde.py +0 -0
  112. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/time.py +0 -0
  113. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/tokenizer_core.py +0 -0
  114. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglot/trie.py +0 -0
  115. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglotc.egg-info/SOURCES.txt +0 -0
  116. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglotc.egg-info/dependency_links.txt +0 -0
  117. {sqlglotc-30.18.0 → sqlglotc-30.19.0}/sqlglotc.egg-info/scm_file_list.json +0 -0
  118. {sqlglotc-30.18.0 → sqlglotc-30.19.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.18.0
3
+ Version: 30.19.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.18.0
10
+ Requires-Dist: sqlglot==30.19.0
11
11
  Provides-Extra: dev
12
12
  Requires-Dist: setuptools>=61.0; extra == "dev"
13
13
  Requires-Dist: setuptools_scm; extra == "dev"
@@ -5,6 +5,12 @@ from __future__ import annotations
5
5
  from sqlglot.expressions.core import Expression, Func, AggFunc, Binary
6
6
 
7
7
 
8
+ class Agg(Expression, AggFunc):
9
+ @property
10
+ def output_name(self) -> str:
11
+ return self.this.name
12
+
13
+
8
14
  class AIAgg(Expression, AggFunc):
9
15
  arg_types = {"this": True, "expression": True}
10
16
  _sql_names = ["AI_AGG"]
@@ -240,10 +240,15 @@ class Explode(Expression, Func, UDTF):
240
240
  is_var_len_args = True
241
241
 
242
242
 
243
- class Inline(Expression, Func):
243
+ class Inline(Expression, Func, UDTF):
244
244
  pass
245
245
 
246
246
 
247
+ class Stack(Expression, Func, UDTF):
248
+ arg_types = {"this": True, "expressions": True}
249
+ is_var_len_args = True
250
+
251
+
247
252
  @trait
248
253
  class ExplodeOuter(Expr):
249
254
  pass
@@ -1828,6 +1828,10 @@ class Identifier(Expression):
1828
1828
  class DynamicIdentifier(Expression, Func):
1829
1829
  arg_types = {"this": True, "expressions": False}
1830
1830
 
1831
+ @property
1832
+ def name(self) -> str:
1833
+ return self.this.name if self.this else ""
1834
+
1831
1835
 
1832
1836
  class Opclass(Expression):
1833
1837
  arg_types = {"this": True, "expression": True}
@@ -240,6 +240,10 @@ class OpenJSON(Expression, Func):
240
240
  arg_types = {"this": True, "path": False, "expressions": False}
241
241
 
242
242
 
243
+ class FromJson(Expression, Func):
244
+ arg_types = {"this": True, "expression": True, "options": False}
245
+
246
+
243
247
  class ParseJSON(Expression, Func):
244
248
  # BigQuery, Snowflake have PARSE_JSON, Presto has JSON_PARSE
245
249
  # Snowflake also has TRY_PARSE_JSON, which is represented using `safe`
@@ -12,6 +12,7 @@ from sqlglot.expressions.core import (
12
12
  Condition,
13
13
  Distinct,
14
14
  Dot,
15
+ DynamicIdentifier,
15
16
  Expr,
16
17
  Expression,
17
18
  Func,
@@ -624,7 +625,6 @@ class Group(Expression):
624
625
  arg_types = {
625
626
  "expressions": False,
626
627
  "grouping_sets": False,
627
- "grouping_sets_as_group_by_element": False,
628
628
  "cube": False,
629
629
  "rollup": False,
630
630
  "totals": False,
@@ -967,9 +967,10 @@ class Table(Expression, Selectable):
967
967
 
968
968
  @property
969
969
  def name(self) -> str:
970
- if not self.this or isinstance(self.this, Func):
970
+ this = self.this
971
+ if not this or (isinstance(this, Func) and not isinstance(this, DynamicIdentifier)):
971
972
  return ""
972
- return self.this.name
973
+ return this.name
973
974
 
974
975
  @property
975
976
  def db(self) -> str:
@@ -1019,6 +1020,20 @@ class Table(Expression, Selectable):
1019
1020
  return col
1020
1021
 
1021
1022
 
1023
+ def _is_star(expression: Expr) -> bool:
1024
+ stack = [expression]
1025
+ while stack:
1026
+ node = stack.pop()
1027
+ if isinstance(node, SetOperation):
1028
+ stack.append(node.this)
1029
+ stack.append(node.expression)
1030
+ elif isinstance(node, Subquery):
1031
+ stack.append(node.this)
1032
+ elif node.is_star:
1033
+ return True
1034
+ return False
1035
+
1036
+
1022
1037
  class SetOperation(Expression, Query):
1023
1038
  arg_types = {
1024
1039
  "with_": False,
@@ -1061,7 +1076,7 @@ class SetOperation(Expression, Query):
1061
1076
 
1062
1077
  @property
1063
1078
  def is_star(self) -> bool:
1064
- return self.this.is_star or self.expression.is_star
1079
+ return _is_star(self)
1065
1080
 
1066
1081
  @property
1067
1082
  def selects(self) -> list[Expr]:
@@ -1719,7 +1734,7 @@ class Subquery(Expression, DerivedTable, Query):
1719
1734
 
1720
1735
  @property
1721
1736
  def is_star(self) -> bool:
1722
- return self.this.is_star
1737
+ return _is_star(self)
1723
1738
 
1724
1739
  @property
1725
1740
  def output_name(self) -> str:
@@ -32,6 +32,7 @@ class Concat(Expression, Func):
32
32
 
33
33
 
34
34
  class ConcatWs(Concat):
35
+ arg_types = {**Concat.arg_types, "flatten": False}
35
36
  _sql_names = ["CONCAT_WS"]
36
37
 
37
38
 
@@ -535,6 +535,12 @@ class Generator:
535
535
  # True means limit 1 happens after the set op, False means it it happens on y.
536
536
  SET_OP_MODIFIERS = True
537
537
 
538
+ # Whether a SELECT operand can have a branch-local LIMIT/TOP without parentheses.
539
+ SET_OP_LIMITS = False
540
+
541
+ # Whether set operation operands can be parenthesized without a SELECT wrapper.
542
+ SET_OP_PARENTHESIZED_OPERANDS = True
543
+
538
544
  # Whether parameters from COPY statement are wrapped in parentheses
539
545
  COPY_PARAMS_ARE_WRAPPED = True
540
546
 
@@ -1902,16 +1908,16 @@ class Generator:
1902
1908
  if not self.SET_OP_MODIFIERS:
1903
1909
  limit = expression.args.get("limit")
1904
1910
  order = expression.args.get("order")
1911
+ offset = expression.args.get("offset")
1905
1912
 
1906
- if limit or order:
1913
+ if limit or order or offset:
1907
1914
  select = self._move_ctes_to_top_level(
1908
1915
  exp.subquery(expression, "_l_0", copy=False).select("*", copy=False)
1909
1916
  )
1910
1917
 
1911
- if limit:
1912
- select = select.limit(limit.pop(), copy=False)
1913
- if order:
1914
- select = select.order_by(order.pop(), copy=False)
1918
+ for arg in ("limit", "order", "offset"):
1919
+ if value := expression.args.get(arg):
1920
+ select.set(arg, value.pop())
1915
1921
  return self.sql(select)
1916
1922
 
1917
1923
  sqls: list[str] = []
@@ -1929,6 +1935,14 @@ class Generator:
1929
1935
  )
1930
1936
  stack.append(node.this)
1931
1937
  else:
1938
+ if (
1939
+ not self.SET_OP_LIMITS
1940
+ and isinstance(node, exp.Select)
1941
+ and node.args.get("limit")
1942
+ ):
1943
+ node = node.subquery(copy=False)
1944
+ if not self.SET_OP_PARENTHESIZED_OPERANDS:
1945
+ node = exp.select("*").from_(node, copy=False)
1932
1946
  sqls.append(self.sql(node))
1933
1947
 
1934
1948
  this = self.sep().join(sqls)
@@ -2836,7 +2850,7 @@ class Generator:
2836
2850
  ):
2837
2851
  add_separator = True
2838
2852
 
2839
- if grouping_sets and not expression.args.get("grouping_sets_as_group_by_element"):
2853
+ if grouping_sets:
2840
2854
  if self.SUPPORTS_GROUPING_SETS_AS_SUFFIX:
2841
2855
  add_separator = False
2842
2856
  else:
@@ -3324,8 +3338,8 @@ class Generator:
3324
3338
  self.sql(expression, "order"),
3325
3339
  *self.offset_limit_modifiers(expression, isinstance(limit, exp.Fetch), limit),
3326
3340
  *self.after_limit_modifiers(expression),
3327
- self.options_modifier(expression),
3328
3341
  self.sql(expression, "for_"),
3342
+ self.options_modifier(expression),
3329
3343
  sep="",
3330
3344
  )
3331
3345
 
@@ -3822,6 +3836,7 @@ class Generator:
3822
3836
  path = self.expressions(expression, sep="", flat=True).lstrip(".")
3823
3837
 
3824
3838
  if self.QUOTE_JSON_PATH:
3839
+ path = self.escape_str(path)
3825
3840
  path = f"{self.dialect.QUOTE_START}{path}{self.dialect.QUOTE_END}"
3826
3841
 
3827
3842
  return path
@@ -3840,7 +3855,7 @@ class Generator:
3840
3855
 
3841
3856
  if self._quote_json_path_key_using_brackets and self.JSON_PATH_SINGLE_QUOTE_ESCAPE:
3842
3857
  escaped = expression.replace("'", "\\'")
3843
- escaped = f"\\'{expression}\\'"
3858
+ escaped = f"'{escaped}'"
3844
3859
  else:
3845
3860
  escaped = expression.replace('"', '\\"')
3846
3861
  escaped = f'"{escaped}"'
@@ -5401,12 +5416,6 @@ class Generator:
5401
5416
 
5402
5417
  this = self.json_path_part(this)
5403
5418
 
5404
- if quoted and self.QUOTE_JSON_PATH:
5405
- # The whole path is rendered as a single quoted string literal, so the bracketed key
5406
- # (which may itself contain backslash-escaped quotes, e.g. ["x \"y\"z"]) must be
5407
- # escaped again for the outer string literal (-> ["x \\"y\\"z"]).
5408
- this = self.escape_str(this)
5409
-
5410
5419
  return (
5411
5420
  f"[{this}]"
5412
5421
  if self._quote_json_path_key_using_brackets and self.JSON_PATH_BRACKETED_KEY_SUPPORTED
@@ -186,6 +186,7 @@ class ClickHouseGenerator(generator.Generator):
186
186
  TABLE_HINTS = False
187
187
  GROUPINGS_SEP = ""
188
188
  SET_OP_MODIFIERS = False
189
+ SET_OP_LIMITS = True
189
190
  ARRAY_SIZE_NAME = "LENGTH"
190
191
  WRAP_DERIVED_VALUES = False
191
192
  AUTO_REFRESH_BARE_INTERVALS = True
@@ -445,6 +446,15 @@ class ClickHouseGenerator(generator.Generator):
445
446
 
446
447
  return self.func("groupConcat", this)
447
448
 
449
+ def select_sql(self, expression: exp.Select) -> str:
450
+ limit = expression.args.get("limit")
451
+ if isinstance(limit, exp.Fetch) and not expression.args.get("order"):
452
+ count = limit.args.get("count")
453
+ expression.set(
454
+ "limit", exp.Limit(expression=count if count is not None else exp.Literal.number(1))
455
+ )
456
+ return super().select_sql(expression)
457
+
448
458
  def offset_sql(self, expression: exp.Offset) -> str:
449
459
  offset = super().offset_sql(expression)
450
460
 
@@ -97,10 +97,10 @@ class DatabricksGenerator(SparkGenerator):
97
97
  return f"{self.sql(expression, 'this')} TIMESERIES"
98
98
 
99
99
  def jsonpath_sql(self, expression: exp.JSONPath) -> str:
100
- expression.set("escape", None)
101
100
  path = super().jsonpath_sql(expression)
102
101
 
103
102
  if isinstance(expression.parent, exp.JSONExtractScalar):
103
+ path = self.escape_str(path)
104
104
  return f"{self.dialect.QUOTE_START}{path}{self.dialect.QUOTE_END}"
105
105
 
106
106
  return path
@@ -104,6 +104,7 @@ class DorisGenerator(MySQLGenerator):
104
104
  "alter",
105
105
  "analyze",
106
106
  "analyzed",
107
+ "analyzer",
107
108
  "and",
108
109
  "anti",
109
110
  "append",
@@ -111,6 +112,7 @@ class DorisGenerator(MySQLGenerator):
111
112
  "array_range",
112
113
  "as",
113
114
  "asc",
115
+ "asof",
114
116
  "at",
115
117
  "authors",
116
118
  "auto",
@@ -132,6 +134,7 @@ class DorisGenerator(MySQLGenerator):
132
134
  "bitxor",
133
135
  "blob",
134
136
  "boolean",
137
+ "both",
135
138
  "brief",
136
139
  "broker",
137
140
  "buckets",
@@ -148,6 +151,7 @@ class DorisGenerator(MySQLGenerator):
148
151
  "catalogs",
149
152
  "chain",
150
153
  "char",
154
+ "char_filter",
151
155
  "character",
152
156
  "charset",
153
157
  "check",
@@ -227,6 +231,7 @@ class DorisGenerator(MySQLGenerator):
227
231
  "drop",
228
232
  "dropp",
229
233
  "dual",
234
+ "dump",
230
235
  "duplicate",
231
236
  "dynamic",
232
237
  "else",
@@ -329,8 +334,10 @@ class DorisGenerator(MySQLGenerator):
329
334
  "largeint",
330
335
  "last",
331
336
  "lateral",
337
+ "layout",
332
338
  "ldap",
333
339
  "ldap_admin_password",
340
+ "leading",
334
341
  "left",
335
342
  "less",
336
343
  "level",
@@ -352,6 +359,7 @@ class DorisGenerator(MySQLGenerator):
352
359
  "match",
353
360
  "match_all",
354
361
  "match_any",
362
+ "match_condition",
355
363
  "match_phrase",
356
364
  "match_phrase_edge",
357
365
  "match_phrase_prefix",
@@ -377,6 +385,7 @@ class DorisGenerator(MySQLGenerator):
377
385
  "next",
378
386
  "ngram_bf",
379
387
  "no",
388
+ "no_use_mv",
380
389
  "non_nullable",
381
390
  "not",
382
391
  "null",
@@ -410,6 +419,7 @@ class DorisGenerator(MySQLGenerator):
410
419
  "permissive",
411
420
  "physical",
412
421
  "plan",
422
+ "play",
413
423
  "process",
414
424
  "plugin",
415
425
  "plugins",
@@ -520,6 +530,9 @@ class DorisGenerator(MySQLGenerator):
520
530
  "timestampdiff",
521
531
  "tinyint",
522
532
  "to",
533
+ "token_filter",
534
+ "tokenizer",
535
+ "trailing",
523
536
  "transaction",
524
537
  "trash",
525
538
  "tree",
@@ -527,6 +540,7 @@ class DorisGenerator(MySQLGenerator):
527
540
  "trim",
528
541
  "true",
529
542
  "truncate",
543
+ "try_cast",
530
544
  "type",
531
545
  "type_cast",
532
546
  "types",
@@ -539,6 +553,7 @@ class DorisGenerator(MySQLGenerator):
539
553
  "unsigned",
540
554
  "update",
541
555
  "use",
556
+ "use_mv",
542
557
  "user",
543
558
  "using",
544
559
  "value",
@@ -651,17 +651,6 @@ def _struct_sql(self: DuckDBGenerator, expression: exp.Struct) -> str:
651
651
  return f"ROW({csv_args})" if is_bq_inline_struct else f"{{{csv_args}}}"
652
652
 
653
653
 
654
- def _datatype_sql(self: DuckDBGenerator, expression: exp.DataType) -> str:
655
- if expression.is_type("array"):
656
- return f"{self.expressions(expression, flat=True)}[{self.expressions(expression, key='values', flat=True)}]"
657
-
658
- # Modifiers are not supported for TIME, [TIME | TIMESTAMP] WITH TIME ZONE
659
- if expression.is_type(exp.DType.TIME, exp.DType.TIMETZ, exp.DType.TIMESTAMPTZ):
660
- return expression.this.value
661
-
662
- return self.datatype_sql(expression)
663
-
664
-
665
654
  def _json_format_sql(self: DuckDBGenerator, expression: exp.JSONFormat) -> str:
666
655
  sql = self.func("TO_JSON", expression.this, expression.args.get("options"))
667
656
  return f"CAST({sql} AS TEXT)"
@@ -1665,7 +1654,6 @@ class DuckDBGenerator(generator.Generator):
1665
1654
  if e.args.get("abbreviated")
1666
1655
  else self.func("MONTHNAME", e.this)
1667
1656
  ),
1668
- exp.DataType: _datatype_sql,
1669
1657
  exp.Date: _date_sql,
1670
1658
  exp.DateAdd: _date_delta_to_binary_interval_op(),
1671
1659
  exp.DateFromParts: _date_from_parts_sql,
@@ -2308,6 +2296,18 @@ class DuckDBGenerator(generator.Generator):
2308
2296
  _TRYCAST_DATE_SLASH_FMT = "%m/%d/%Y"
2309
2297
  _TRYCAST_DATE_MON_FMT = "%d-%b-%Y"
2310
2298
 
2299
+ def datatype_sql(self, expression: exp.DataType) -> str:
2300
+ if expression.is_type(exp.DType.ARRAY):
2301
+ return f"{self.expressions(expression, flat=True)}[{self.expressions(expression, key='values', flat=True)}]"
2302
+
2303
+ # Modifiers are not supported for TIME, [TIME | TIMESTAMP] WITH TIME ZONE
2304
+ if expression.is_type(
2305
+ exp.DType.TIME, exp.DType.TIMETZ, exp.DType.TIMESTAMPTZ, exp.DType.TIMESTAMPLTZ
2306
+ ):
2307
+ expression.set("expressions", None)
2308
+
2309
+ return super().datatype_sql(expression)
2310
+
2311
2311
  def _array_bag_sql(self, condition: exp.Expr, arr1: exp.Expr, arr2: exp.Expr) -> str:
2312
2312
  cond = exp.Paren(this=exp.replace_placeholders(condition, arr1=arr1, arr2=arr2))
2313
2313
  return self.sql(
@@ -53,22 +53,22 @@ class FabricGenerator(TSQLGenerator):
53
53
  **TSQLGenerator.TYPE_MAPPING,
54
54
  exp.DType.DATETIME: "DATETIME2",
55
55
  exp.DType.DECIMAL: "DECIMAL",
56
- exp.DType.IMAGE: "VARBINARY",
56
+ exp.DType.IMAGE: "VARBINARY(MAX)",
57
57
  exp.DType.INT: "INT",
58
- exp.DType.JSON: "VARCHAR",
59
- exp.DType.MONEY: "DECIMAL",
58
+ exp.DType.JSON: "VARCHAR(MAX)",
59
+ exp.DType.MONEY: "DECIMAL(19, 4)",
60
60
  exp.DType.NCHAR: "CHAR",
61
61
  exp.DType.NVARCHAR: "VARCHAR",
62
62
  exp.DType.ROWVERSION: "ROWVERSION",
63
63
  exp.DType.SMALLDATETIME: "DATETIME2",
64
- exp.DType.SMALLMONEY: "DECIMAL",
64
+ exp.DType.SMALLMONEY: "DECIMAL(10, 4)",
65
65
  exp.DType.TIMESTAMP: "DATETIME2",
66
66
  exp.DType.TIMESTAMPNTZ: "DATETIME2",
67
67
  exp.DType.TIMESTAMPTZ: "DATETIME2",
68
68
  exp.DType.TINYINT: "SMALLINT",
69
69
  exp.DType.UTINYINT: "SMALLINT",
70
70
  exp.DType.UUID: "UNIQUEIDENTIFIER",
71
- exp.DType.XML: "VARCHAR",
71
+ exp.DType.XML: "VARCHAR(MAX)",
72
72
  }
73
73
 
74
74
  TRANSFORMS = {
@@ -17,6 +17,7 @@ from sqlglot.dialects.dialect import (
17
17
  no_pivot_sql,
18
18
  no_tablesample_sql,
19
19
  no_trycast_sql,
20
+ if_sql,
20
21
  remove_ts_or_ds_to_date,
21
22
  rename_func,
22
23
  strposition_sql,
@@ -165,6 +166,8 @@ class MySQLGenerator(generator.Generator):
165
166
  f"""GROUP_CONCAT({self.sql(e, "this")} SEPARATOR {self.sql(e, "separator") or "','"})"""
166
167
  ),
167
168
  exp.ILike: no_ilike_sql,
169
+ # https://dev.mysql.com/doc/refman/9.7/en/flow-control-functions.html#function_if
170
+ exp.If: if_sql(false_value="NULL"),
168
171
  exp.JSONExtractScalar: arrow_json_extract_sql,
169
172
  exp.Length: length_or_char_length_sql,
170
173
  exp.LogicalOr: rename_func("MAX"),
@@ -692,6 +695,15 @@ class MySQLGenerator(generator.Generator):
692
695
  global_ = " GLOBAL" if expression.args.get("global_") else ""
693
696
 
694
697
  target = self.sql(expression, "target")
698
+
699
+ # SHOW CREATE ... takes a possibly qualified name, it has no FROM clause
700
+ # https://dev.mysql.com/doc/refman/8.4/en/show-create-table.html
701
+ if expression.name.startswith("CREATE") and (db_id := self.sql(expression, "db")):
702
+ target = f"{db_id}.{target}"
703
+ db = ""
704
+ else:
705
+ db = self._prefixed_sql("FROM", expression, "db")
706
+
695
707
  target = f" {target}" if target else ""
696
708
  if expression.name in ("COLUMNS", "INDEX"):
697
709
  target = f" FROM{target}"
@@ -702,8 +714,6 @@ class MySQLGenerator(generator.Generator):
702
714
  elif expression.name == "PROJECTIONS":
703
715
  target = f" ON TABLE{target}" if target else ""
704
716
 
705
- db = self._prefixed_sql("FROM", expression, "db")
706
-
707
717
  like = self._prefixed_sql("LIKE", expression, "like")
708
718
  where = self.sql(expression, "where")
709
719
 
@@ -90,6 +90,15 @@ def _dpipe_sql(self: generator.Generator, e: exp.DPipe) -> str:
90
90
  return self.func("SAFECONCAT" if e.args.get("safe") else "CONCAT", e.this, e.expression)
91
91
 
92
92
 
93
+ def _distinct_sql(self, e: exp.Distinct) -> str:
94
+ this = self.expressions(e, flat=True)
95
+
96
+ if len(e.expressions) == 1:
97
+ return f"set({this})"
98
+
99
+ return f"set(ZIPNOTNULL({this}))"
100
+
101
+
93
102
  class PythonGenerator(generator.Generator):
94
103
  TRANSFORMS = {
95
104
  **{klass: _rename for klass in subclasses(exp.__name__, exp.Binary)},
@@ -105,7 +114,7 @@ class PythonGenerator(generator.Generator):
105
114
  exp.Concat: lambda self, e: self.func(
106
115
  "SAFECONCAT" if e.args.get("safe") else "CONCAT", *e.expressions
107
116
  ),
108
- exp.Distinct: lambda self, e: f"set({self.sql(e, 'this')})",
117
+ exp.Distinct: _distinct_sql,
109
118
  exp.Div: _div_sql,
110
119
  exp.DPipe: _dpipe_sql,
111
120
  exp.Extract: lambda self, e: f"EXTRACT('{e.name.lower()}', {self.sql(e, 'expression')})",
@@ -1454,6 +1454,17 @@ class SingleStoreGenerator(MySQLGenerator):
1454
1454
 
1455
1455
  return self.sql(res)
1456
1456
 
1457
+ def withingroup_sql(self, expression: exp.WithinGroup) -> str:
1458
+ # SingleStore includes trailing NULLs in percentile calculations, so we sort them first
1459
+ if isinstance(expression.this, (exp.PercentileCont, exp.PercentileDisc)) and isinstance(
1460
+ expression.expression, exp.Order
1461
+ ):
1462
+ expression = expression.copy()
1463
+ for ordered in expression.expression.expressions:
1464
+ ordered.set("nulls_first", True)
1465
+
1466
+ return super().withingroup_sql(expression)
1467
+
1457
1468
  def all_sql(self, expression: exp.All) -> str:
1458
1469
  self.unsupported("ALL subquery predicate is not supported in SingleStore")
1459
1470
  return super().all_sql(expression)
@@ -128,6 +128,9 @@ class SparkGenerator(Spark2Generator):
128
128
  exp.SafeMultiply: rename_func("TRY_MULTIPLY"),
129
129
  exp.SafeSubtract: rename_func("TRY_SUBTRACT"),
130
130
  exp.StartsWith: rename_func("STARTSWITH"),
131
+ exp.StabilityProperty: lambda self, e: (
132
+ "DETERMINISTIC" if e.name == "IMMUTABLE" else "NOT DETERMINISTIC"
133
+ ),
131
134
  exp.TimeAdd: date_delta_to_binary_interval_op(cast=False),
132
135
  exp.TimeSub: date_delta_to_binary_interval_op(cast=False),
133
136
  exp.TsOrDsAdd: _dateadd_sql,