sqlglot 27.6.0__tar.gz → 27.7.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 (226) hide show
  1. {sqlglot-27.6.0 → sqlglot-27.7.0}/CHANGELOG.md +25 -0
  2. {sqlglot-27.6.0 → sqlglot-27.7.0}/PKG-INFO +1 -1
  3. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/_version.py +2 -2
  4. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/bigquery.py +40 -5
  5. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/clickhouse.py +27 -8
  6. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/dialect.py +10 -2
  7. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/doris.py +43 -2
  8. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/dremio.py +24 -3
  9. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/duckdb.py +32 -3
  10. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/exasol.py +25 -29
  11. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/singlestore.py +28 -1
  12. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/snowflake.py +1 -1
  13. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/spark.py +1 -0
  14. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/teradata.py +58 -0
  15. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/expressions.py +58 -1
  16. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/generator.py +21 -2
  17. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/annotate_types.py +4 -1
  18. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/merge_subqueries.py +4 -0
  19. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/qualify_tables.py +0 -8
  20. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/parser.py +29 -5
  21. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot.egg-info/PKG-INFO +1 -1
  22. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_bigquery.py +21 -23
  23. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_clickhouse.py +8 -0
  24. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_dialect.py +128 -0
  25. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_doris.py +94 -1
  26. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_dremio.py +7 -6
  27. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_duckdb.py +16 -0
  28. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_exasol.py +27 -22
  29. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_presto.py +0 -1
  30. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_singlestore.py +32 -0
  31. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_snowflake.py +40 -2
  32. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_teradata.py +35 -0
  33. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_tsql.py +7 -0
  34. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/annotate_functions.sql +94 -0
  35. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/merge_subqueries.sql +9 -2
  36. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/qualify_columns.sql +15 -2
  37. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_optimizer.py +2 -1
  38. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_parser.py +1 -0
  39. {sqlglot-27.6.0 → sqlglot-27.7.0}/.gitignore +0 -0
  40. {sqlglot-27.6.0 → sqlglot-27.7.0}/.gitpod.yml +0 -0
  41. {sqlglot-27.6.0 → sqlglot-27.7.0}/.pre-commit-config.yaml +0 -0
  42. {sqlglot-27.6.0 → sqlglot-27.7.0}/CONTRIBUTING.md +0 -0
  43. {sqlglot-27.6.0 → sqlglot-27.7.0}/LICENSE +0 -0
  44. {sqlglot-27.6.0 → sqlglot-27.7.0}/MANIFEST.in +0 -0
  45. {sqlglot-27.6.0 → sqlglot-27.7.0}/Makefile +0 -0
  46. {sqlglot-27.6.0 → sqlglot-27.7.0}/README.md +0 -0
  47. {sqlglot-27.6.0 → sqlglot-27.7.0}/pyproject.toml +0 -0
  48. {sqlglot-27.6.0 → sqlglot-27.7.0}/setup.cfg +0 -0
  49. {sqlglot-27.6.0 → sqlglot-27.7.0}/setup.py +0 -0
  50. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/__init__.py +0 -0
  51. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/__main__.py +0 -0
  52. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/_typing.py +0 -0
  53. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/__init__.py +0 -0
  54. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/athena.py +0 -0
  55. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/databricks.py +0 -0
  56. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/drill.py +0 -0
  57. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/druid.py +0 -0
  58. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/dune.py +0 -0
  59. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/fabric.py +0 -0
  60. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/hive.py +0 -0
  61. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/materialize.py +0 -0
  62. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/mysql.py +0 -0
  63. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/oracle.py +0 -0
  64. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/postgres.py +0 -0
  65. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/presto.py +0 -0
  66. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/prql.py +0 -0
  67. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/redshift.py +0 -0
  68. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/risingwave.py +0 -0
  69. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/spark2.py +0 -0
  70. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/sqlite.py +0 -0
  71. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/starrocks.py +0 -0
  72. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/tableau.py +0 -0
  73. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/trino.py +0 -0
  74. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/dialects/tsql.py +0 -0
  75. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/diff.py +0 -0
  76. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/errors.py +0 -0
  77. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/executor/__init__.py +0 -0
  78. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/executor/context.py +0 -0
  79. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/executor/env.py +0 -0
  80. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/executor/python.py +0 -0
  81. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/executor/table.py +0 -0
  82. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/helper.py +0 -0
  83. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/jsonpath.py +0 -0
  84. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/lineage.py +0 -0
  85. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/__init__.py +0 -0
  86. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/canonicalize.py +0 -0
  87. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/eliminate_ctes.py +0 -0
  88. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/eliminate_joins.py +0 -0
  89. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/eliminate_subqueries.py +0 -0
  90. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
  91. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/normalize.py +0 -0
  92. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
  93. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/optimize_joins.py +0 -0
  94. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/optimizer.py +0 -0
  95. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/pushdown_predicates.py +0 -0
  96. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/pushdown_projections.py +0 -0
  97. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/qualify.py +0 -0
  98. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/qualify_columns.py +0 -0
  99. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/scope.py +0 -0
  100. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/simplify.py +0 -0
  101. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/optimizer/unnest_subqueries.py +0 -0
  102. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/planner.py +0 -0
  103. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/py.typed +0 -0
  104. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/schema.py +0 -0
  105. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/serde.py +0 -0
  106. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/time.py +0 -0
  107. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/tokens.py +0 -0
  108. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/transforms.py +0 -0
  109. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot/trie.py +0 -0
  110. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot.egg-info/SOURCES.txt +0 -0
  111. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot.egg-info/dependency_links.txt +0 -0
  112. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot.egg-info/requires.txt +0 -0
  113. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot.egg-info/top_level.txt +0 -0
  114. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglot.png +0 -0
  115. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/Cargo.lock +0 -0
  116. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/Cargo.toml +0 -0
  117. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/benches/dialect_settings.json +0 -0
  118. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/benches/long.rs +0 -0
  119. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/benches/token_type_settings.json +0 -0
  120. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/benches/tokenizer_dialect_settings.json +0 -0
  121. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/benches/tokenizer_settings.json +0 -0
  122. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/pyproject.toml +0 -0
  123. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/src/lib.rs +0 -0
  124. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/src/settings.rs +0 -0
  125. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/src/token.rs +0 -0
  126. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/src/tokenizer.rs +0 -0
  127. {sqlglot-27.6.0 → sqlglot-27.7.0}/sqlglotrs/src/trie.rs +0 -0
  128. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/__init__.py +0 -0
  129. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/__init__.py +0 -0
  130. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_athena.py +0 -0
  131. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_databricks.py +0 -0
  132. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_drill.py +0 -0
  133. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_druid.py +0 -0
  134. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_dune.py +0 -0
  135. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_fabric.py +0 -0
  136. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_hive.py +0 -0
  137. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_materialize.py +0 -0
  138. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_mysql.py +0 -0
  139. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_oracle.py +0 -0
  140. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_pipe_syntax.py +0 -0
  141. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_postgres.py +0 -0
  142. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_prql.py +0 -0
  143. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_redshift.py +0 -0
  144. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_risingwave.py +0 -0
  145. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_spark.py +0 -0
  146. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_sqlite.py +0 -0
  147. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_starrocks.py +0 -0
  148. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_tableau.py +0 -0
  149. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/dialects/test_trino.py +0 -0
  150. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/identity.sql +0 -0
  151. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/jsonpath/LICENSE +0 -0
  152. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/jsonpath/cts.json +0 -0
  153. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/annotate_types.sql +0 -0
  154. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/canonicalize.sql +0 -0
  155. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/eliminate_ctes.sql +0 -0
  156. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/eliminate_joins.sql +0 -0
  157. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/eliminate_subqueries.sql +0 -0
  158. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/isolate_table_selects.sql +0 -0
  159. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/normalize.sql +0 -0
  160. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/normalize_identifiers.sql +0 -0
  161. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/optimize_joins.sql +0 -0
  162. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/optimizer.sql +0 -0
  163. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/pushdown_cte_alias_columns.sql +0 -0
  164. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/pushdown_predicates.sql +0 -0
  165. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/pushdown_projections.sql +0 -0
  166. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/qualify_columns__invalid.sql +0 -0
  167. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/qualify_columns__with_invisible.sql +0 -0
  168. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/qualify_columns_ddl.sql +0 -0
  169. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/qualify_tables.sql +0 -0
  170. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/quote_identifiers.sql +0 -0
  171. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/simplify.sql +0 -0
  172. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/call_center.csv.gz +0 -0
  173. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/catalog_page.csv.gz +0 -0
  174. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/catalog_returns.csv.gz +0 -0
  175. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/catalog_sales.csv.gz +0 -0
  176. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/customer.csv.gz +0 -0
  177. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/customer_address.csv.gz +0 -0
  178. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/customer_demographics.csv.gz +0 -0
  179. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/date_dim.csv.gz +0 -0
  180. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/household_demographics.csv.gz +0 -0
  181. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/income_band.csv.gz +0 -0
  182. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/inventory.csv.gz +0 -0
  183. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/item.csv.gz +0 -0
  184. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/promotion.csv.gz +0 -0
  185. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/reason.csv.gz +0 -0
  186. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/ship_mode.csv.gz +0 -0
  187. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/store.csv.gz +0 -0
  188. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/store_returns.csv.gz +0 -0
  189. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/store_sales.csv.gz +0 -0
  190. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/time_dim.csv.gz +0 -0
  191. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/tpc-ds.sql +0 -0
  192. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/warehouse.csv.gz +0 -0
  193. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/web_page.csv.gz +0 -0
  194. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/web_returns.csv.gz +0 -0
  195. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/web_sales.csv.gz +0 -0
  196. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-ds/web_site.csv.gz +0 -0
  197. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-h/customer.csv.gz +0 -0
  198. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-h/lineitem.csv.gz +0 -0
  199. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-h/nation.csv.gz +0 -0
  200. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-h/orders.csv.gz +0 -0
  201. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-h/part.csv.gz +0 -0
  202. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-h/partsupp.csv.gz +0 -0
  203. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-h/region.csv.gz +0 -0
  204. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-h/supplier.csv.gz +0 -0
  205. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/tpc-h/tpc-h.sql +0 -0
  206. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/optimizer/unnest_subqueries.sql +0 -0
  207. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/partial.sql +0 -0
  208. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/fixtures/pretty.sql +0 -0
  209. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/gen_fixtures.py +0 -0
  210. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/helpers.py +0 -0
  211. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_build.py +0 -0
  212. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_dialect_imports.py +0 -0
  213. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_diff.py +0 -0
  214. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_docs.py +0 -0
  215. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_executor.py +0 -0
  216. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_expressions.py +0 -0
  217. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_generator.py +0 -0
  218. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_helper.py +0 -0
  219. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_jsonpath.py +0 -0
  220. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_lineage.py +0 -0
  221. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_schema.py +0 -0
  222. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_serde.py +0 -0
  223. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_time.py +0 -0
  224. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_tokens.py +0 -0
  225. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_transforms.py +0 -0
  226. {sqlglot-27.6.0 → sqlglot-27.7.0}/tests/test_transpile.py +0 -0
