sqlglot 28.4.1__tar.gz → 28.6.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 (240) hide show
  1. {sqlglot-28.4.1 → sqlglot-28.6.0}/CHANGELOG.md +48 -0
  2. {sqlglot-28.4.1 → sqlglot-28.6.0}/PKG-INFO +44 -2
  3. {sqlglot-28.4.1 → sqlglot-28.6.0}/README.md +42 -0
  4. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/_version.py +3 -3
  5. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/bigquery.py +5 -7
  6. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/clickhouse.py +2 -0
  7. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/dialect.py +139 -5
  8. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/doris.py +1 -0
  9. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/druid.py +1 -0
  10. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/duckdb.py +835 -147
  11. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/exasol.py +17 -1
  12. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/hive.py +2 -0
  13. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/mysql.py +7 -11
  14. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/oracle.py +38 -1
  15. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/postgres.py +18 -30
  16. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/presto.py +2 -0
  17. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/redshift.py +4 -0
  18. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/singlestore.py +13 -3
  19. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/snowflake.py +161 -18
  20. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/spark.py +10 -0
  21. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/spark2.py +3 -2
  22. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/starrocks.py +1 -0
  23. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/trino.py +1 -0
  24. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/tsql.py +3 -0
  25. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/diff.py +1 -1
  26. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/expressions.py +140 -34
  27. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/generator.py +119 -25
  28. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/annotate_types.py +50 -14
  29. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/resolver.py +19 -0
  30. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/parser.py +124 -44
  31. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/schema.py +1 -0
  32. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/tokens.py +14 -2
  33. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/__init__.py +16 -1
  34. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/hive.py +3 -0
  35. sqlglot-28.6.0/sqlglot/typing/mysql.py +10 -0
  36. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/snowflake.py +67 -5
  37. sqlglot-28.6.0/sqlglot/typing/spark.py +10 -0
  38. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/spark2.py +6 -0
  39. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.egg-info/PKG-INFO +44 -2
  40. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.egg-info/SOURCES.txt +3 -0
  41. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.egg-info/requires.txt +1 -1
  42. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/Cargo.lock +1 -1
  43. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/Cargo.toml +1 -1
  44. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/src/tokenizer.rs +7 -2
  45. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_bigquery.py +1 -1
  46. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_clickhouse.py +5 -1
  47. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_databricks.py +1 -0
  48. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_dialect.py +172 -5
  49. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_druid.py +1 -0
  50. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_duckdb.py +116 -19
  51. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_exasol.py +18 -3
  52. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_mysql.py +9 -2
  53. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_oracle.py +63 -8
  54. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_postgres.py +77 -14
  55. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_presto.py +12 -0
  56. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_redshift.py +1 -0
  57. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_singlestore.py +4 -0
  58. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_snowflake.py +853 -57
  59. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_spark.py +14 -2
  60. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_teradata.py +1 -1
  61. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/identity.sql +2 -1
  62. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/annotate_functions.sql +344 -0
  63. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/annotate_types.sql +93 -0
  64. sqlglot-28.6.0/tests/test_dialect_entry_points.py +64 -0
  65. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_diff.py +7 -0
  66. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_generator.py +77 -0
  67. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_optimizer.py +61 -0
  68. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_parser.py +2 -0
  69. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_schema.py +30 -0
  70. {sqlglot-28.4.1 → sqlglot-28.6.0}/.gitignore +0 -0
  71. {sqlglot-28.4.1 → sqlglot-28.6.0}/.gitpod.yml +0 -0
  72. {sqlglot-28.4.1 → sqlglot-28.6.0}/.pre-commit-config.yaml +0 -0
  73. {sqlglot-28.4.1 → sqlglot-28.6.0}/CONTRIBUTING.md +0 -0
  74. {sqlglot-28.4.1 → sqlglot-28.6.0}/LICENSE +0 -0
  75. {sqlglot-28.4.1 → sqlglot-28.6.0}/MANIFEST.in +0 -0
  76. {sqlglot-28.4.1 → sqlglot-28.6.0}/Makefile +0 -0
  77. {sqlglot-28.4.1 → sqlglot-28.6.0}/pyproject.toml +0 -0
  78. {sqlglot-28.4.1 → sqlglot-28.6.0}/setup.cfg +0 -0
  79. {sqlglot-28.4.1 → sqlglot-28.6.0}/setup.py +0 -0
  80. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/__init__.py +0 -0
  81. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/__main__.py +0 -0
  82. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/_typing.py +0 -0
  83. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/__init__.py +0 -0
  84. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/athena.py +0 -0
  85. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/databricks.py +0 -0
  86. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/dremio.py +0 -0
  87. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/drill.py +0 -0
  88. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/dune.py +0 -0
  89. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/fabric.py +0 -0
  90. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/materialize.py +0 -0
  91. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/prql.py +0 -0
  92. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/risingwave.py +0 -0
  93. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/solr.py +0 -0
  94. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/sqlite.py +0 -0
  95. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/tableau.py +0 -0
  96. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/dialects/teradata.py +0 -0
  97. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/errors.py +0 -0
  98. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/executor/__init__.py +0 -0
  99. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/executor/context.py +0 -0
  100. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/executor/env.py +0 -0
  101. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/executor/python.py +0 -0
  102. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/executor/table.py +0 -0
  103. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/helper.py +0 -0
  104. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/jsonpath.py +0 -0
  105. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/lineage.py +0 -0
  106. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/__init__.py +0 -0
  107. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/canonicalize.py +0 -0
  108. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/eliminate_ctes.py +0 -0
  109. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/eliminate_joins.py +0 -0
  110. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/eliminate_subqueries.py +0 -0
  111. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
  112. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/merge_subqueries.py +0 -0
  113. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/normalize.py +0 -0
  114. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
  115. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/optimize_joins.py +0 -0
  116. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/optimizer.py +0 -0
  117. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/pushdown_predicates.py +0 -0
  118. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/pushdown_projections.py +0 -0
  119. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/qualify.py +0 -0
  120. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/qualify_columns.py +0 -0
  121. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/qualify_tables.py +0 -0
  122. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/scope.py +0 -0
  123. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/simplify.py +0 -0
  124. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/optimizer/unnest_subqueries.py +0 -0
  125. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/planner.py +0 -0
  126. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/py.typed +0 -0
  127. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/serde.py +0 -0
  128. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/time.py +0 -0
  129. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/transforms.py +0 -0
  130. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/trie.py +0 -0
  131. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/bigquery.py +0 -0
  132. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/presto.py +0 -0
  133. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot/typing/tsql.py +0 -0
  134. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.egg-info/dependency_links.txt +0 -0
  135. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.egg-info/top_level.txt +0 -0
  136. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglot.png +0 -0
  137. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/benches/dialect_settings.json +0 -0
  138. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/benches/long.rs +0 -0
  139. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/benches/token_type_settings.json +0 -0
  140. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/benches/tokenizer_dialect_settings.json +0 -0
  141. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/benches/tokenizer_settings.json +0 -0
  142. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/pyproject.toml +0 -0
  143. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/src/lib.rs +0 -0
  144. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/src/settings.rs +0 -0
  145. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/src/token.rs +0 -0
  146. {sqlglot-28.4.1 → sqlglot-28.6.0}/sqlglotrs/src/trie.rs +0 -0
  147. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/__init__.py +0 -0
  148. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/__init__.py +0 -0
  149. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_athena.py +0 -0
  150. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_doris.py +0 -0
  151. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_dremio.py +0 -0
  152. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_drill.py +0 -0
  153. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_dune.py +0 -0
  154. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_fabric.py +0 -0
  155. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_hive.py +0 -0
  156. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_materialize.py +0 -0
  157. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_pipe_syntax.py +0 -0
  158. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_prql.py +0 -0
  159. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_risingwave.py +0 -0
  160. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_solr.py +0 -0
  161. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_sqlite.py +0 -0
  162. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_starrocks.py +0 -0
  163. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_tableau.py +0 -0
  164. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_trino.py +0 -0
  165. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/dialects/test_tsql.py +0 -0
  166. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/jsonpath/LICENSE +0 -0
  167. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/jsonpath/cts.json +0 -0
  168. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/canonicalize.sql +0 -0
  169. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/eliminate_ctes.sql +0 -0
  170. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/eliminate_joins.sql +0 -0
  171. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/eliminate_subqueries.sql +0 -0
  172. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/isolate_table_selects.sql +0 -0
  173. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/merge_subqueries.sql +0 -0
  174. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/normalize.sql +0 -0
  175. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/normalize_identifiers.sql +0 -0
  176. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/optimize_joins.sql +0 -0
  177. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/optimizer.sql +0 -0
  178. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/pushdown_cte_alias_columns.sql +0 -0
  179. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/pushdown_predicates.sql +0 -0
  180. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/pushdown_projections.sql +0 -0
  181. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/qualify_columns.sql +0 -0
  182. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/qualify_columns__invalid.sql +0 -0
  183. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/qualify_columns__with_invisible.sql +0 -0
  184. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/qualify_columns_ddl.sql +0 -0
  185. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/qualify_tables.sql +0 -0
  186. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/quote_identifiers.sql +0 -0
  187. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/simplify.sql +0 -0
  188. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/call_center.csv.gz +0 -0
  189. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/catalog_page.csv.gz +0 -0
  190. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/catalog_returns.csv.gz +0 -0
  191. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/catalog_sales.csv.gz +0 -0
  192. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/customer.csv.gz +0 -0
  193. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/customer_address.csv.gz +0 -0
  194. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/customer_demographics.csv.gz +0 -0
  195. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/date_dim.csv.gz +0 -0
  196. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/household_demographics.csv.gz +0 -0
  197. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/income_band.csv.gz +0 -0
  198. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/inventory.csv.gz +0 -0
  199. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/item.csv.gz +0 -0
  200. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/promotion.csv.gz +0 -0
  201. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/reason.csv.gz +0 -0
  202. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/ship_mode.csv.gz +0 -0
  203. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/store.csv.gz +0 -0
  204. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/store_returns.csv.gz +0 -0
  205. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/store_sales.csv.gz +0 -0
  206. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/time_dim.csv.gz +0 -0
  207. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/tpc-ds.sql +0 -0
  208. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/warehouse.csv.gz +0 -0
  209. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/web_page.csv.gz +0 -0
  210. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/web_returns.csv.gz +0 -0
  211. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/web_sales.csv.gz +0 -0
  212. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-ds/web_site.csv.gz +0 -0
  213. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/customer.csv.gz +0 -0
  214. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/lineitem.csv.gz +0 -0
  215. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/nation.csv.gz +0 -0
  216. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/orders.csv.gz +0 -0
  217. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/part.csv.gz +0 -0
  218. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/partsupp.csv.gz +0 -0
  219. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/region.csv.gz +0 -0
  220. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/supplier.csv.gz +0 -0
  221. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/tpc-h/tpc-h.sql +0 -0
  222. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/optimizer/unnest_subqueries.sql +0 -0
  223. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/partial.sql +0 -0
  224. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/fixtures/pretty.sql +0 -0
  225. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/gen_fixtures.py +0 -0
  226. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/helpers.py +0 -0
  227. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_build.py +0 -0
  228. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_dialect_imports.py +0 -0
  229. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_docs.py +0 -0
  230. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_errors.py +0 -0
  231. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_executor.py +0 -0
  232. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_expressions.py +0 -0
  233. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_helper.py +0 -0
  234. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_jsonpath.py +0 -0
  235. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_lineage.py +0 -0
  236. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_serde.py +0 -0
  237. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_time.py +0 -0
  238. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_tokens.py +0 -0
  239. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_transforms.py +0 -0
  240. {sqlglot-28.4.1 → sqlglot-28.6.0}/tests/test_transpile.py +0 -0
