sqlglot 30.23.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 (340) hide show
  1. {sqlglot-30.23.0 → sqlglot-30.24.0}/CHANGELOG.md +65 -0
  2. {sqlglot-30.23.0/sqlglot.egg-info → sqlglot-30.24.0}/PKG-INFO +3 -3
  3. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/_version.py +3 -3
  4. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/clickhouse.py +1 -0
  5. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/dialect.py +15 -1
  6. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/oracle.py +1 -0
  7. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/postgres.py +4 -0
  8. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/starrocks.py +17 -0
  9. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/array.py +1 -5
  10. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/query.py +8 -0
  11. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generator.py +31 -1
  12. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/bigquery.py +142 -1
  13. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/clickhouse.py +2 -1
  14. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/duckdb.py +36 -40
  15. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/fabric.py +5 -0
  16. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/hive.py +4 -0
  17. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/mysql.py +3 -0
  18. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/postgres.py +8 -3
  19. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/presto.py +14 -7
  20. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/snowflake.py +15 -7
  21. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/spark2.py +22 -1
  22. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/starrocks.py +35 -4
  23. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/teradata.py +11 -1
  24. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/helper.py +17 -0
  25. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/annotate_types.py +24 -16
  26. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/merge_subqueries.py +4 -0
  27. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/optimize_joins.py +5 -1
  28. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/qualify_columns.py +33 -9
  29. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/scope.py +8 -7
  30. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/simplify.py +23 -5
  31. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/unnest_subqueries.py +29 -0
  32. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parser.py +145 -32
  33. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/clickhouse.py +6 -0
  34. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/doris.py +3 -3
  35. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/dremio.py +3 -0
  36. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/drill.py +3 -0
  37. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/duckdb.py +34 -8
  38. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/hive.py +13 -0
  39. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/mysql.py +71 -3
  40. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/oracle.py +3 -1
  41. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/postgres.py +3 -1
  42. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/presto.py +2 -0
  43. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/prql.py +2 -8
  44. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/redshift.py +3 -1
  45. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/singlestore.py +3 -0
  46. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/snowflake.py +4 -4
  47. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/spark2.py +4 -1
  48. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/sqlite.py +14 -1
  49. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/starrocks.py +73 -10
  50. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/teradata.py +15 -0
  51. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/trino.py +6 -1
  52. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/tokenizer_core.py +1 -0
  53. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/transforms.py +3 -3
  54. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/__init__.py +1 -1
  55. {sqlglot-30.23.0 → sqlglot-30.24.0/sqlglot.egg-info}/PKG-INFO +3 -3
  56. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot.egg-info/SOURCES.txt +1 -0
  57. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot.egg-info/requires.txt +2 -2
  58. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot.egg-info/scm_file_list.json +1 -0
  59. sqlglot-30.24.0/sqlglot.egg-info/scm_version.json +8 -0
  60. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglotc/setup.py +17 -0
  61. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_bigquery.py +73 -1
  62. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_clickhouse.py +4 -0
  63. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_dialect.py +193 -9
  64. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_duckdb.py +64 -30
  65. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_fabric.py +7 -0
  66. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_hive.py +32 -13
  67. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_mysql.py +102 -0
  68. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_oracle.py +12 -0
  69. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_postgres.py +90 -0
  70. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_presto.py +10 -16
  71. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_snowflake.py +8 -17
  72. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_spark.py +28 -11
  73. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_sqlite.py +40 -0
  74. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_starrocks.py +116 -0
  75. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_teradata.py +38 -1
  76. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_trino.py +125 -0
  77. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/merge_subqueries.sql +48 -0
  78. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/qualify_columns.sql +11 -0
  79. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/simplify.sql +64 -0
  80. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_build.py +2 -0
  81. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_generator.py +9 -0
  82. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_helper.py +21 -1
  83. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_optimizer.py +197 -0
  84. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_parser.py +131 -6
  85. sqlglot-30.24.0/tests/test_sqlglotc.py +113 -0
  86. sqlglot-30.23.0/sqlglot.egg-info/scm_version.json +0 -8
  87. {sqlglot-30.23.0 → sqlglot-30.24.0}/.gitignore +0 -0
  88. {sqlglot-30.23.0 → sqlglot-30.24.0}/.gitmodules +0 -0
  89. {sqlglot-30.23.0 → sqlglot-30.24.0}/.gitpod.yml +0 -0
  90. {sqlglot-30.23.0 → sqlglot-30.24.0}/.pre-commit-config.yaml +0 -0
  91. {sqlglot-30.23.0 → sqlglot-30.24.0}/AGENTS.md +0 -0
  92. {sqlglot-30.23.0 → sqlglot-30.24.0}/CLAUDE.md +0 -0
  93. {sqlglot-30.23.0 → sqlglot-30.24.0}/CONTRIBUTING.md +0 -0
  94. {sqlglot-30.23.0 → sqlglot-30.24.0}/LICENSE +0 -0
  95. {sqlglot-30.23.0 → sqlglot-30.24.0}/MANIFEST.in +0 -0
  96. {sqlglot-30.23.0 → sqlglot-30.24.0}/Makefile +0 -0
  97. {sqlglot-30.23.0 → sqlglot-30.24.0}/README.md +0 -0
  98. {sqlglot-30.23.0 → sqlglot-30.24.0}/pyproject.toml +0 -0
  99. {sqlglot-30.23.0 → sqlglot-30.24.0}/setup.cfg +0 -0
  100. {sqlglot-30.23.0 → sqlglot-30.24.0}/setup.py +0 -0
  101. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/__init__.py +0 -0
  102. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/__main__.py +0 -0
  103. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/_typing.py +0 -0
  104. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/anonymize.py +0 -0
  105. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/__init__.py +0 -0
  106. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/athena.py +0 -0
  107. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/bigquery.py +0 -0
  108. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/databricks.py +0 -0
  109. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/dax.py +0 -0
  110. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/doris.py +0 -0
  111. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/dremio.py +0 -0
  112. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/drill.py +0 -0
  113. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/druid.py +0 -0
  114. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/duckdb.py +0 -0
  115. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/dune.py +0 -0
  116. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/exasol.py +0 -0
  117. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/fabric.py +0 -0
  118. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/hive.py +0 -0
  119. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/materialize.py +0 -0
  120. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/mysql.py +0 -0
  121. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/presto.py +0 -0
  122. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/prql.py +0 -0
  123. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/redshift.py +0 -0
  124. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/risingwave.py +0 -0
  125. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/singlestore.py +0 -0
  126. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/snowflake.py +0 -0
  127. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/solr.py +0 -0
  128. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/spark.py +0 -0
  129. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/spark2.py +0 -0
  130. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/sqlite.py +0 -0
  131. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/tableau.py +0 -0
  132. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/teradata.py +0 -0
  133. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/trino.py +0 -0
  134. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/dialects/tsql.py +0 -0
  135. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/diff.py +0 -0
  136. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/errors.py +0 -0
  137. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/executor/__init__.py +0 -0
  138. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/executor/context.py +0 -0
  139. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/executor/env.py +0 -0
  140. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/executor/python.py +0 -0
  141. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/executor/table.py +0 -0
  142. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/__init__.py +0 -0
  143. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/aggregate.py +0 -0
  144. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/builders.py +0 -0
  145. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/constraints.py +0 -0
  146. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/core.py +0 -0
  147. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/datatypes.py +0 -0
  148. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/ddl.py +0 -0
  149. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/dml.py +0 -0
  150. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/functions.py +0 -0
  151. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/json.py +0 -0
  152. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/math.py +0 -0
  153. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/properties.py +0 -0
  154. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/string.py +0 -0
  155. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/expressions/temporal.py +0 -0
  156. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/__init__.py +0 -0
  157. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/athena.py +0 -0
  158. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/databricks.py +0 -0
  159. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/dax.py +0 -0
  160. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/doris.py +0 -0
  161. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/dremio.py +0 -0
  162. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/drill.py +0 -0
  163. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/druid.py +0 -0
  164. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/dune.py +0 -0
  165. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/exasol.py +0 -0
  166. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/materialize.py +0 -0
  167. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/oracle.py +0 -0
  168. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/prql.py +0 -0
  169. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/python.py +0 -0
  170. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/redshift.py +0 -0
  171. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/risingwave.py +0 -0
  172. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/singlestore.py +0 -0
  173. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/solr.py +0 -0
  174. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/spark.py +0 -0
  175. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/sqlite.py +0 -0
  176. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/tableau.py +0 -0
  177. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/trino.py +0 -0
  178. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/generators/tsql.py +0 -0
  179. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/jsonpath.py +0 -0
  180. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/lineage.py +0 -0
  181. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/__init__.py +0 -0
  182. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/canonicalize.py +0 -0
  183. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/canonicalize_internal_names.py +0 -0
  184. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/eliminate_ctes.py +0 -0
  185. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/eliminate_joins.py +0 -0
  186. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/eliminate_subqueries.py +0 -0
  187. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/helpers.py +0 -0
  188. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
  189. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/journal.py +0 -0
  190. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/normalize.py +0 -0
  191. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
  192. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/optimizer.py +0 -0
  193. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/pushdown_predicates.py +0 -0
  194. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/pushdown_projections.py +0 -0
  195. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/qualify.py +0 -0
  196. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/qualify_tables.py +0 -0
  197. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/optimizer/resolver.py +0 -0
  198. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/__init__.py +0 -0
  199. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/athena.py +0 -0
  200. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/base.py +0 -0
  201. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/bigquery.py +0 -0
  202. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/databricks.py +0 -0
  203. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/dax.py +0 -0
  204. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/druid.py +0 -0
  205. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/dune.py +0 -0
  206. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/exasol.py +0 -0
  207. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/fabric.py +0 -0
  208. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/materialize.py +0 -0
  209. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/risingwave.py +0 -0
  210. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/solr.py +0 -0
  211. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/spark.py +0 -0
  212. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/tableau.py +0 -0
  213. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/parsers/tsql.py +0 -0
  214. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/planner.py +0 -0
  215. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/py.typed +0 -0
  216. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/schema.py +0 -0
  217. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/serde.py +0 -0
  218. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/time.py +0 -0
  219. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/tokens.py +0 -0
  220. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/trie.py +0 -0
  221. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/bigquery.py +0 -0
  222. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/clickhouse.py +0 -0
  223. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/databricks.py +0 -0
  224. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/duckdb.py +0 -0
  225. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/hive.py +0 -0
  226. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/mysql.py +0 -0
  227. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/postgres.py +0 -0
  228. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/presto.py +0 -0
  229. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/redshift.py +0 -0
  230. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/snowflake.py +0 -0
  231. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/spark.py +0 -0
  232. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/spark2.py +0 -0
  233. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot/typing/tsql.py +0 -0
  234. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot.egg-info/dependency_links.txt +0 -0
  235. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot.egg-info/top_level.txt +0 -0
  236. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglot.png +0 -0
  237. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglotc/MANIFEST.in +0 -0
  238. {sqlglot-30.23.0 → sqlglot-30.24.0}/sqlglotc/pyproject.toml +0 -0
  239. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/__init__.py +0 -0
  240. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/__init__.py +0 -0
  241. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_athena.py +0 -0
  242. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_databricks.py +0 -0
  243. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_dax.py +0 -0
  244. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_doris.py +0 -0
  245. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_dremio.py +0 -0
  246. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_drill.py +0 -0
  247. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_druid.py +0 -0
  248. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_dune.py +0 -0
  249. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_exasol.py +0 -0
  250. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_materialize.py +0 -0
  251. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_pipe_syntax.py +0 -0
  252. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_prql.py +0 -0
  253. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_redshift.py +0 -0
  254. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_risingwave.py +0 -0
  255. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_singlestore.py +0 -0
  256. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_solr.py +0 -0
  257. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_tableau.py +0 -0
  258. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/dialects/test_tsql.py +0 -0
  259. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/identity.sql +0 -0
  260. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/jsonpath/LICENSE +0 -0
  261. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/jsonpath/cts.json +0 -0
  262. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/annotate_functions.sql +0 -0
  263. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/annotate_types.sql +0 -0
  264. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/canonicalize.sql +0 -0
  265. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/canonicalize_internal_names.sql +0 -0
  266. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/eliminate_ctes.sql +0 -0
  267. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/eliminate_joins.sql +0 -0
  268. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/eliminate_subqueries.sql +0 -0
  269. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/isolate_table_selects.sql +0 -0
  270. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/normalize.sql +0 -0
  271. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/normalize_identifiers.sql +0 -0
  272. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/optimize_joins.sql +0 -0
  273. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/optimizer.sql +0 -0
  274. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/pushdown_cte_alias_columns.sql +0 -0
  275. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/pushdown_predicates.sql +0 -0
  276. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/pushdown_projections.sql +0 -0
  277. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/qualify_columns__invalid.sql +0 -0
  278. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/qualify_columns__with_invisible.sql +0 -0
  279. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/qualify_columns_ddl.sql +0 -0
  280. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/qualify_tables.sql +0 -0
  281. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/quote_identifiers.sql +0 -0
  282. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/call_center.csv.gz +0 -0
  283. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/catalog_page.csv.gz +0 -0
  284. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/catalog_returns.csv.gz +0 -0
  285. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/catalog_sales.csv.gz +0 -0
  286. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/customer.csv.gz +0 -0
  287. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/customer_address.csv.gz +0 -0
  288. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/customer_demographics.csv.gz +0 -0
  289. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/date_dim.csv.gz +0 -0
  290. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/household_demographics.csv.gz +0 -0
  291. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/income_band.csv.gz +0 -0
  292. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/inventory.csv.gz +0 -0
  293. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/item.csv.gz +0 -0
  294. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/promotion.csv.gz +0 -0
  295. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/reason.csv.gz +0 -0
  296. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/ship_mode.csv.gz +0 -0
  297. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/store.csv.gz +0 -0
  298. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/store_returns.csv.gz +0 -0
  299. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/store_sales.csv.gz +0 -0
  300. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/time_dim.csv.gz +0 -0
  301. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/tpc-ds.sql +0 -0
  302. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/warehouse.csv.gz +0 -0
  303. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/web_page.csv.gz +0 -0
  304. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/web_returns.csv.gz +0 -0
  305. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/web_sales.csv.gz +0 -0
  306. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-ds/web_site.csv.gz +0 -0
  307. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-h/customer.csv.gz +0 -0
  308. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-h/lineitem.csv.gz +0 -0
  309. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-h/nation.csv.gz +0 -0
  310. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-h/orders.csv.gz +0 -0
  311. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-h/part.csv.gz +0 -0
  312. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-h/partsupp.csv.gz +0 -0
  313. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-h/region.csv.gz +0 -0
  314. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-h/supplier.csv.gz +0 -0
  315. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/tpc-h/tpc-h.sql +0 -0
  316. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/optimizer/unnest_subqueries.sql +0 -0
  317. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/partial.sql +0 -0
  318. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/fixtures/pretty.sql +0 -0
  319. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/gen_fixtures.py +0 -0
  320. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/helpers.py +0 -0
  321. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/leakcheck.py +0 -0
  322. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/sqlglot/__init__.py +0 -0
  323. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_anonymize.py +0 -0
  324. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_dialect_entry_points.py +0 -0
  325. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_dialect_imports.py +0 -0
  326. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_diff.py +0 -0
  327. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_docs.py +0 -0
  328. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_errors.py +0 -0
  329. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_executor.py +0 -0
  330. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_expressions.py +0 -0
  331. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_integration_loader.py +0 -0
  332. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_jsonpath.py +0 -0
  333. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_lineage.py +0 -0
  334. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_schema.py +0 -0
  335. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_serde.py +0 -0
  336. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_time.py +0 -0
  337. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_tokens.py +0 -0
  338. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_transforms.py +0 -0
  339. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_transpile.py +0 -0
  340. {sqlglot-30.23.0 → sqlglot-30.24.0}/tests/test_typing.py +0 -0