@@ -1,6 +1,30 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ## [v27.6.0] - 2025-08-01
5
+ ### :boom: BREAKING CHANGES
6
+ - due to [`6b691b3`](https://github.com/tobymao/sqlglot/commit/6b691b33c3528c0377bd8822a3df90de869c6cb1) - Parse and transpile GET(...) extract function *(PR [#5500](https://github.com/tobymao/sqlglot/pull/5500) by [@VaggelisD](https://github.com/VaggelisD))*:
7
+
8
+ Parse and transpile GET(...) extract function (#5500)
9
+
10
+ - due to [`964a275`](https://github.com/tobymao/sqlglot/commit/964a275b42314380de3b301ada9f9756602729f7) - Make `UNION` column qualification recursive *(PR [#5508](https://github.com/tobymao/sqlglot/pull/5508) by [@VaggelisD](https://github.com/VaggelisD))*:
11
+
12
+ Make `UNION` column qualification recursive (#5508)
13
+
14
+
15
+ ### :sparkles: New Features
16
+ - [`6b691b3`](https://github.com/tobymao/sqlglot/commit/6b691b33c3528c0377bd8822a3df90de869c6cb1) - **snowflake**: Parse and transpile GET(...) extract function *(PR [#5500](https://github.com/tobymao/sqlglot/pull/5500) by [@VaggelisD](https://github.com/VaggelisD))*
17
+ - :arrow_lower_right: *addresses issue [#5495](https://github.com/tobymao/sqlglot/issues/5495) opened by [@kyle-cheung](https://github.com/kyle-cheung)*
18
+ - [`a2a2f0f`](https://github.com/tobymao/sqlglot/commit/a2a2f0fe910228651c5c39beebcc02172a0b7e94) - **exasol**: Add support for IF, NULLIFZERO, and ZEROIFNULL functions *(PR [#5502](https://github.com/tobymao/sqlglot/pull/5502) by [@nnamdi16](https://github.com/nnamdi16))*
19
+ - [`2d8ce58`](https://github.com/tobymao/sqlglot/commit/2d8ce587c75f21b188ec4c201936eedac3b051e8) - **singlestore**: Added cast operator *(PR [#5504](https://github.com/tobymao/sqlglot/pull/5504) by [@AdalbertMemSQL](https://github.com/AdalbertMemSQL))*
20
+ - [`6256348`](https://github.com/tobymao/sqlglot/commit/6256348a28b72ae9052d4244736846af209410b0) - **exasol**: add support for ADD_DAYS function in exasol dialect *(PR [#5507](https://github.com/tobymao/sqlglot/pull/5507) by [@nnamdi16](https://github.com/nnamdi16))*
21
+ - [`2f40fc5`](https://github.com/tobymao/sqlglot/commit/2f40fc578a840c9276a4c3b91351fb8d95c837fc) - add more pseudocols to bq which are not expanded by star *(PR [#5509](https://github.com/tobymao/sqlglot/pull/5509) by [@z3z1ma](https://github.com/z3z1ma))*
22
+
23
+ ### :bug: Bug Fixes
24
+ - [`3b52061`](https://github.com/tobymao/sqlglot/commit/3b520611c5a894ddea935d13aadd27c791a8a755) - **exasol**: fix TokenType.TEXT mapping in exasol dialect *(PR [#5506](https://github.com/tobymao/sqlglot/pull/5506) by [@nnamdi16](https://github.com/nnamdi16))*
25
+ - [`964a275`](https://github.com/tobymao/sqlglot/commit/964a275b42314380de3b301ada9f9756602729f7) - Make `UNION` column qualification recursive *(PR [#5508](https://github.com/tobymao/sqlglot/pull/5508) by [@VaggelisD](https://github.com/VaggelisD))*
26
+
27
+
4
28
  ## [v27.5.1] - 2025-07-30
5
29
  ### :bug: Bug Fixes
6
30
  - [`caf71d6`](https://github.com/tobymao/sqlglot/commit/caf71d687c0048d2346fddaee58b519e4f2e7945) - `between` builder should not set `symmetric` by default *(commit by [@georgesittas](https://github.com/georgesittas))*
@@ -6379,3 +6403,4 @@ Changelog
6379
6403
  [v27.4.1]: https://github.com/tobymao/sqlglot/compare/v27.4.0...v27.4.1
6380
6404
  [v27.5.0]: https://github.com/tobymao/sqlglot/compare/v27.4.1...v27.5.0
6381
6405
  [v27.5.1]: https://github.com/tobymao/sqlglot/compare/v27.5.0...v27.5.1
6406
+ [v27.6.0]: https://github.com/tobymao/sqlglot/compare/v27.5.1...v27.6.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 27.6.0
3
+ Version: 27.7.0
4
4
  Summary: An easily customizable SQL parser and transpiler
5
5
  Author-email: Toby Mao <toby.mao@gmail.com>
6
6
  Project-URL: Homepage, https://sqlglot.com/
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '27.6.0'
21
- __version_tuple__ = version_tuple = (27, 6, 0)
20
+ __version__ = version = '27.7.0'
21
+ __version_tuple__ = version_tuple = (27, 7, 0)
@@ -481,10 +481,20 @@ class BigQuery(Dialect):
481
481
  exp.BitwiseOrAgg: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BIGINT),
482
482
  exp.BitwiseXorAgg: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BIGINT),
483
483
  exp.BitwiseCountAgg: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BIGINT),
484
+ exp.ByteLength: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BIGINT),
485
+ exp.ByteString: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BINARY),
486
+ exp.CodePointsToString: lambda self, e: self._annotate_with_type(
487
+ e, exp.DataType.Type.VARCHAR
488
+ ),
484
489
  exp.Concat: _annotate_concat,
485
490
  exp.Corr: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.DOUBLE),
486
491
  exp.CovarPop: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.DOUBLE),
487
492
  exp.CovarSamp: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.DOUBLE),
493
+ exp.DateFromUnixDate: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.DATE),
494
+ exp.DateTrunc: lambda self, e: self._annotate_by_args(e, "this"),
495
+ exp.GenerateTimestampArray: lambda self, e: self._annotate_with_type(
496
+ e, exp.DataType.build("ARRAY<TIMESTAMP>", dialect="bigquery")
497
+ ),
488
498
  exp.JSONArray: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.JSON),
489
499
  exp.JSONExtractScalar: lambda self, e: self._annotate_with_type(
490
500
  e, exp.DataType.Type.VARCHAR
@@ -494,6 +504,9 @@ class BigQuery(Dialect):
494
504
  ),
495
505
  exp.JSONType: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.VARCHAR),
496
506
  exp.Lag: lambda self, e: self._annotate_by_args(e, "this", "default"),
507
+ exp.ParseTime: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.TIME),
508
+ exp.ParseDatetime: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.DATETIME),
509
+ exp.Reverse: lambda self, e: self._annotate_by_args(e, "this"),
497
510
  exp.SHA: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BINARY),