@@ -1,6 +1,52 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ## [v28.5.0] - 2025-12-17
5
+ ### :boom: BREAKING CHANGES
6
+ - due to [`4dfc810`](https://github.com/tobymao/sqlglot/commit/4dfc810f45d5a617ada2ba4ed57002549c8d1853) - support transpilation of BOOLNOT from snowflake to duckdb *(PR [#6577](https://github.com/tobymao/sqlglot/pull/6577) by [@fivetran-felixhuang](https://github.com/fivetran-felixhuang))*:
7
+
8
+ support transpilation of BOOLNOT from snowflake to duckdb (#6577)
9
+
10
+ - due to [`b857185`](https://github.com/tobymao/sqlglot/commit/b8571850ca55802671484d118560a7b90e893c39) - remove Sysdate in favor of CurrentTimestamp with sysdate arg *(PR [#6584](https://github.com/tobymao/sqlglot/pull/6584) by [@georgesittas](https://github.com/georgesittas))*:
11
+
12
+ remove Sysdate in favor of CurrentTimestamp with sysdate arg (#6584)
13
+
14
+ - due to [`bf217d6`](https://github.com/tobymao/sqlglot/commit/bf217d69f92efcbce5b69d637976e915ca63998d) - make `JSONArrayAgg` an `AggFunc` *(PR [#6585](https://github.com/tobymao/sqlglot/pull/6585) by [@AbhishekASLK](https://github.com/AbhishekASLK))*:
15
+
16
+ make `JSONArrayAgg` an `AggFunc` (#6585)
17
+
18
+ - due to [`604efe5`](https://github.com/tobymao/sqlglot/commit/604efe5cf5812d0b1dd9d625ed278907d0d7fb8f) - Type annotation fixes for TO_TIMESTAMP* *(PR [#6557](https://github.com/tobymao/sqlglot/pull/6557) by [@fivetran-kwoodbeck](https://github.com/fivetran-kwoodbeck))*:
19
+
20
+ Type annotation fixes for TO_TIMESTAMP* (#6557)
21
+
22
+
23
+ ### :sparkles: New Features
24
+ - [`4dfc810`](https://github.com/tobymao/sqlglot/commit/4dfc810f45d5a617ada2ba4ed57002549c8d1853) - **snowflake**: support transpilation of BOOLNOT from snowflake to duckdb *(PR [#6577](https://github.com/tobymao/sqlglot/pull/6577) by [@fivetran-felixhuang](https://github.com/fivetran-felixhuang))*
25
+ - [`7077981`](https://github.com/tobymao/sqlglot/commit/707798166c1b45e633bd0e8d02d1c0146598b03a) - **snowflake**: Transpilation of Snowflake MONTHS_BETWEEN to DuckDB *(PR [#6561](https://github.com/tobymao/sqlglot/pull/6561) by [@fivetran-kwoodbeck](https://github.com/fivetran-kwoodbeck))*
26
+ - [`604efe5`](https://github.com/tobymao/sqlglot/commit/604efe5cf5812d0b1dd9d625ed278907d0d7fb8f) - **snowflake**: Type annotation fixes for TO_TIMESTAMP* *(PR [#6557](https://github.com/tobymao/sqlglot/pull/6557) by [@fivetran-kwoodbeck](https://github.com/fivetran-kwoodbeck))*
27
+ - [`3567880`](https://github.com/tobymao/sqlglot/commit/35678808dafb37c5d37c806682e6af9b6351bced) - add tokens to functions *(commit by [@tobymao](https://github.com/tobymao))*
28
+
29
+ ### :bug: Bug Fixes
30
+ - [`b857185`](https://github.com/tobymao/sqlglot/commit/b8571850ca55802671484d118560a7b90e893c39) - **snowflake**: remove Sysdate in favor of CurrentTimestamp with sysdate arg *(PR [#6584](https://github.com/tobymao/sqlglot/pull/6584) by [@georgesittas](https://github.com/georgesittas))*
31
+ - [`bf217d6`](https://github.com/tobymao/sqlglot/commit/bf217d69f92efcbce5b69d637976e915ca63998d) - make `JSONArrayAgg` an `AggFunc` *(PR [#6585](https://github.com/tobymao/sqlglot/pull/6585) by [@AbhishekASLK](https://github.com/AbhishekASLK))*
32
+ - [`48f5e99`](https://github.com/tobymao/sqlglot/commit/48f5e999d3d3f6ad51c30e7a33a3a574d0e50d2b) - **duckdb**: preserve l/r-trim syntax *(PR [#6588](https://github.com/tobymao/sqlglot/pull/6588) by [@georgesittas](https://github.com/georgesittas))*
33
+ - :arrow_lower_right: *fixes issue [#6587](https://github.com/tobymao/sqlglot/issues/6587) opened by [@baruchoxman](https://github.com/baruchoxman)*
34
+
35
+ ### :wrench: Chores
36
+ - [`ea0263a`](https://github.com/tobymao/sqlglot/commit/ea0263aa555591b03b06a4b6dee093fe42b545f9) - Skip integration tests GA for external contributors & fix `git diff` *(PR [#6582](https://github.com/tobymao/sqlglot/pull/6582) by [@VaggelisD](https://github.com/VaggelisD))*
37
+
38
+
39
+ ## [v28.4.1] - 2025-12-16
40
+ ### :boom: BREAKING CHANGES
41
+ - due to [`cfc9346`](https://github.com/tobymao/sqlglot/commit/cfc9346ba0477523d3de8f923d83fd09814b22ac) - bump sqlglotrs to 0.10.0 *(commit by [@tobymao](https://github.com/tobymao))*:
42
+
43
+ bump sqlglotrs to 0.10.0
44
+
45
+
46
+ ### :wrench: Chores
47
+ - [`cfc9346`](https://github.com/tobymao/sqlglot/commit/cfc9346ba0477523d3de8f923d83fd09814b22ac) - bump sqlglotrs to 0.10.0 *(commit by [@tobymao](https://github.com/tobymao))*
48
+
49
+
4
50
  ## [v28.4.0] - 2025-12-16
5
51
  ### :boom: BREAKING CHANGES
6
52
  - due to [`938f4b6`](https://github.com/tobymao/sqlglot/commit/938f4b6ebc1c0d26bd3c1400883978c79a435189) - annotate type for LAST_DAY *(PR [#5528](https://github.com/tobymao/sqlglot/pull/5528) by [@geooo109](https://github.com/geooo109))*:
@@ -11504,3 +11550,5 @@ Changelog
11504
11550
  [v28.2.0]: https://github.com/tobymao/sqlglot/compare/v28.1.0...v28.2.0
11505
11551
  [v28.3.0]: https://github.com/tobymao/sqlglot/compare/v28.2.0...v28.3.0
11506
11552
  [v28.4.0]: https://github.com/tobymao/sqlglot/compare/v27.6.1...v28.4.0
11553
+ [v28.4.1]: https://github.com/tobymao/sqlglot/compare/v28.4.0...v28.4.1
11554
+ [v28.5.0]: https://github.com/tobymao/sqlglot/compare/v28.4.1...v28.5.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 28.4.1
3
+ Version: 28.6.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
@@ -33,7 +33,7 @@ Requires-Dist: typing_extensions; extra == "dev"
33
33
  Requires-Dist: maturin<2.0,>=1.4; extra == "dev"
34
34
  Requires-Dist: pyperf; extra == "dev"
35
35
  Provides-Extra: rs
36
- Requires-Dist: sqlglotrs==0.10.0; extra == "rs"
36
+ Requires-Dist: sqlglotrs==0.11.0; extra == "rs"
37
37
  Dynamic: license-file
38
38
  Dynamic: provides-extra
39
39
 
@@ -71,6 +71,7 @@ Contributions are very welcome in SQLGlot; read the [contribution guide](https:/
71
71
  * [Used By](#used-by)
72
72
  * [Documentation](#documentation)
73
73
  * [Run Tests and Lint](#run-tests-and-lint)
74
+ * [Deployment](#deployment)
74
75
  * [Benchmarks](#benchmarks)
75
76
  * [Optional Dependencies](#optional-dependencies)
76
77
  * [Supported Dialects](#supported-dialects)
@@ -565,6 +566,21 @@ make test # Unit and integration tests (or test-rs, to use the Rust tokenizer)
565
566
  make check # Full test suite & linter checks
566
567
  ```
567
568
 
569
+ ## Deployment
570
+
571
+ To deploy a new SQLGlot version, follow these steps:
572
+
573
+ 1. Run `git pull` to make sure the local git repo is at the head of the main branch
574
+ 2. If the Rust tokenizer code changed since the last version release:
575
+ 1. Bump the `version` attribute under the `package` header in `sqlglotrs/Cargo.toml`
576
+ 2. Run `make install-dev`. This will update the `Cargo.lock` file
577
+ 3. Commit the changes made to `Cargo.toml` and `Cargo.lock`
578
+ 3. Do a `git tag` operation to bump the SQLGlot version, e.g. `git tag v28.5.0`
579
+ 4. Run `git push && git push --tags` to deploy the new version
580
+
581
+ > [!IMPORTANT]
582
+ > If there are any breaking changes since the last version release, make sure to deploy either a minor or major version for both sqlglot and sqlglotrs. Refer to SQLGlot's [versioning scheme](#versioning) for more information.
583
+
568
584
  ## Benchmarks
569
585
 
570
586
  [Benchmarks](https://github.com/tobymao/sqlglot/blob/main/benchmarks/bench.py) run on Python 3.10.12 in seconds.
@@ -627,3 +643,29 @@ x + interval '1' month
627
643
  **Official Dialects** are maintained by the core SQLGlot team with higher priority for bug fixes and feature additions.
628
644
 
629
645
  **Community Dialects** are developed and maintained primarily through community contributions. These are fully functional but may receive lower priority for issue resolution compared to officially supported dialects. We welcome and encourage community contributions to improve these dialects.
646
+
647
+ ### Creating a Dialect Plugin
648
+
649
+ If your database isn't supported, you can create a plugin that registers a custom dialect via entry points. Create a package with your dialect class and register it in `setup.py`:
650
+
651
+ ```python
652
+ from setuptools import setup
653
+
654
+ setup(
655
+ name="mydb-sqlglot-dialect",
656
+ entry_points={
657
+ "sqlglot.dialects": [
658
+ "mydb = my_package.dialect:MyDB",
659
+ ],
660
+ },
661
+ )
662
+ ```
663
+
664
+ The dialect will be automatically discovered and can be used like any built-in dialect:
665
+
666
+ ```python
667
+ from sqlglot import transpile
668
+ transpile("SELECT * FROM t", read="mydb", write="postgres")
669
+ ```
670
+
671
+ See the [Custom Dialects](#custom-dialects) section for implementation details.
@@ -32,6 +32,7 @@ Contributions are very welcome in SQLGlot; read the [contribution guide](https:/
32
32
  * [Used By](#used-by)
33
33
  * [Documentation](#documentation)
34
34
  * [Run Tests and Lint](#run-tests-and-lint)
35
+ * [Deployment](#deployment)
35
36
  * [Benchmarks](#benchmarks)
36
37
  * [Optional Dependencies](#optional-dependencies)
37
38
  * [Supported Dialects](#supported-dialects)
@@ -526,6 +527,21 @@ make test # Unit and integration tests (or test-rs, to use the Rust tokenizer)
526
527
  make check # Full test suite & linter checks
527
528
  ```
528
529
 
530
+ ## Deployment
531
+
532
+ To deploy a new SQLGlot version, follow these steps:
533
+
534
+ 1. Run `git pull` to make sure the local git repo is at the head of the main branch
535
+ 2. If the Rust tokenizer code changed since the last version release:
536
+ 1. Bump the `version` attribute under the `package` header in `sqlglotrs/Cargo.toml`
537
+ 2. Run `make install-dev`. This will update the `Cargo.lock` file
538
+ 3. Commit the changes made to `Cargo.toml` and `Cargo.lock`
539
+ 3. Do a `git tag` operation to bump the SQLGlot version, e.g. `git tag v28.5.0`
540
+ 4. Run `git push && git push --tags` to deploy the new version
541
+
542
+ > [!IMPORTANT]
543
+ > If there are any breaking changes since the last version release, make sure to deploy either a minor or major version for both sqlglot and sqlglotrs. Refer to SQLGlot's [versioning scheme](#versioning) for more information.
544
+
529
545
  ## Benchmarks
530
546
 
531
547
  [Benchmarks](https://github.com/tobymao/sqlglot/blob/main/benchmarks/bench.py) run on Python 3.10.12 in seconds.
@@ -588,3 +604,29 @@ x + interval '1' month
588
604
  **Official Dialects** are maintained by the core SQLGlot team with higher priority for bug fixes and feature additions.
589
605
 
590
606
  **Community Dialects** are developed and maintained primarily through community contributions. These are fully functional but may receive lower priority for issue resolution compared to officially supported dialects. We welcome and encourage community contributions to improve these dialects.
607
+
608
+ ### Creating a Dialect Plugin
609
+
610
+ If your database isn't supported, you can create a plugin that registers a custom dialect via entry points. Create a package with your dialect class and register it in `setup.py`:
611
+
612
+ ```python
613
+ from setuptools import setup
614
+
615
+ setup(
616
+ name="mydb-sqlglot-dialect",
617
+ entry_points={
618
+ "sqlglot.dialects": [
619
+ "mydb = my_package.dialect:MyDB",
620
+ ],
621
+ },
622
+ )
623
+ ```
624
+
625
+ The dialect will be automatically discovered and can be used like any built-in dialect:
626
+
627
+ ```python
628
+ from sqlglot import transpile
629
+ transpile("SELECT * FROM t", read="mydb", write="postgres")
630
+ ```
631
+
632
+ See the [Custom Dialects](#custom-dialects) section for implementation details.
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '28.4.1'
32
- __version_tuple__ = version_tuple = (28, 4, 1)
31
+ __version__ = version = '28.6.0'
32
+ __version_tuple__ = version_tuple = (28, 6, 0)
33
33
 
34
- __commit_id__ = commit_id = 'gcfc9346ba'
34
+ __commit_id__ = commit_id = 'g33b8a5d25'
@@ -51,6 +51,8 @@ JSON_EXTRACT_TYPE = t.Union[exp.JSONExtract, exp.JSONExtractScalar, exp.JSONExtr
51
51
 
52
52
  DQUOTES_ESCAPING_JSON_FUNCTIONS = ("JSON_QUERY", "JSON_VALUE", "JSON_QUERY_ARRAY")
53
53
 
54
+ MAKE_INTERVAL_KWARGS = ["year", "month", "day", "hour", "minute", "second"]
55
+
54
56
 
55
57
  def _derived_table_values_to_unnest(self: BigQuery.Generator, expression: exp.Values) -> str:
56
58
  if not expression.find_ancestor(exp.From, exp.Join):
@@ -389,7 +391,9 @@ class BigQuery(Dialect):
389
391
  EXCLUDES_PSEUDOCOLUMNS_FROM_STAR = True
390
392
  QUERY_RESULTS_ARE_STRUCTS = True
391
393
  JSON_EXTRACT_SCALAR_SCALAR_ONLY = True
394
+ LEAST_GREATEST_IGNORES_NULLS = False
392
395
  DEFAULT_NULL_TYPE = exp.DataType.Type.BIGINT
396
+ PRIORITIZE_NON_LITERAL_TYPES = True
393
397
 
394
398
  # https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#initcap
395
399
  INITCAP_DEFAULT_DELIMITER_CHARS = ' \t\n\r\f\v\\[\\](){}/|<>!?@"^#$&~_,.:;*%+\\-'
@@ -602,12 +606,6 @@ class BigQuery(Dialect):
602
606
  "EDIT_DISTANCE": _build_levenshtein,
603
607
  "FORMAT_DATE": _build_format_time(exp.TsOrDsToDate),
604
608
  "GENERATE_ARRAY": exp.GenerateSeries.from_arg_list,
605
- "GREATEST": lambda args: exp.Greatest(
606
- this=seq_get(args, 0), expressions=args[1:], null_if_any_null=True
607
- ),
608
- "LEAST": lambda args: exp.Least(
609
- this=seq_get(args, 0), expressions=args[1:], null_if_any_null=True
610
- ),
611
609
  "JSON_EXTRACT_SCALAR": _build_extract_json_with_default_path(exp.JSONExtractScalar),
612
610
  "JSON_EXTRACT_ARRAY": _build_extract_json_with_default_path(exp.JSONExtractArray),
613
611
  "JSON_EXTRACT_STRING_ARRAY": _build_extract_json_with_default_path(exp.JSONValueArray),
@@ -964,7 +962,7 @@ class BigQuery(Dialect):
964
962
  def _parse_make_interval(self) -> exp.MakeInterval:
965
963
  expr = exp.MakeInterval()
966
964
 
967
- for arg_key in expr.arg_types:
965
+ for arg_key in MAKE_INTERVAL_KWARGS:
968
966
  value = self._parse_lambda()
969
967
 
970
968
  if not value:
@@ -565,6 +565,8 @@ class ClickHouse(Dialect):
565
565
  "MEDIAN": lambda self: self._parse_quantile(),
566
566
  "COLUMNS": lambda self: self._parse_columns(),
567
567
  "TUPLE": lambda self: exp.Struct.from_arg_list(self._parse_function_args(alias=True)),
568
+ "AND": lambda self: exp.and_(*self._parse_function_args(alias=False)),
569
+ "OR": lambda self: exp.or_(*self._parse_function_args(alias=False)),
568
570
  }
569
571
 
570
572
  FUNCTION_PARSERS.pop("MATCH")
@@ -27,6 +27,8 @@ from sqlglot.tokens import Token, Tokenizer, TokenType
27
27
  from sqlglot.trie import new_trie
28
28
  from sqlglot.typing import EXPRESSION_METADATA
29
29
 
30
+ from importlib.metadata import entry_points
31
+
30
32
  DATE_ADD_OR_DIFF = t.Union[
31
33
  exp.DateAdd,
32
34
  exp.DateDiff,
@@ -66,6 +68,8 @@ UNESCAPED_SEQUENCES = {
66
68
  "\\\\": "\\",
67
69
  }
68
70
 
71
+ PLUGIN_GROUP_NAME = "sqlglot.dialects"
72
+
69
73
 
70
74
  class Dialects(str, Enum):
71
75
  """Dialects supported by SQLGLot."""
@@ -153,12 +157,54 @@ class _Dialect(type):
153
157
  if isinstance(key, Dialects):
154
158
  key = key.value
155
159
 
156
- # This import will lead to a new dialect being loaded, and hence, registered.
157
- # We check that the key is an actual sqlglot module to avoid blindly importing
158
- # files. Custom user dialects need to be imported at the top-level package, in
159
- # order for them to be registered as soon as possible.
160
+ # 1. Try standard sqlglot modules first
160
161
  if key in DIALECT_MODULE_NAMES:
162
+ module = importlib.import_module(f"sqlglot.dialects.{key}")
163
+ # If module was already imported, the class may not be in _classes
164
+ # Find and register the dialect class from the module
165
+ if key not in cls._classes:
166
+ for attr_name in dir(module):
167
+ attr = getattr(module, attr_name, None)
168
+ if (
169
+ isinstance(attr, type)
170
+ and issubclass(attr, Dialect)
171
+ and attr.__name__.lower() == key
172
+ ):
173
+ cls._classes[key] = attr
174
+ break
175
+ return
176
+
177
+ # 2. Try entry points (for plugins)
178
+ try:
179
+ all_eps = entry_points()
180
+ # Python 3.10+ has select() method, older versions use dict-like access
181
+ if hasattr(all_eps, "select"):
182
+ eps = all_eps.select(group=PLUGIN_GROUP_NAME, name=key)
183
+ else:
184
+ # For older Python versions, entry_points() returns a dict-like object
185
+ group_eps = all_eps.get(PLUGIN_GROUP_NAME, []) # type: ignore
186
+ eps = [ep for ep in group_eps if ep.name == key] # type: ignore
187
+
188
+ for entry_point in eps:
189
+ dialect_class = entry_point.load()
190
+ # Verify it's a Dialect subclass
191
+ # issubclass() returns False if not a subclass, TypeError only if not a class at all
192
+ if isinstance(dialect_class, type) and issubclass(dialect_class, Dialect):
193
+ # Register the dialect using the entry point name (key)
194
+ # The metaclass may have registered it by class name, but we need it by entry point name
195
+ if key not in cls._classes:
196
+ cls._classes[key] = dialect_class
197
+ return
198
+ except ImportError:
199
+ # entry_point.load() failed (bad plugin - module/class doesn't exist)
200
+ pass
201
+
202
+ # 3. Try direct import (for backward compatibility)
203
+ # This allows namespace packages or explicit imports to work
204
+ try:
161
205
  importlib.import_module(f"sqlglot.dialects.{key}")
206
+ except ImportError:
207
+ pass
162
208
 
163
209
  @classmethod
164
210
  def __getitem__(cls, key: str) -> t.Type[Dialect]:
@@ -741,6 +787,18 @@ class Dialect(metaclass=_Dialect):
741
787
  For example, in BigQuery the default type of the NULL value is INT64.
742
788
  """
743
789
 
790
+ LEAST_GREATEST_IGNORES_NULLS = True
791
+ """
792
+ Whether LEAST/GREATEST functions ignore NULL values, e.g:
793
+ - BigQuery, Snowflake, MySQL, Presto/Trino: LEAST(1, NULL, 2) -> NULL
794
+ - Spark, Postgres, DuckDB, TSQL: LEAST(1, NULL, 2) -> 1
795
+ """
796
+
797
+ PRIORITIZE_NON_LITERAL_TYPES = False
798
+ """
799
+ Whether to prioritize non-literal types over literals during type annotation.
800
+ """
801
+
744
802
  # --- Autofilled ---
745
803
 
746
804
  tokenizer_class = Tokenizer
@@ -935,7 +993,9 @@ class Dialect(metaclass=_Dialect):
935
993
 
936
994
  result = cls.get(dialect_name.strip())
937
995
  if not result:
938
- suggest_closest_match_and_fail("dialect", dialect_name, list(DIALECT_MODULE_NAMES))
996
+ # Include both built-in dialects and any loaded dialects for better error messages
997
+ all_dialects = set(DIALECT_MODULE_NAMES) | set(cls._classes.keys())
998
+ suggest_closest_match_and_fail("dialect", dialect_name, all_dialects)
939
999
 
940
1000
  assert result is not None
941
1001
  return result(**kwargs)
@@ -1300,6 +1360,59 @@ def var_map_sql(
1300
1360
  return self.func(map_func_name, *args)
1301
1361
 
1302
1362
 
1363
+ def months_between_sql(self: Generator, expression: exp.MonthsBetween) -> str:
1364
+ """
1365
+ Transpile MONTHS_BETWEEN to dialects that don't have native support.
1366
+
1367
+ Snowflake's MONTHS_BETWEEN returns whole months + fractional part where:
1368
+ - Fractional part = (DAY(date1) - DAY(date2)) / 31
1369
+ - Special case: If both dates are last day of month, fractional part = 0
1370
+
1371
+ Formula: DATEDIFF('month', date2, date1) + (DAY(date1) - DAY(date2)) / 31.0
1372
+ """
1373
+ date1 = expression.this
1374
+ date2 = expression.expression
1375
+
1376
+ # Cast to DATE to ensure consistent behavior
1377
+ date1_cast = exp.cast(date1, exp.DataType.Type.DATE, copy=False)
1378
+ date2_cast = exp.cast(date2, exp.DataType.Type.DATE, copy=False)
1379
+
1380
+ # Whole months: DATEDIFF('month', date2, date1)
1381
+ whole_months = exp.DateDiff(this=date1_cast, expression=date2_cast, unit=exp.var("month"))
1382
+
1383
+ # Day components
1384
+ day1 = exp.Day(this=date1_cast.copy())
1385
+ day2 = exp.Day(this=date2_cast.copy())
1386
+
1387
+ # Last day of month components
1388
+ last_day_of_month1 = exp.LastDay(this=date1_cast.copy())
1389
+ last_day_of_month2 = exp.LastDay(this=date2_cast.copy())
1390
+
1391
+ day_of_last_day1 = exp.Day(this=last_day_of_month1)
1392
+ day_of_last_day2 = exp.Day(this=last_day_of_month2)
1393
+
1394
+ # Check if both are last day of month
1395
+ last_day1 = exp.EQ(this=day1.copy(), expression=day_of_last_day1)
1396
+ last_day2 = exp.EQ(this=day2.copy(), expression=day_of_last_day2)
1397
+ both_last_day = exp.And(this=last_day1, expression=last_day2)
1398
+
1399
+ # Fractional part: (DAY(date1) - DAY(date2)) / 31.0
1400
+ fractional = exp.Div(
1401
+ this=exp.Paren(this=exp.Sub(this=day1.copy(), expression=day2.copy())),
1402
+ expression=exp.Literal.number("31.0"),
1403
+ )
1404
+
1405
+ # If both are last day of month, fractional = 0, else calculate fractional
1406
+ fractional_with_check = exp.If(
1407
+ this=both_last_day, true=exp.Literal.number("0"), false=fractional
1408
+ )
1409
+
1410
+ # Final result: whole_months + fractional
1411
+ result = exp.Add(this=whole_months, expression=fractional_with_check)
1412
+
1413
+ return self.sql(result)
1414
+
1415
+
1303
1416
  def build_formatted_time(
1304
1417
  exp_class: t.Type[E], dialect: str, default: t.Optional[bool | str] = None
1305
1418
  ) -> t.Callable[[t.List], E]:
@@ -2154,3 +2267,24 @@ def regexp_replace_global_modifier(expression: exp.RegexpReplace) -> exp.Express
2154
2267
  modifiers = exp.Literal.string(value + "g")
2155
2268
 
2156
2269
  return modifiers
2270
+
2271
+
2272
+ def getbit_sql(self: Generator, expression: exp.Getbit) -> str:
2273
+ """
2274
+ Generates SQL for Getbit according to DuckDB and Postgres, transpiling it if either:
2275
+
2276
+ 1. The zero index corresponds to the least-significant bit
2277
+ 2. The input type is an integer value
2278
+ """
2279
+ value = expression.this
2280
+ position = expression.expression
2281
+
2282
+ if not expression.args.get("zero_is_msb") and expression.is_type(
2283
+ *exp.DataType.SIGNED_INTEGER_TYPES, *exp.DataType.UNSIGNED_INTEGER_TYPES
2284
+ ):
2285
+ # Use bitwise operations: (value >> position) & 1
2286
+ shifted = exp.BitwiseRightShift(this=value, expression=position)
2287
+ masked = exp.BitwiseAnd(this=shifted, expression=exp.Literal.number(1))
2288
+ return self.sql(masked)
2289
+
2290
+ return self.func("GET_BIT", value, position)
@@ -178,6 +178,7 @@ class Doris(MySQL):
178
178
  VARCHAR_REQUIRES_SIZE = False
179
179
  WITH_PROPERTIES_PREFIX = "PROPERTIES"
180
180
  RENAME_TABLE_WITH_DB = False
181
+ UPDATE_STATEMENT_SUPPORTS_FROM = True
181
182
 
182
183
  TYPE_MAPPING = {
183
184
  **MySQL.Generator.TYPE_MAPPING,
@@ -17,4 +17,5 @@ class Druid(Dialect):
17
17
  **generator.Generator.TRANSFORMS,
18
18
  exp.CurrentTimestamp: lambda *_: "CURRENT_TIMESTAMP",
19
19
  exp.Mod: rename_func("MOD"),
20
+ exp.Array: lambda self, e: f"ARRAY[{self.expressions(e)}]",
20
21
  }