@@ -1,6 +1,70 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ## [v30.23.0] - 2026-10-14
5
+ ### :boom: BREAKING CHANGES
6
+ - due to [`cf39265`](https://github.com/tobymao/sqlglot/commit/cf39265a3e8efd8c32bab7f9c9b4f123fdfbf682) - hash flag for case-sensitive nodes [CLAUDE] *(PR [#8599](https://github.com/tobymao/sqlglot/pull/8599) by [@laravioli](https://github.com/laravioli))*:
7
+
8
+ hash flag for case-sensitive nodes [CLAUDE] (#8599)
9
+
10
+ - due to [`4d7d7ca`](https://github.com/tobymao/sqlglot/commit/4d7d7ca94250269dc1903d7175b7b8aa96e9a480) - generate JSONExtractRaw for JSON-valued extraction *(PR [#8601](https://github.com/tobymao/sqlglot/pull/8601) by [@ebarkhordar](https://github.com/ebarkhordar))*:
11
+
12
+ generate JSONExtractRaw for JSON-valued extraction (#8601)
13
+
14
+ - due to [`623dc88`](https://github.com/tobymao/sqlglot/commit/623dc8889ba7bffa9b006fd1d1641715b73d5ce4) - infer correct types for temporal interval arithmetic *(PR [#8622](https://github.com/tobymao/sqlglot/pull/8622) by [@georgesittas](https://github.com/georgesittas))*:
15
+
16
+ infer correct types for temporal interval arithmetic (#8622)
17
+
18
+
19
+ ### :sparkles: New Features
20
+ - [`8abe7f8`](https://github.com/tobymao/sqlglot/commit/8abe7f8382c80f95cb1e5a8a985969f6c11fd03a) - **starrocks**: parse TIME_SLICE into exp.TimeSlice [CLAUDE] *(PR [#8555](https://github.com/tobymao/sqlglot/pull/8555) by [@nytai](https://github.com/nytai))*
21
+ - [`f3a6eb9`](https://github.com/tobymao/sqlglot/commit/f3a6eb95e424ef03bf20fca05a0431a666946e90) - **doris**: parse full-text search operators [CLAUDE] *(PR [#8585](https://github.com/tobymao/sqlglot/pull/8585) by [@kaya-abdullah](https://github.com/kaya-abdullah))*
22
+ - :arrow_lower_right: *addresses issue [#8584](https://github.com/tobymao/sqlglot/issues/8584) opened by [@kaya-abdullah](https://github.com/kaya-abdullah)*
23
+ - [`3ba19ee`](https://github.com/tobymao/sqlglot/commit/3ba19eedd7b381f990f9926266457eda7a60095b) - **starrocks**: support AGGREGATE KEY tables [CLAUDE] *(PR [#8591](https://github.com/tobymao/sqlglot/pull/8591) by [@nytai](https://github.com/nytai))*
24
+ - [`9114355`](https://github.com/tobymao/sqlglot/commit/9114355463fd02a9b505c869edb0561503a07b19) - **mysql**: Allow constraints without names. *(PR [#8600](https://github.com/tobymao/sqlglot/pull/8600) by [@burnison](https://github.com/burnison))*
25
+ - [`6202d94`](https://github.com/tobymao/sqlglot/commit/6202d94764305621117dc6229cda79575ca103e5) - **starrocks**: support HLL columns and the HLL_UNION aggregation type [CLAUDE] *(PR [#8612](https://github.com/tobymao/sqlglot/pull/8612) by [@nytai](https://github.com/nytai))*
26
+ - [`0b00178`](https://github.com/tobymao/sqlglot/commit/0b0017821590b08497529d37387396adb6c3aa5b) - **spark**: parse all ALTER TABLE DROP COLUMN[S] forms [CLAUDE] *(PR [#8611](https://github.com/tobymao/sqlglot/pull/8611) by [@tsamaras](https://github.com/tsamaras))*
27
+ - [`59a96d8`](https://github.com/tobymao/sqlglot/commit/59a96d868a6b8ed114ac3e216201106fea8bc351) - **starrocks**: support REFRESH MATERIALIZED VIEW options [CLAUDE] *(PR [#8613](https://github.com/tobymao/sqlglot/pull/8613) by [@nytai](https://github.com/nytai))*
28
+ - [`676ba36`](https://github.com/tobymao/sqlglot/commit/676ba365497215dadf89c3fa57f4872529745650) - **mysql**: Support named `FOREIGN KEY` indexes. *(PR [#8615](https://github.com/tobymao/sqlglot/pull/8615) by [@burnison](https://github.com/burnison))*
29
+ - [`b679d0c`](https://github.com/tobymao/sqlglot/commit/b679d0cf8cad5bab7bb5004d9b8f8ce51d542b42) - **databricks**: match_recognize support closes [#8617](https://github.com/tobymao/sqlglot/pull/8617) *(commit by [@georgesittas](https://github.com/georgesittas))*
30
+
31
+ ### :bug: Bug Fixes
32
+ - [`a00dc2e`](https://github.com/tobymao/sqlglot/commit/a00dc2e5c489214bea53bacbbeba8713f21ebce1) - **postgres**: improve json_value support closes [#8579](https://github.com/tobymao/sqlglot/pull/8579) *(commit by [@georgesittas](https://github.com/georgesittas))*
33
+ - [`ffb9721`](https://github.com/tobymao/sqlglot/commit/ffb9721df98984c62817701ec8cd895cb3b1ee82) - **oracle**: tokenize q'...' quoted string literals [CLAUDE] *(PR [#8582](https://github.com/tobymao/sqlglot/pull/8582) by [@DylanMerigaud](https://github.com/DylanMerigaud))*
34
+ - [`e237d59`](https://github.com/tobymao/sqlglot/commit/e237d5980e8084cd2eceb874280efc3f3369c0ba) - **optimizer**: keep the alias outside of COALESCE when unnesting a COUNT subquery [CLAUDE] *(PR [#8589](https://github.com/tobymao/sqlglot/pull/8589) by [@anishmehta24](https://github.com/anishmehta24))*
35
+ - [`98bedf6`](https://github.com/tobymao/sqlglot/commit/98bedf649b244d321782a213944320d54f7cc868) - **oracle**: parse partition clauses and flashback queries [CODEX] *(PR [#8588](https://github.com/tobymao/sqlglot/pull/8588) by [@yousefissa](https://github.com/yousefissa))*
36
+ - :arrow_lower_right: *fixes issue [#8587](https://github.com/tobymao/sqlglot/issues/8587) opened by [@cofin](https://github.com/cofin)*
37
+ - [`09481ce`](https://github.com/tobymao/sqlglot/commit/09481cec085106bc77fb584e4d322f7e179a5a11) - **optimizer**: qualify bare USING columns after SEMI/ANTI JOIN closes [#8590](https://github.com/tobymao/sqlglot/pull/8590) *(PR [#8592](https://github.com/tobymao/sqlglot/pull/8592) by [@ansh-rohilla](https://github.com/ansh-rohilla))*
38
+ - :arrow_lower_right: *fixes issue [#8590](https://github.com/tobymao/sqlglot/issues/8590) opened by [@jackr-xceleration](https://github.com/jackr-xceleration)*
39
+ - [`df0a300`](https://github.com/tobymao/sqlglot/commit/df0a3006c485010e2bde4f2b6ce16594885772f0) - **duckdb**: append on 1-based ARRAY_INSERT -1 *(PR [#8597](https://github.com/tobymao/sqlglot/pull/8597) by [@siddharthsarda](https://github.com/siddharthsarda))*
40
+ - [`7d9a6cd`](https://github.com/tobymao/sqlglot/commit/7d9a6cd599c41e4bd886c757e1b9e60b39bef70c) - allow `EXTERNAL FUNCTION` in Athena `CTAS` *(PR [#8602](https://github.com/tobymao/sqlglot/pull/8602) by [@matthias-Q](https://github.com/matthias-Q))*
41
+ - [`e38929e`](https://github.com/tobymao/sqlglot/commit/e38929edd78a20f74fc19fee819e14ac23add687) - **teradata**: default window aggregate frame to the whole partition [CLAUDE] *(PR [#8596](https://github.com/tobymao/sqlglot/pull/8596) by [@bhuvan-uda](https://github.com/bhuvan-uda))*
42
+ - :arrow_lower_right: *fixes issue [#8595](https://github.com/tobymao/sqlglot/issues/8595) opened by [@bhuvan-uda](https://github.com/bhuvan-uda)*
43
+ - [`cf39265`](https://github.com/tobymao/sqlglot/commit/cf39265a3e8efd8c32bab7f9c9b4f123fdfbf682) - **expressions**: hash flag for case-sensitive nodes [CLAUDE] *(PR [#8599](https://github.com/tobymao/sqlglot/pull/8599) by [@laravioli](https://github.com/laravioli))*
44
+ - :arrow_lower_right: *fixes issue [#8598](https://github.com/tobymao/sqlglot/issues/8598) opened by [@laravioli](https://github.com/laravioli)*
45
+ - [`ab0a291`](https://github.com/tobymao/sqlglot/commit/ab0a291f91f1ba8c32058340bf76738c4ea685ea) - **oracle**: normalize flashback timestamps and simplify parsing *(PR [#8608](https://github.com/tobymao/sqlglot/pull/8608) by [@georgesittas](https://github.com/georgesittas))*
46
+ - [`a0cc28b`](https://github.com/tobymao/sqlglot/commit/a0cc28b91c3d186801d478e83967e967b86c90dd) - **doris**: round-trip MATCH operands and quoted analyzers *(PR [#8607](https://github.com/tobymao/sqlglot/pull/8607) by [@georgesittas](https://github.com/georgesittas))*
47
+ - [`4d7d7ca`](https://github.com/tobymao/sqlglot/commit/4d7d7ca94250269dc1903d7175b7b8aa96e9a480) - **clickhouse**: generate JSONExtractRaw for JSON-valued extraction *(PR [#8601](https://github.com/tobymao/sqlglot/pull/8601) by [@ebarkhordar](https://github.com/ebarkhordar))*
48
+ - [`1f8d15b`](https://github.com/tobymao/sqlglot/commit/1f8d15bbd68586704666533b21a5b35d710d68f0) - convert DuckDB ARRAY_SLICE endpoints to SLICE lengths *(PR [#8609](https://github.com/tobymao/sqlglot/pull/8609) by [@georgesittas](https://github.com/georgesittas))*
49
+ - [`61c3ca4`](https://github.com/tobymao/sqlglot/commit/61c3ca4479c167d9c90d51f73184568769fa0635) - **oracle**: parse CREATE TABLE TABLESPACE *(PR [#8605](https://github.com/tobymao/sqlglot/pull/8605) by [@cmodiano](https://github.com/cmodiano))*
50
+ - [`08f2405`](https://github.com/tobymao/sqlglot/commit/08f2405cfddc874f4366cbcca9e25233fcb11281) - **oracle**: expand alternative quoting and support national literals *(PR [#8606](https://github.com/tobymao/sqlglot/pull/8606) by [@georgesittas](https://github.com/georgesittas))*
51
+ - :arrow_lower_right: *fixes issue [#8580](https://github.com/tobymao/sqlglot/issues/8580) opened by [@cmodiano](https://github.com/cmodiano)*
52
+ - [`5b949bd`](https://github.com/tobymao/sqlglot/commit/5b949bd6b7f1db1474a87ac34d3a9246fa7de237) - **oracle**: parse CREATE TABLE physical attributes and storage clauses closes [#8581](https://github.com/tobymao/sqlglot/pull/8581) *(commit by [@georgesittas](https://github.com/georgesittas))*
53
+ - [`ba643d3`](https://github.com/tobymao/sqlglot/commit/ba643d33285475774c3253551e1ed18ac89e6c22) - **clickhouse**: transpile RegexpCount to countMatches [CLAUDE] *(PR [#8616](https://github.com/tobymao/sqlglot/pull/8616) by [@ekut](https://github.com/ekut))*
54
+ - [`623dc88`](https://github.com/tobymao/sqlglot/commit/623dc8889ba7bffa9b006fd1d1641715b73d5ce4) - **duckdb**: infer correct types for temporal interval arithmetic *(PR [#8622](https://github.com/tobymao/sqlglot/pull/8622) by [@georgesittas](https://github.com/georgesittas))*
55
+ - [`b1b244b`](https://github.com/tobymao/sqlglot/commit/b1b244b1f38a3000c94a7b21ee6dfae1959dd4b2) - **optimizer**: qualify columns for SPLIT_TO_TABLE *(PR [#8625](https://github.com/tobymao/sqlglot/pull/8625) by [@andrjohns](https://github.com/andrjohns))*
56
+ - [`e92c222`](https://github.com/tobymao/sqlglot/commit/e92c22287ff73a66e9dece115acedb81133f0dbf) - **duckdb**: cast array elements to text before applying the ARRAY_TO_STRING null replacement [CLAUDE] *(PR [#8627](https://github.com/tobymao/sqlglot/pull/8627) by [@anishmehta24](https://github.com/anishmehta24))*
57
+ - [`fbda0b9`](https://github.com/tobymao/sqlglot/commit/fbda0b91481d679f17844af15fb998cc559533be) - **parser**: keep the whole statement when REFRESH falls back to a cmd *(PR [#8621](https://github.com/tobymao/sqlglot/pull/8621) by [@nytai](https://github.com/nytai))*
58
+ - [`fdba492`](https://github.com/tobymao/sqlglot/commit/fdba492cec5a1fbe012add7f1aed18f46739c2a3) - **optimizer**: include semi/anti join refs when identifying alias collisions *(PR [#8623](https://github.com/tobymao/sqlglot/pull/8623) by [@treysp](https://github.com/treysp))*
59
+ - [`2c7b928`](https://github.com/tobymao/sqlglot/commit/2c7b928071ed32e72b218011a1a3c011dba26b24) - **athena**: route by each engine's rules when the combined tokenizer fails [CLAUDE] *(PR [#8629](https://github.com/tobymao/sqlglot/pull/8629) by [@masiljangajji](https://github.com/masiljangajji))*
60
+ - :arrow_lower_right: *fixes issue [#8628](https://github.com/tobymao/sqlglot/issues/8628) opened by [@masiljangajji](https://github.com/masiljangajji)*
61
+ - [`ad8764a`](https://github.com/tobymao/sqlglot/commit/ad8764a0436a7b5c500b783ebe50dbf20c1e477c) - keep a replacement's grouping in replace_placeholders *(PR [#8624](https://github.com/tobymao/sqlglot/pull/8624) by [@tobymao](https://github.com/tobymao))*
62
+
63
+ ### :wrench: Chores
64
+ - [`579789d`](https://github.com/tobymao/sqlglot/commit/579789dc3d368daf6aa0919ed5c0994187472a4b) - add support for Python 3.15 *(PR [#8586](https://github.com/tobymao/sqlglot/pull/8586) by [@Viicos](https://github.com/Viicos))*
65
+ - [`c0a9457`](https://github.com/tobymao/sqlglot/commit/c0a945740e55facdc7120c17cda2771dc55c7903) - **mysql**: tests for named FOREIGN KEY indexes *(commit by [@geooo109](https://github.com/geooo109))*
66
+
67
+
4
68
  ## [v30.22.0] - 2026-10-09
5
69
  ### :boom: BREAKING CHANGES
6
70
  - due to [`5d997d9`](https://github.com/tobymao/sqlglot/commit/5d997d94d8041ed12db5abe7a1155b30df057b43) - Parse bare `ALTER TABLE ... DROP c`. *(PR [#8432](https://github.com/tobymao/sqlglot/pull/8432) by [@burnison](https://github.com/burnison))*:
@@ -16239,3 +16303,4 @@ pip install "sqlglot[c]" # compiled — faster, but no subclassing
16239
16303
  [v30.20.0]: https://github.com/tobymao/sqlglot/compare/v30.19.0...v30.20.0
16240
16304
  [v30.21.0]: https://github.com/tobymao/sqlglot/compare/v30.20.0...v30.21.0
16241
16305
  [v30.22.0]: https://github.com/tobymao/sqlglot/compare/v30.21.0...v30.22.0
16306
+ [v30.23.0]: https://github.com/tobymao/sqlglot/compare/v30.22.0...v30.23.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 30.23.0
3
+ Version: 30.24.0
4
4
  Summary: An easily customizable SQL parser and transpiler
5
5
  Author-email: Toby Mao <toby.mao@gmail.com>
6
6
  License-Expression: MIT
@@ -34,10 +34,10 @@ Requires-Dist: types-pytz; extra == "dev"
34
34
  Requires-Dist: typing_extensions; extra == "dev"
35
35
  Requires-Dist: pyperf; extra == "dev"
36
36
  Provides-Extra: c
37
- Requires-Dist: sqlglotc==30.23.0; python_version >= "3.10" and extra == "c"
37
+ Requires-Dist: sqlglotc==30.24.0; python_version >= "3.10" and extra == "c"
38
38
  Provides-Extra: rs
39
39
  Requires-Dist: sqlglotrs==0.13.0; extra == "rs"
40
- Requires-Dist: sqlglotc==30.23.0; python_version >= "3.10" and extra == "rs"
40
+ Requires-Dist: sqlglotc==30.24.0; python_version >= "3.10" and extra == "rs"
41
41
  Dynamic: license-file
42
42
  Dynamic: provides-extra
43
43
 
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '30.23.0'
22
- __version_tuple__ = version_tuple = (30, 23, 0)
21
+ __version__ = version = '30.24.0'
22
+ __version_tuple__ = version_tuple = (30, 24, 0)
23
23
 
24
- __commit_id__ = commit_id = 'gad8764a04'
24
+ __commit_id__ = commit_id = 'g5d588c0f3'
@@ -116,6 +116,7 @@ class ClickHouse(Dialect):
116
116
  "UINT8": TokenType.UTINYINT,
117
117
  "IPV4": TokenType.IPV4,
118
118
  "IPV6": TokenType.IPV6,
119
+ "PASTE": TokenType.PASTE,
119
120
  "POINT": TokenType.POINT,
120
121
  "PROJECTION": TokenType.PROJECTION,
121
122
  "RING": TokenType.RING,
@@ -2140,7 +2140,10 @@ def is_parse_json(expression: exp.Expr) -> bool:
2140
2140
 
2141
2141
 
2142
2142
  def isnull_to_is_null(args: BuilderArgs) -> exp.Expr:
2143
- return exp.Paren(this=exp.Is(this=seq_get(args, 0), expression=exp.null()))
2143
+ this = seq_get(args, 0)
2144
+ if isinstance(this, (exp.Predicate, exp.Connector, exp.Not)):
2145
+ this = exp.Paren(this=this)
2146
+ return exp.Paren(this=exp.Is(this=this, expression=exp.null()))
2144
2147
 
2145
2148
 
2146
2149
  def generatedasidentitycolumnconstraint_sql(
@@ -2774,6 +2777,17 @@ def build_timetostr_or_tochar(
2774
2777
  return exp.ToChar.from_arg_list(args)
2775
2778
 
2776
2779
 
2780
+ def array_sort_order(expression: exp.ArraySort) -> tuple[bool, bool | None] | None:
2781
+ """Whether an ArraySort is ascending and puts NULLs first, or None if either isn't a literal."""
2782
+ asc = expression.args.get("asc") or exp.true()
2783
+ nulls_first = expression.args.get("nulls_first")
2784
+ if not isinstance(asc, exp.Boolean):
2785
+ return None
2786
+ if nulls_first is None:
2787
+ return asc.this, None
2788
+ return (asc.this, nulls_first.this) if isinstance(nulls_first, exp.Boolean) else None
2789
+
2790
+
2777
2791
  def build_replace_with_optional_replacement(args: BuilderArgs) -> exp.Replace:
2778
2792
  return exp.Replace(
2779
2793
  this=seq_get(args, 0),
@@ -37,6 +37,7 @@ class Oracle(Dialect):
37
37
  "HH12": "%I", # alias for HH
38
38
  "HH24": "%H", # Hour of day (0-23)
39
39
  "IW": "%V", # Calendar week of year (1-52 or 1-53), as defined by the ISO 8601 standard
40
+ "IYYY": "%G", # 4-digit year of the ISO 8601 week-numbering calendar
40
41
  "MI": "%M", # Minute (0-59)
41
42
  "MM": "%m", # Month (01-12; January = 01)
42
43
  "MON": "%b", # Abbreviated name of month
@@ -44,6 +44,10 @@ class Postgres(Dialect):
44
44
  "FMSS": "%-S", # Second
45
45
  "HH12": "%I", # 09
46
46
  "HH24": "%H", # 09
47
+ "iw": "%V", # ISO 8601 week of year
48
+ "IW": "%V", # ISO 8601 week of year
49
+ "iyyy": "%G", # ISO 8601 week-numbering year
50
+ "IYYY": "%G", # ISO 8601 week-numbering year
47
51
  "mi": "%M", # zero padded minute
48
52
  "MI": "%M", # zero padded minute
49
53
  "mm": "%m", # 01
@@ -18,16 +18,33 @@ class StarRocks(MySQL):
18
18
  }
19
19
 
20
20
  class Tokenizer(MySQL.Tokenizer):
21
+ # Unlike MySQL, "#" doesn't start a comment
22
+ COMMENTS = ["--", ("/*", "*/")]
21
23
  DASH_COMMENT_REQUIRES_BOUNDARY = False
22
24
  COMMENTS_TERMINATE_AT_NEWLINE_ONLY = False
23
25
 
24
26
  KEYWORDS = {
25
27
  **MySQL.Tokenizer.KEYWORDS,
28
+ "ADMIN": TokenType.COMMAND,
29
+ "BACKUP": TokenType.COMMAND,
30
+ "CANCEL": TokenType.COMMAND,
31
+ "DEALLOCATE": TokenType.COMMAND,
32
+ "EXPORT": TokenType.COMMAND,
26
33
  "HLL": TokenType.HLLSKETCH,
34
+ "INSTALL": TokenType.COMMAND,
27
35
  "LARGEINT": TokenType.INT128,
36
+ "PAUSE": TokenType.COMMAND,
37
+ "RECOVER": TokenType.COMMAND,
28
38
  "REFRESH": TokenType.REFRESH,
39
+ "RESTORE": TokenType.COMMAND,
40
+ "RESUME": TokenType.COMMAND,
41
+ "STOP": TokenType.COMMAND,
42
+ "SUBMIT": TokenType.COMMAND,
43
+ "UNINSTALL": TokenType.COMMAND,
29
44
  }
30
45
  KEYWORDS.pop("IGNORE")
46
+ KEYWORDS.pop("#>")
47
+ KEYWORDS.pop("#>>")
31
48
 
32
49
  Parser = StarRocksParser
33
50
 
@@ -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
 
@@ -1938,6 +1938,10 @@ class WindowSpec(Expression):
1938
1938
  }
1939
1939
 
1940
1940
 
1941
+ class PartitionByExcluding(Expression):
1942
+ arg_types = {"expressions": True}
1943
+
1944
+
1941
1945
  class PreWhere(Expression):
1942
1946
  pass
1943
1947
 
@@ -2020,6 +2024,10 @@ class DropPartition(Expression):
2020
2024
  arg_types = {"expressions": True, "exists": False}
2021
2025
 
2022
2026
 
2027
+ class ReplaceColumns(Expression):
2028
+ arg_types = {"expressions": True}
2029
+
2030
+
2023
2031
  class ReplacePartition(Expression):
2024
2032
  arg_types = {"expression": True, "source": True}
2025
2033
 
@@ -2178,6 +2178,7 @@ class Generator:
2178
2178
  property_name = exp.Properties.PROPERTY_TO_NAME.get(property_cls)
2179
2179
  if not property_name:
2180
2180
  self.unsupported(f"Unsupported property {expression.key}")
2181
+ return ""
2181
2182
 
2182
2183
  return f"{property_name}={self.sql(expression, 'this')}"
2183
2184
 
@@ -2319,6 +2320,10 @@ class Generator:
2319
2320
  override = " OVERRIDE" if expression.args.get("override") else ""
2320
2321
  return f"LOCKING {kind}{this}{for_or_in} {lock_type}{override}"
2321
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
+
2322
2327
  def withdataproperty_sql(self, expression: exp.WithDataProperty) -> str:
2323
2328
  data_sql = f"WITH {'NO ' if expression.args.get('no') else ''}DATA"
2324
2329
  statistics = expression.args.get("statistics")
@@ -2561,6 +2566,10 @@ class Generator:
2561
2566
  expression: exp.TableSample,
2562
2567
  tablesample_keyword: str | None = None,
2563
2568
  ) -> str:
2569
+ if expression.expressions:
2570
+ self.unsupported("Multiple sample sets are not supported")
2571
+ return ""
2572
+
2564
2573
  method = self.sql(expression, "method")
2565
2574
  method = f"{method} " if method and self.TABLESAMPLE_WITH_METHOD else ""
2566
2575
  numerator = self.sql(expression, "bucket_numerator")
@@ -3638,6 +3647,9 @@ class Generator:
3638
3647
  partition = self.expressions(expression, key="partition_by", flat=True)
3639
3648
  return f"PARTITION BY {partition}" if partition else ""
3640
3649
 
3650
+ def partitionbyexcluding_sql(self, expression: exp.PartitionByExcluding) -> str:
3651
+ return f"EXCLUDING {self.expressions(expression, flat=True)}"
3652
+
3641
3653
  def windowspec_sql(self, expression: exp.WindowSpec) -> str:
3642
3654
  kind = self.sql(expression, "kind")
3643
3655
  start = csv(self.sql(expression, "start"), self.sql(expression, "start_side"), sep=" ")
@@ -4517,6 +4529,9 @@ class Generator:
4517
4529
  def addconstraint_sql(self, expression: exp.AddConstraint) -> str:
4518
4530
  return f"ADD {self.expressions(expression, indent=False)}"
4519
4531
 
4532
+ def replacecolumns_sql(self, expression: exp.ReplaceColumns) -> str:
4533
+ return f"REPLACE COLUMNS ({self.expressions(expression, flat=True)})"
4534
+
4520
4535
  def addpartition_sql(self, expression: exp.AddPartition) -> str:
4521
4536
  exists = "IF NOT EXISTS " if expression.args.get("exists") else ""
4522
4537
  location = self.sql(expression, "location")
@@ -4771,14 +4786,22 @@ class Generator:
4771
4786
  sqls: list[str] = []
4772
4787
  stack: list[None | str | exp.Expr] = [expression]
4773
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")
4774
4791
 
4775
4792
  while stack:
4776
4793
  node = stack.pop()
4777
4794
 
4778
- 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
+ ):
4779
4800
  op_func = node.args.get("operator")
4780
4801
  if op_func:
4781
4802
  op = f"OPERATOR({self.sql(op_func)})"
4803
+ elif is_is:
4804
+ op = "IS NOT" if node.args.get("negate") else "IS"
4782
4805
 
4783
4806
  stack.append(node.args.get("expression"))
4784
4807
  stack.append(f" {self.maybe_comment(op, comments=node.comments)} ")
@@ -6053,6 +6076,13 @@ class Generator:
6053
6076
  exp.TimestampDiff(this=expression.this, expression=start_ts, unit=exp.var("SECONDS"))
6054
6077
  )
6055
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
+
6056
6086
  def arraysize_sql(self, expression: exp.ArraySize) -> str:
6057
6087
  dim = expression.expression
6058
6088
 
@@ -3,10 +3,13 @@ from __future__ import annotations
3
3
  import logging
4
4
  import re
5
5
  import typing as t
6
+ from decimal import Decimal
7
+ from fractions import Fraction
6
8
 
7
9
  from sqlglot import exp, generator, transforms
8
10
  from sqlglot.dialects.dialect import (
9
11
  arg_max_or_min_no_count,
12
+ array_sort_order,
10
13
  date_add_interval_sql,
11
14
  datestrtodate_sql,
12
15
  filter_array_using_unnest,
@@ -176,6 +179,90 @@ def _array_contains_sql(self: BigQueryGenerator, expression: exp.ArrayContains)
176
179
  )
177
180
 
178
181
 
182
+ def _widen_decimal(expression: exp.Expr) -> exp.Expr:
183
+ # NUMERIC holds at most 29 integer and 9 fractional digits, e.g. DECIMAL(38, 0) needs BIGNUMERIC
184
+ for node in expression.find_all(exp.DataType):
185
+ if node.is_type(exp.DType.DECIMAL) and node.expressions:
186
+ precision, *rest = (param.this for param in node.expressions)
187
+ scale = rest[0] if rest else exp.Literal.number(0)
188
+ if precision.is_int and scale.is_int:
189
+ scale_digits = int(scale.name)
190
+ if int(precision.name) - scale_digits > 29 or scale_digits > 9:
191
+ node.set("this", exp.DType.BIGDECIMAL)
192
+ return expression
193
+
194
+
195
+ def _extract_part(part: str) -> t.Callable[[BigQueryGenerator, exp.Func], str]:
196
+ return lambda self, e: self.sql(exp.func("EXTRACT", exp.var(part), e.this, copy=False))
197
+
198
+
199
+ def _day_of_week_iso_sql(self: BigQueryGenerator, expression: exp.DayOfWeekIso) -> str:
200
+ # DAYOFWEEK is Sunday=1..Saturday=7, ISO is Monday=1..Sunday=7
201
+ template: exp.Expr = exp.maybe_parse("(MOD(EXTRACT(DAYOFWEEK FROM :this) + 5, 7) + 1)")
202
+ return self.sql(exp.replace_placeholders(template, this=expression.this))
203
+
204
+
205
+ def _array_agg_fold_sql(
206
+ self: BigQueryGenerator, expression: exp.ArrayDistinct | exp.ArraySort
207
+ ) -> str:
208
+ distinct = False
209
+ ignore_nulls = False
210
+ sort: exp.ArraySort | None = None
211
+ agg: exp.Expr = expression
212
+ while isinstance(agg, (exp.ArrayDistinct, exp.ArraySort)) and not agg.expression:
213
+ if isinstance(agg, exp.ArrayDistinct):
214
+ distinct = True
215
+ ignore_nulls |= agg.args.get("check_null") is False
216
+ elif sort is None:
217
+ sort = agg
218
+ agg = agg.this
219
+
220
+ order = array_sort_order(sort) if sort else None
221
+
222
+ # An ARRAY_AGG with its own ORDER BY or LIMIT can't take another
223
+ if (
224
+ not isinstance(agg, exp.ArrayAgg)
225
+ or isinstance(agg.this, (exp.Order, exp.Limit))
226
+ or (sort is not None and order is None)
227
+ ):
228
+ self.unsupported(
229
+ f"{expression.sql_name()} is only supported on an ARRAY_AGG without ORDER BY or LIMIT and with a literal order"
230
+ )
231
+ return self.func(expression.sql_name(), expression.this, expression.expression)
232
+
233
+ value = agg.this
234
+ if isinstance(value, exp.Distinct):
235
+ distinct, value = True, value.expressions[0]
236
+
237
+ folded: exp.Expr = exp.Distinct(expressions=[value]) if distinct else value
238
+ if order is not None:
239
+ asc, nulls_first = order
240
+ keys = [exp.Ordered(this=value.copy(), desc=not asc or None, nulls_first=asc)]
241
+
242
+ # Aggregate ORDER BY only puts NULLs first when ascending, so other placements need a key
243
+ if not ignore_nulls and nulls_first is not None and nulls_first != asc:
244
+ if distinct:
245
+ self.unsupported("ARRAY_AGG(DISTINCT) only puts NULLs first when ascending")
246
+ else:
247
+ is_null = value.copy().is_(exp.null())
248
+ keys.insert(
249
+ 0,
250
+ exp.Ordered(
251
+ this=is_null, desc=nulls_first or None, nulls_first=not nulls_first
252
+ ),
253
+ )
254
+ folded = exp.Order(this=folded, expressions=keys)
255
+ agg.set("this", folded)
256
+ if ignore_nulls:
257
+ # All-NULL input yields [], but an empty input still yields NULL.
258
+ agg = exp.If(
259
+ this=exp.Count(this=exp.Star()).eq(0),
260
+ true=exp.null(),
261
+ false=exp.func("COALESCE", exp.IgnoreNulls(this=agg), exp.array()),
262
+ )
263
+ return self.sql(agg)
264
+
265
+
179
266
  def _ts_or_ds_add_sql(self: BigQueryGenerator, expression: exp.TsOrDsAdd) -> str:
180
267
  return date_add_interval_sql("DATE", "ADD")(self, ts_or_ds_add_cast(expression))
181
268
 
@@ -311,6 +398,8 @@ class BigQueryGenerator(generator.Generator):
311
398
  exp.ArgMin: arg_max_or_min_no_count("MIN_BY"),
312
399
  exp.Array: inline_array_unless_query,
313
400
  exp.ArrayContains: _array_contains_sql,
401
+ exp.ArrayDistinct: _array_agg_fold_sql,
402
+ exp.ArraySort: _array_agg_fold_sql,
314
403
  exp.ArrayFilter: filter_array_using_unnest,
315
404
  exp.ArrayRemove: filter_array_using_unnest,
316
405
  exp.BitwiseAndAgg: rename_func("BIT_AND"),
@@ -318,7 +407,9 @@ class BigQueryGenerator(generator.Generator):
318
407
  exp.BitwiseXorAgg: rename_func("BIT_XOR"),
319
408
  exp.BitwiseCount: rename_func("BIT_COUNT"),
320
409
  exp.ByteLength: rename_func("BYTE_LENGTH"),
321
- exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]),
410
+ exp.Cast: transforms.preprocess(
411
+ [_widen_decimal, transforms.remove_precision_parameterized_types]
412
+ ),
322
413
  exp.CollateProperty: lambda self, e: (
323
414
  f"DEFAULT COLLATE {self.sql(e, 'this')}"
324
415
  if e.args.get("default")
@@ -336,6 +427,10 @@ class BigQueryGenerator(generator.Generator):
336
427
  exp.DatetimeAdd: date_add_interval_sql("DATETIME", "ADD"),
337
428
  exp.DatetimeSub: date_add_interval_sql("DATETIME", "SUB"),
338
429
  exp.DateFromUnixDate: rename_func("DATE_FROM_UNIX_DATE"),
430
+ exp.Day: _extract_part("DAY"),
431
+ exp.DayOfMonth: _extract_part("DAY"),
432
+ exp.DayOfWeekIso: _day_of_week_iso_sql,
433
+ exp.DayOfYear: _extract_part("DAYOFYEAR"),
339
434
  exp.Filter: no_filter_sql,
340
435
  exp.FromTimeZone: lambda self, e: self.func(
341
436
  "DATETIME", self.func("TIMESTAMP", e.this, e.args.get("zone")), "'UTC'"
@@ -346,6 +441,7 @@ class BigQueryGenerator(generator.Generator):
346
441
  ),
347
442
  exp.Hex: lambda self, e: self.func("UPPER", self.func("TO_HEX", self.sql(e, "this"))),
348
443
  exp.HexString: lambda self, e: self.hexstring_sql(e, binary_function_repr="FROM_HEX"),
444
+ exp.Hour: _extract_part("HOUR"),
349
445
  exp.If: if_sql(false_value="NULL"),
350
446
  exp.ILike: no_ilike_sql,
351
447
  exp.IntDiv: rename_func("DIV"),
@@ -366,12 +462,14 @@ class BigQueryGenerator(generator.Generator):
366
462
  exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)),
367
463
  exp.MD5Digest: rename_func("MD5"),
368
464
  exp.Min: min_or_least,
465
+ exp.Month: _extract_part("MONTH"),
369
466
  exp.Normalize: lambda self, e: self.func(
370
467
  "NORMALIZE_AND_CASEFOLD" if e.args.get("is_casefold") else "NORMALIZE",
371
468
  e.this,
372
469
  e.args.get("form"),
373
470
  ),
374
471
  exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}",
472
+ exp.Quarter: _extract_part("QUARTER"),
375
473
  exp.RegexpExtract: lambda self, e: self.func(
376
474
  "REGEXP_EXTRACT",
377
475
  e.this,
@@ -431,6 +529,8 @@ class BigQueryGenerator(generator.Generator):
431
529
  exp.Uuid: lambda *_: "GENERATE_UUID()",
432
530
  exp.Values: _derived_table_values_to_unnest,
433
531
  exp.VariancePop: rename_func("VAR_POP"),
532
+ exp.WeekOfYear: _extract_part("ISOWEEK"),
533
+ exp.Year: _extract_part("YEAR"),
434
534
  exp.SafeDivide: rename_func("SAFE_DIVIDE"),
435
535
  }
436
536
 
@@ -582,6 +682,47 @@ class BigQueryGenerator(generator.Generator):
582
682
  "within",
583
683
  }
584
684
 
685
+ def frombase_sql(self, expression: exp.FromBase) -> str:
686
+ # Hex is the only base BigQuery can cast from, and the sign goes before the prefix, e.g. -0xff
687
+ if expression.expression.name != "16":
688
+ self.unsupported("FROM_BASE is only supported for base 16")
689
+ return self.function_fallback_sql(expression)
690
+
691
+ prefixed = exp.func(
692
+ "REGEXP_REPLACE",
693
+ expression.this,
694
+ exp.Literal.string("^([+-]?)"),
695
+ exp.Literal.string("\\10x"),
696
+ copy=False,
697
+ )
698
+ return self.sql(exp.cast(prefixed, exp.DType.BIGINT, copy=False))
699
+
700
+ def approxquantile_sql(self, expression: exp.ApproxQuantile) -> str:
701
+ node: exp.Expr = expression
702
+ while node.parent and not isinstance(node.parent, (exp.Window, exp.AggFunc, exp.Select)):
703
+ node = node.parent
704
+ if isinstance(node.parent, exp.Window) and node.arg_key == "this":
705
+ self.unsupported("APPROX_QUANTILES does not support window functions")
706
+ return self.function_fallback_sql(expression)
707
+
708
+ # The k/n quantile is APPROX_QUANTILES(x, n)[k], e.g. 0.95 -> n = 20, k = 19. n is at most
709
+ # 100,000, so the quantile has at most 5 decimal places, and Decimal comparisons are exact
710
+ quantile = expression.args["quantile"]
711
+ weight = expression.args.get("weight")
712
+ value = Decimal(quantile.to_py()) if quantile.is_number else None
713
+ if (
714
+ value is None
715
+ or not 0 <= value <= 1
716
+ or round(value, 5) != value
717
+ or (weight and (not weight.is_number or weight.to_py() != 1))
718
+ ):
719
+ self.unsupported("APPROX_QUANTILE needs a literal quantile and no weight")
720
+ return self.function_fallback_sql(expression)
721
+
722
+ fraction = Fraction(value)
723
+ quantiles = exp.func("APPROX_QUANTILES", expression.this, fraction.denominator, copy=False)
724
+ return self.sql(quantiles[fraction.numerator])
725
+
585
726
  def weekstart_sql(self, expression: exp.WeekStart) -> str:
586
727
  if expression.this.name.upper() == "SUNDAY":
587
728
  # BigQuery specific optimization since WEEK(SUNDAY) == WEEK
@@ -688,7 +688,8 @@ class ClickHouseGenerator(generator.Generator):
688
688
  comment_prop = expression.find(exp.SchemaCommentProperty)
689
689
  if comment_prop:
690
690
  comment_prop.pop()
691
- query.replace(exp.paren(query))
691
+ if not isinstance(query, exp.Subquery):
692
+ query.replace(exp.paren(query))
692
693
  else:
693
694
  comment_prop = None
694
695