498
511
  exp.SHA2: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BINARY),
499
512
  exp.Sign: lambda self, e: self._annotate_by_args(e, "this"),
@@ -501,6 +514,10 @@ class BigQuery(Dialect):
501
514
  exp.TimestampFromParts: lambda self, e: self._annotate_with_type(
502
515
  e, exp.DataType.Type.DATETIME
503
516
  ),
517
+ exp.TimestampTrunc: lambda self, e: self._annotate_by_args(e, "this"),
518
+ exp.TimeFromParts: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.TIME),
519
+ exp.TsOrDsToTime: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.TIME),
520
+ exp.TimeTrunc: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.TIME),
504
521
  exp.Unicode: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.BIGINT),
505
522
  }
506
523
 
@@ -621,7 +638,13 @@ class BigQuery(Dialect):
621
638
  "PARSE_DATE": lambda args: build_formatted_time(exp.StrToDate, "bigquery")(
622
639
  [seq_get(args, 1), seq_get(args, 0)]
623
640
  ),
641
+ "PARSE_TIME": lambda args: build_formatted_time(exp.ParseTime, "bigquery")(
642
+ [seq_get(args, 1), seq_get(args, 0)]
643
+ ),
624
644
  "PARSE_TIMESTAMP": _build_parse_timestamp,
645
+ "PARSE_DATETIME": lambda args: build_formatted_time(exp.ParseDatetime, "bigquery")(
646
+ [seq_get(args, 1), seq_get(args, 0)]
647
+ ),
625
648
  "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list,
626
649
  "REGEXP_EXTRACT": _build_regexp_extract(exp.RegexpExtract),
627
650
  "REGEXP_SUBSTR": _build_regexp_extract(exp.RegexpExtract),
@@ -652,6 +675,8 @@ class BigQuery(Dialect):
652
675
  "TO_JSON_STRING": exp.JSONFormat.from_arg_list,
653
676
  "FORMAT_DATETIME": _build_format_time(exp.TsOrDsToDatetime),
654
677
  "FORMAT_TIMESTAMP": _build_format_time(exp.TsOrDsToTimestamp),
678
+ "FORMAT_TIME": _build_format_time(exp.TsOrDsToTime),
679
+ "WEEK": lambda args: exp.WeekStart(this=exp.var(seq_get(args, 0))),
655
680
  }
656
681
 
657
682
  FUNCTION_PARSERS = {
@@ -994,6 +1019,13 @@ class BigQuery(Dialect):
994
1019
  EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False
995
1020
  SUPPORTS_UNIX_SECONDS = True
996
1021
 
1022
+ TS_OR_DS_TYPES = (
1023
+ exp.TsOrDsToDatetime,
1024
+ exp.TsOrDsToTimestamp,
1025
+ exp.TsOrDsToTime,
1026
+ exp.TsOrDsToDate,
1027
+ )
1028
+
997
1029
  TRANSFORMS = {
998
1030
  **generator.Generator.TRANSFORMS,
999
1031
  exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"),
@@ -1022,6 +1054,7 @@ class BigQuery(Dialect):
1022
1054
  exp.DateSub: date_add_interval_sql("DATE", "SUB"),
1023
1055
  exp.DatetimeAdd: date_add_interval_sql("DATETIME", "ADD"),
1024
1056
  exp.DatetimeSub: date_add_interval_sql("DATETIME", "SUB"),
1057
+ exp.DateFromUnixDate: rename_func("DATE_FROM_UNIX_DATE"),
1025
1058
  exp.FromTimeZone: lambda self, e: self.func(
1026
1059
  "DATETIME", self.func("TIMESTAMP", e.this, e.args.get("zone")), "'UTC'"
1027
1060
  ),
@@ -1059,6 +1092,10 @@ class BigQuery(Dialect):
1059
1092
  exp.RegexpLike: rename_func("REGEXP_CONTAINS"),
1060
1093
  exp.ReturnsProperty: _returnsproperty_sql,
1061
1094
  exp.Rollback: lambda *_: "ROLLBACK TRANSACTION",
1095
+ exp.ParseTime: lambda self, e: self.func("PARSE_TIME", self.format_time(e), e.this),
1096
+ exp.ParseDatetime: lambda self, e: self.func(
1097
+ "PARSE_DATETIME", self.format_time(e), e.this
1098
+ ),
1062
1099
  exp.Select: transforms.preprocess(
1063
1100
  [
1064
1101
  transforms.explode_projection_to_unnest(),
@@ -1297,14 +1334,12 @@ class BigQuery(Dialect):
1297
1334
  func_name = "FORMAT_DATETIME"
1298
1335
  elif isinstance(this, exp.TsOrDsToTimestamp):
1299
1336
  func_name = "FORMAT_TIMESTAMP"
1337
+ elif isinstance(this, exp.TsOrDsToTime):
1338
+ func_name = "FORMAT_TIME"
1300
1339
  else:
1301
1340
  func_name = "FORMAT_DATE"
1302
1341
 
1303
- time_expr = (
1304
- this
1305
- if isinstance(this, (exp.TsOrDsToDatetime, exp.TsOrDsToTimestamp, exp.TsOrDsToDate))
1306
- else expression
1307
- )
1342
+ time_expr = this if isinstance(this, self.TS_OR_DS_TYPES) else expression
1308
1343
  return self.func(
1309
1344
  func_name, self.format_time(expression), time_expr.this, expression.args.get("zone")
1310
1345
  )
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
  import typing as t
3
3
  import datetime
4
4
  from sqlglot import exp, generator, parser, tokens
5
+ from sqlglot._typing import E
5
6
  from sqlglot.dialects.dialect import (
6
7
  Dialect,
7
8
  NormalizationStrategy,
@@ -31,14 +32,19 @@ from sqlglot.generator import unsupported_args
31
32
  DATEΤΙΜΕ_DELTA = t.Union[exp.DateAdd, exp.DateDiff, exp.DateSub, exp.TimestampSub, exp.TimestampAdd]
32
33
 
33
34
 
34
- def _build_date_format(args: t.List) -> exp.TimeToStr:
35
- expr = build_formatted_time(exp.TimeToStr, "clickhouse")(args)
35
+ def _build_datetime_format(
36
+ expr_type: t.Type[E],
37
+ ) -> t.Callable[[t.List], E]:
38
+ def _builder(args: t.List) -> E:
39
+ expr = build_formatted_time(expr_type, "clickhouse")(args)
36
40
 
37
- timezone = seq_get(args, 2)
38
- if timezone:
39
- expr.set("zone", timezone)
41
+ timezone = seq_get(args, 2)
42
+ if timezone:
43
+ expr.set("zone", timezone)
40
44
 
41
- return expr
45
+ return expr
46
+
47
+ return _builder
42
48
 
43
49
 
44
50
  def _unix_to_time_sql(self: ClickHouse.Generator, expression: exp.UnixToTime) -> str:
@@ -310,16 +316,17 @@ class ClickHouse(Dialect):
310
316
  "DATEADD": build_date_delta(exp.DateAdd, default_unit=None),
311
317
  "DATE_DIFF": build_date_delta(exp.DateDiff, default_unit=None, supports_timezone=True),
312
318
  "DATEDIFF": build_date_delta(exp.DateDiff, default_unit=None, supports_timezone=True),
313
- "DATE_FORMAT": _build_date_format,
319
+ "DATE_FORMAT": _build_datetime_format(exp.TimeToStr),
314
320
  "DATE_SUB": build_date_delta(exp.DateSub, default_unit=None),
315
321
  "DATESUB": build_date_delta(exp.DateSub, default_unit=None),
316
- "FORMATDATETIME": _build_date_format,
322
+ "FORMATDATETIME": _build_datetime_format(exp.TimeToStr),
317
323
  "JSONEXTRACTSTRING": build_json_extract_path(
318
324
  exp.JSONExtractScalar, zero_based_indexing=False
319
325
  ),
320
326
  "LENGTH": lambda args: exp.Length(this=seq_get(args, 0), binary=True),
321
327
  "MAP": parser.build_var_map,
322
328
  "MATCH": exp.RegexpLike.from_arg_list,
329
+ "PARSEDATETIME": _build_datetime_format(exp.ParseDatetime),
323
330
  "RANDCANONICAL": exp.Rand.from_arg_list,
324
331
  "STR_TO_DATE": _build_str_to_date,
325
332
  "TUPLE": exp.Struct.from_arg_list,
@@ -1141,6 +1148,7 @@ class ClickHouse(Dialect):
1141
1148
  exp.Levenshtein: unsupported_args("ins_cost", "del_cost", "sub_cost", "max_dist")(
1142
1149
  rename_func("editDistance")
1143
1150
  ),
1151
+ exp.ParseDatetime: rename_func("parseDateTime"),
1144
1152
  }
1145
1153
 
1146
1154
  PROPERTIES_LOCATION = {
@@ -1177,6 +1185,17 @@ class ClickHouse(Dialect):
1177
1185
  exp.DataType.Type.MULTIPOLYGON,
1178
1186
  }
1179
1187
 
1188
+ def offset_sql(self, expression: exp.Offset) -> str:
1189
+ offset = super().offset_sql(expression)
1190
+
1191
+ # OFFSET ... FETCH syntax requires a "ROW" or "ROWS" keyword
1192
+ # https://clickhouse.com/docs/sql-reference/statements/select/offset
1193
+ parent = expression.parent
1194
+ if isinstance(parent, exp.Select) and isinstance(parent.args.get("limit"), exp.Fetch):
1195
+ offset = f"{offset} ROWS"
1196
+
1197
+ return offset
1198
+
1180
1199
  def strtodate_sql(self, expression: exp.StrToDate) -> str:
1181
1200
  strtodate_sql = self.function_fallback_sql(expression)
1182
1201
 
@@ -654,6 +654,8 @@ class Dialect(metaclass=_Dialect):
654
654
  exp.Length,
655
655
  exp.UnixDate,
656
656
  exp.UnixSeconds,
657
+ exp.UnixMicros,
658
+ exp.UnixMillis,
657
659
  },
658
660
  exp.DataType.Type.BINARY: {
659
661
  exp.FromBase64,
@@ -674,6 +676,7 @@ class Dialect(metaclass=_Dialect):
674
676
  exp.DateFromParts,
675
677
  exp.DateStrToDate,
676
678
  exp.DiToDate,
679
+ exp.LastDay,
677
680
  exp.StrToDate,
678
681
  exp.TimeStrToDate,
679
682
  exp.TsOrDsToDate,
@@ -718,6 +721,9 @@ class Dialect(metaclass=_Dialect):
718
721
  },
719
722
  exp.DataType.Type.INTERVAL: {
720
723
  exp.Interval,
724
+ exp.JustifyDays,
725
+ exp.JustifyHours,
726
+ exp.JustifyInterval,
721
727
  exp.MakeInterval,
722
728
  },
723
729
  exp.DataType.Type.JSON: {
@@ -1650,9 +1656,11 @@ def unit_to_str(expression: exp.Expression, default: str = "DAY") -> t.Optional[
1650
1656
  def unit_to_var(expression: exp.Expression, default: str = "DAY") -> t.Optional[exp.Expression]:
1651
1657
  unit = expression.args.get("unit")
1652
1658
 
1653
- if isinstance(unit, (exp.Var, exp.Placeholder)):
1659
+ if isinstance(unit, (exp.Var, exp.Placeholder, exp.WeekStart)):
1654
1660
  return unit
1655
- return exp.Var(this=default) if default else None
1661
+
1662
+ value = unit.name if unit else default
1663
+ return exp.Var(this=value) if value else None
1656
1664
 
1657
1665
 
1658
1666
  @t.overload
@@ -1,15 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import typing as t
4
+
3
5
  from sqlglot import exp
4
6
  from sqlglot.dialects.dialect import (
5
7
  approx_count_distinct_sql,
6
- build_timestamp_trunc,
7
8
  property_sql,
8
9
  rename_func,
9
10
  time_format,
10
11
  unit_to_str,
11
12
  )
12
13
  from sqlglot.dialects.mysql import MySQL
14
+ from sqlglot.helper import seq_get
13
15
  from sqlglot.tokens import TokenType
14
16
 
15
17
 
@@ -22,6 +24,22 @@ def _lag_lead_sql(self, expression: exp.Lag | exp.Lead) -> str:
22
24
  )
23
25
 
24
26
 
27
+ # Accept both DATE_TRUNC(datetime, unit) and DATE_TRUNC(unit, datetime)
28
+ def _build_date_trunc(args: t.List[exp.Expression]) -> exp.Expression:
29
+ a0, a1 = seq_get(args, 0), seq_get(args, 1)
30
+
31
+ def _is_unit_like(e: exp.Expression | None) -> bool:
32
+ if not (isinstance(e, exp.Literal) and e.is_string):
33
+ return False
34
+ text = e.this
35
+ return not any(ch.isdigit() for ch in text)
36
+
37
+ # Determine which argument is the unit
38
+ unit, this = (a0, a1) if _is_unit_like(a0) else (a1, a0)
39
+
40
+ return exp.TimestampTrunc(this=this, unit=unit)
41
+
42
+
25
43
  class Doris(MySQL):
26
44
  DATE_FORMAT = "'yyyy-MM-dd'"
27
45
  DATEINT_FORMAT = "'yyyyMMdd'"
@@ -31,7 +49,7 @@ class Doris(MySQL):
31
49
  FUNCTIONS = {
32
50
  **MySQL.Parser.FUNCTIONS,
33
51
  "COLLECT_SET": exp.ArrayUniqueAgg.from_arg_list,
34
- "DATE_TRUNC": build_timestamp_trunc,
52
+ "DATE_TRUNC": _build_date_trunc,
35
53
  "MONTHS_ADD": exp.AddMonths.from_arg_list,
36
54
  "REGEXP": exp.RegexpLike.from_arg_list,
37
55
  "TO_DATE": exp.TsOrDsToDate.from_arg_list,
@@ -40,6 +58,9 @@ class Doris(MySQL):
40
58
  FUNCTION_PARSERS = MySQL.Parser.FUNCTION_PARSERS.copy()
41
59
  FUNCTION_PARSERS.pop("GROUP_CONCAT")
42
60
 
61
+ NO_PAREN_FUNCTIONS = MySQL.Parser.NO_PAREN_FUNCTIONS.copy()
62
+ NO_PAREN_FUNCTIONS.pop(TokenType.CURRENT_DATE)
63
+
43
64
  PROPERTY_PARSERS = {
44
65
  **MySQL.Parser.PROPERTY_PARSERS,
45
66
  "PROPERTIES": lambda self: self._parse_wrapped_properties(),
@@ -111,6 +132,7 @@ class Doris(MySQL):
111
132
  LAST_DAY_SUPPORTS_DATE_PART = False
112
133
  VARCHAR_REQUIRES_SIZE = False
113
134
  WITH_PROPERTIES_PREFIX = "PROPERTIES"
135
+ RENAME_TABLE_WITH_DB = False
114
136
 
115
137
  TYPE_MAPPING = {
116
138
  **MySQL.Generator.TYPE_MAPPING,
@@ -123,6 +145,7 @@ class Doris(MySQL):
123
145
  **MySQL.Generator.PROPERTIES_LOCATION,
124
146
  exp.UniqueKeyProperty: exp.Properties.Location.POST_SCHEMA,
125
147
  exp.PartitionByRangeProperty: exp.Properties.Location.POST_SCHEMA,
148
+ exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
126
149
  }
127
150
 
128
151
  CAST_MAPPING = {}
@@ -137,6 +160,7 @@ class Doris(MySQL):
137
160
  exp.ArrayAgg: rename_func("COLLECT_LIST"),
138
161
  exp.ArrayToString: rename_func("ARRAY_JOIN"),
139
162
  exp.ArrayUniqueAgg: rename_func("COLLECT_SET"),
163
+ exp.CurrentDate: lambda self, _: self.func("CURRENT_DATE"),
140
164
  exp.CurrentTimestamp: lambda self, _: self.func("NOW"),
141
165
  exp.DateTrunc: lambda self, e: self.func("DATE_TRUNC", e.this, unit_to_str(e)),
142
166
  exp.GroupConcat: lambda self, e: self.func(
@@ -683,3 +707,20 @@ class Doris(MySQL):
683
707
  # Handle both static and dynamic partition definitions
684
708
  create_sql = ", ".join(self.sql(e) for e in create_expressions)
685
709
  return f"PARTITION BY RANGE ({partition_expressions}) ({create_sql})"
710
+
711
+ def partitionedbyproperty_sql(self, expression: exp.PartitionedByProperty) -> str:
712
+ node = expression.this
713
+ if isinstance(node, exp.Schema):
714
+ parts = ", ".join(self.sql(e) for e in node.expressions)
715
+ return f"PARTITION BY ({parts})"
716
+ return f"PARTITION BY ({self.sql(node)})"
717
+
718
+ def table_sql(self, expression: exp.Table, sep: str = " AS ") -> str:
719
+ """Override table_sql to avoid AS keyword in UPDATE and DELETE statements."""
720
+ ancestor = expression.find_ancestor(exp.Update, exp.Delete, exp.Select)
721
+ if not isinstance(ancestor, exp.Select):
722
+ sep = " "
723
+ return super().table_sql(expression, sep=sep)
724
+
725
+ def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str:
726
+ return super().alterrename_sql(expression, include_to=False)
@@ -42,30 +42,51 @@ class Dremio(Dialect):
42
42
  TIME_MAPPING = {
43
43
  # year
44
44
  "YYYY": "%Y",
45
+ "yyyy": "%Y",
45
46
  "YY": "%y",
47
+ "yy": "%y",
46
48
  # month / day
47
49
  "MM": "%m",
50
+ "mm": "%m",
48
51
  "MON": "%b",
52
+ "mon": "%b",
49
53
  "MONTH": "%B",
54
+ "month": "%B",
50
55
  "DDD": "%j",
56
+ "ddd": "%j",
51
57
  "DD": "%d",
58
+ "dd": "%d",
52
59
  "DY": "%a",
60
+ "dy": "%a",
53
61
  "DAY": "%A",
62
+ "day": "%A",
54
63
  # hours / minutes / seconds
55
64
  "HH24": "%H",
65
+ "hh24": "%H",
56
66
  "HH12": "%I",
57
- "HH": "%I", # 24- / 12-hour
67
+ "hh12": "%I",
68
+ "HH": "%I",
69
+ "hh": "%I", # 24- / 12-hour
58
70
  "MI": "%M",
71
+ "mi": "%M",
59
72
  "SS": "%S",
73
+ "ss": "%S",
60
74
  "FFF": "%f",
75
+ "fff": "%f",
61
76
  "AMPM": "%p",
77
+ "ampm": "%p",
62
78
  # ISO week / century etc.
63
79
  "WW": "%W",
80
+ "ww": "%W",
64
81
  "D": "%w",
82
+ "d": "%w",
65
83
  "CC": "%C",
84
+ "cc": "%C",
66
85
  # timezone
67
- "TZD": "%Z", # abbreviation (UTC, PST, ...)
68
- "TZO": "%z", # numeric offset (+0200)
86
+ "TZD": "%Z",
87
+ "tzd": "%Z", # abbreviation (UTC, PST, ...)
88
+ "TZO": "%z",
89
+ "tzo": "%z", # numeric offset (+0200)
69
90
  }
70
91
 
71
92
  class Parser(parser.Parser):
@@ -396,6 +396,7 @@ class DuckDB(Dialect):
396
396
 
397
397
  FUNCTIONS = {
398
398
  **parser.Parser.FUNCTIONS,
399
+ "ANY_VALUE": lambda args: exp.IgnoreNulls(this=exp.AnyValue.from_arg_list(args)),
399
400
  "ARRAY_REVERSE_SORT": _build_sort_array_desc,
400
401
  "ARRAY_SORT": exp.SortArray.from_arg_list,
401
402
  "DATEDIFF": _build_date_diff,
@@ -920,6 +921,7 @@ class DuckDB(Dialect):
920
921
  PROPERTIES_LOCATION[exp.LikeProperty] = exp.Properties.Location.POST_SCHEMA
921
922
  PROPERTIES_LOCATION[exp.TemporaryProperty] = exp.Properties.Location.POST_CREATE
922
923
  PROPERTIES_LOCATION[exp.ReturnsProperty] = exp.Properties.Location.POST_ALIAS
924
+ PROPERTIES_LOCATION[exp.SequenceProperties] = exp.Properties.Location.POST_EXPRESSION
923
925
 
924
926
  IGNORE_RESPECT_NULLS_WINDOW_FUNCTIONS = (
925
927
  exp.FirstValue,
@@ -1136,9 +1138,10 @@ class DuckDB(Dialect):
1136
1138
 
1137
1139
  # If BQ's UNNEST is aliased, we transform it from a column alias to a table alias in DDB
1138
1140
  alias = expression.args.get("alias")
1139
- if alias:
1141
+ if isinstance(alias, exp.TableAlias):
1140
1142
  expression.set("alias", None)
1141
- alias = exp.TableAlias(this=seq_get(alias.args.get("columns"), 0))
1143
+ if alias.columns:
1144
+ alias = exp.TableAlias(this=seq_get(alias.columns, 0))
1142
1145
 
1143
1146
  unnest_sql = super().unnest_sql(expression)
1144
1147
  select = exp.Select(expressions=[unnest_sql]).subquery(alias)
@@ -1152,7 +1155,9 @@ class DuckDB(Dialect):
1152
1155
  # window functions that accept it e.g. FIRST_VALUE(... IGNORE NULLS) OVER (...)
1153
1156
  return super().ignorenulls_sql(expression)
1154
1157
 
1155
- self.unsupported("IGNORE NULLS is not supported for non-window functions.")
1158
+ if not isinstance(expression.this, exp.AnyValue):
1159
+ self.unsupported("IGNORE NULLS is not supported for non-window functions.")
1160
+
1156
1161
  return self.sql(expression, "this")
1157
1162
 
1158
1163
  def respectnulls_sql(self, expression: exp.RespectNulls) -> str:
@@ -1247,3 +1252,27 @@ class DuckDB(Dialect):
1247
1252
  return self.sql(exp.Subquery(this=exp.Select(expressions=[posexplode_sql])))
1248
1253
 
1249
1254
  return posexplode_sql
1255
+
1256
+ def addmonths_sql(self, expression: exp.AddMonths) -> str:
1257
+ this = expression.this
1258
+
1259
+ if not this.type:
1260
+ from sqlglot.optimizer.annotate_types import annotate_types
1261
+
1262
+ this = annotate_types(this, dialect=self.dialect)
1263
+
1264
+ if this.is_type(*exp.DataType.TEXT_TYPES):
1265
+ this = exp.Cast(this=this, to=exp.DataType(this=exp.DataType.Type.TIMESTAMP))
1266
+
1267
+ func = self.func(
1268
+ "DATE_ADD", this, exp.Interval(this=expression.expression, unit=exp.var("MONTH"))
1269
+ )
1270
+
1271
+ # DuckDB's DATE_ADD function returns TIMESTAMP/DATETIME by default, even when the input is DATE
1272
+ # To match for example Snowflake's ADD_MONTHS behavior (which preserves the input type)
1273
+ # We need to cast the result back to the original type when the input is DATE or TIMESTAMPTZ
1274
+ # Example: ADD_MONTHS('2023-01-31'::date, 1) should return DATE, not TIMESTAMP
1275
+ if this.is_type(exp.DataType.Type.DATE, exp.DataType.Type.TIMESTAMPTZ):
1276
+ return self.sql(exp.Cast(this=func, to=this.type))
1277
+
1278
+ return self.sql(func)
@@ -28,6 +28,16 @@ def _sha2_sql(self: Exasol.Generator, expression: exp.SHA2) -> str:
28
28
  return self.func(func_name, expression.this)
29
29
 
30
30
 
31
+ def _date_diff_sql(self: Exasol.Generator, expression: exp.DateDiff | exp.TsOrDsDiff) -> str:
32
+ unit = expression.text("unit").upper() or "DAY"
33
+
34
+ if unit not in DATE_UNITS:
35
+ self.unsupported(f"'{unit}' is not supported in Exasol.")
36
+ return self.function_fallback_sql(expression)
37
+
38
+ return self.func(f"{unit}S_BETWEEN", expression.this, expression.expression)
39
+
40
+
31
41
  # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/trunc%5Bate%5D%20(datetime).htm
32
42
  # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/trunc%5Bate%5D%20(number).htm
33
43
  def _build_trunc(args: t.List[exp.Expression], dialect: DialectType) -> exp.Expression:
@@ -59,6 +69,9 @@ def _build_nullifzero(args: t.List) -> exp.If:
59
69
  return exp.If(this=cond, true=exp.Null(), false=seq_get(args, 0))
60
70
 
61
71
 
72
+ DATE_UNITS = {"DAY", "WEEK", "MONTH", "YEAR", "HOUR", "MINUTE", "SECOND"}
73
+
74
+
62
75
  class Exasol(Dialect):
63
76
  TIME_MAPPING = {
64
77
  "yyyy": "%Y",
@@ -100,20 +113,14 @@ class Exasol(Dialect):
100
113
  class Parser(parser.Parser):
101
114
  FUNCTIONS = {
102
115
  **parser.Parser.FUNCTIONS,
103
- # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/add_days.htm
104
- "ADD_DAYS": build_date_delta(exp.DateAdd, default_unit="DAY"),
105
- # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/add_years.htm
106
- "ADD_YEARS": build_date_delta(exp.DateAdd, default_unit="YEAR"),
107
- # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/add_months.htm
108
- "ADD_MONTHS": build_date_delta(exp.DateAdd, default_unit="MONTH"),
109
- # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/add_weeks.htm
110
- "ADD_WEEKS": build_date_delta(exp.DateAdd, default_unit="WEEK"),
111
- # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/add_hour.htm
112
- "ADD_HOURS": build_date_delta(exp.DateAdd, default_unit="HOUR"),
113
- # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/add_minutes.htm
114
- "ADD_MINUTES": build_date_delta(exp.DateAdd, default_unit="MINUTE"),
115
- # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/add_seconds.htm
116
- "ADD_SECONDS": build_date_delta(exp.DateAdd, default_unit="SECOND"),
116
+ **{
117
+ f"ADD_{unit}S": build_date_delta(exp.DateAdd, default_unit=unit)
118
+ for unit in DATE_UNITS
119
+ },
120
+ **{
121
+ f"{unit}S_BETWEEN": build_date_delta(exp.DateDiff, default_unit=unit)
122
+ for unit in DATE_UNITS
123
+ },
117
124
  "BIT_AND": binary_from_function(exp.BitwiseAnd),
118
125
  "BIT_OR": binary_from_function(exp.BitwiseOr),
119
126
  "BIT_XOR": binary_from_function(exp.BitwiseXor),
@@ -196,16 +203,6 @@ class Exasol(Dialect):
196
203
  exp.DataType.Type.DATETIME: "TIMESTAMP",
197
204
  }
198
205
 
199
- DATE_ADD_FUNCTION_BY_UNIT = {
200
- "DAY": "ADD_DAYS",
201
- "WEEK": "ADD_WEEKS",
202
- "MONTH": "ADD_MONTHS",
203
- "YEAR": "ADD_YEARS",
204
- "HOUR": "ADD_HOURS",
205
- "MINUTE": "ADD_MINUTES",
206
- "SECOND": "ADD_SECONDS",
207
- }
208
-
209
206
  def datatype_sql(self, expression: exp.DataType) -> str:
210
207
  # Exasol supports a fixed default precision of 3 for TIMESTAMP WITH LOCAL TIME ZONE
211
208
  # and does not allow specifying a different custom precision
@@ -230,8 +227,8 @@ class Exasol(Dialect):
230
227
  exp.BitwiseRightShift: rename_func("BIT_RSHIFT"),
231
228
  # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/bit_xor.htm
232
229
  exp.BitwiseXor: rename_func("BIT_XOR"),
233
- # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/every.htm
234
- exp.All: rename_func("EVERY"),
230
+ exp.DateDiff: _date_diff_sql,
231
+ exp.TsOrDsDiff: _date_diff_sql,
235
232
  exp.DateTrunc: lambda self, e: self.func("TRUNC", e.this, unit_to_str(e)),
236
233
  exp.DatetimeTrunc: timestamptrunc_sql(),
237
234
  # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/edit_distance.htm#EDIT_DISTANCE
@@ -301,9 +298,8 @@ class Exasol(Dialect):
301
298
 
302
299
  def dateadd_sql(self, expression: exp.DateAdd) -> str:
303
300
  unit = expression.text("unit").upper() or "DAY"
304
- func_name = self.DATE_ADD_FUNCTION_BY_UNIT.get(unit)
305
- if not func_name:
301
+ if unit not in DATE_UNITS:
306
302
  self.unsupported(f"'{unit}' is not supported in Exasol.")
307
303
  return self.function_fallback_sql(expression)
308
304
 
309
- return self.func(func_name, expression.this, expression.expression)
305
+ return self.func(f"ADD_{unit}S", expression.this, expression.expression)
@@ -2,7 +2,7 @@ from sqlglot import TokenType
2
2
  import typing as t
3
3
 
4
4
  from sqlglot import exp
5
- from sqlglot.dialects.dialect import build_formatted_time
5
+ from sqlglot.dialects.dialect import build_formatted_time, rename_func
6
6
  from sqlglot.dialects.mysql import MySQL
7
7
  from sqlglot.generator import unsupported_args
8
8
  from sqlglot.helper import seq_get
@@ -64,6 +64,8 @@ class SingleStore(MySQL):
64
64
  ),
65
65
  format=MySQL.format_time(seq_get(args, 1)),
66
66
  ),
67
+ "UNIX_TIMESTAMP": exp.StrToUnix.from_arg_list,
68
+ "FROM_UNIXTIME": build_formatted_time(exp.UnixToTime, "mysql"),
67
69
  }
68
70
 
69
71
  CAST_COLUMN_OPERATORS = {TokenType.COLON_GT, TokenType.NCOLON_GT}
@@ -111,6 +113,31 @@ class SingleStore(MySQL):
111
113
  exp.TryCast: unsupported_args("format", "action", "default")(
112
114
  lambda self, e: f"{self.sql(e, 'this')} !:> {self.sql(e, 'to')}"
113
115
  ),
116
+ exp.StrToUnix: unsupported_args("format")(rename_func("UNIX_TIMESTAMP")),
117
+ exp.TimeToUnix: rename_func("UNIX_TIMESTAMP"),
118
+ exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"),
119
+ exp.UnixSeconds: rename_func("UNIX_TIMESTAMP"),
120
+ exp.UnixToStr: lambda self, e: self.func(
121
+ "FROM_UNIXTIME",
122
+ e.this,
123
+ self.format_time(
124
+ e,
125
+ inverse_time_mapping=MySQL.INVERSE_TIME_MAPPING,
126
+ inverse_time_trie=MySQL.INVERSE_TIME_TRIE,
127
+ ),
128
+ ),
129
+ exp.UnixToTime: unsupported_args("scale", "zone", "hours", "minutes")(
130
+ lambda self, e: self.func(
131
+ "FROM_UNIXTIME",
132
+ e.this,
133
+ self.format_time(
134
+ e,
135
+ inverse_time_mapping=MySQL.INVERSE_TIME_MAPPING,
136
+ inverse_time_trie=MySQL.INVERSE_TIME_TRIE,
137
+ ),
138
+ ),
139
+ ),
140
+ exp.UnixToTimeStr: lambda self, e: f"FROM_UNIXTIME({self.sql(e, 'this')}) :> TEXT",
114
141
  }
115
142
 
116
143
  # https://docs.singlestore.com/cloud/reference/sql-reference/restricted-keywords/list-of-restricted-keywords/