sqlglot 27.5.1__tar.gz → 27.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 (226) hide show
  1. {sqlglot-27.5.1 → sqlglot-27.6.0}/CHANGELOG.md +6 -0
  2. {sqlglot-27.5.1 → sqlglot-27.6.0}/PKG-INFO +1 -1
  3. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/_version.py +2 -2
  4. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/bigquery.py +3 -1
  5. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/exasol.py +60 -2
  6. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/singlestore.py +22 -0
  7. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/snowflake.py +2 -0
  8. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/expressions.py +5 -0
  9. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/generator.py +14 -0
  10. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/qualify_columns.py +40 -25
  11. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/parser.py +6 -1
  12. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot.egg-info/PKG-INFO +1 -1
  13. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_exasol.py +57 -1
  14. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_singlestore.py +26 -2
  15. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_snowflake.py +28 -1
  16. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/qualify_columns.sql +19 -0
  17. {sqlglot-27.5.1 → sqlglot-27.6.0}/.gitignore +0 -0
  18. {sqlglot-27.5.1 → sqlglot-27.6.0}/.gitpod.yml +0 -0
  19. {sqlglot-27.5.1 → sqlglot-27.6.0}/.pre-commit-config.yaml +0 -0
  20. {sqlglot-27.5.1 → sqlglot-27.6.0}/CONTRIBUTING.md +0 -0
  21. {sqlglot-27.5.1 → sqlglot-27.6.0}/LICENSE +0 -0
  22. {sqlglot-27.5.1 → sqlglot-27.6.0}/MANIFEST.in +0 -0
  23. {sqlglot-27.5.1 → sqlglot-27.6.0}/Makefile +0 -0
  24. {sqlglot-27.5.1 → sqlglot-27.6.0}/README.md +0 -0
  25. {sqlglot-27.5.1 → sqlglot-27.6.0}/pyproject.toml +0 -0
  26. {sqlglot-27.5.1 → sqlglot-27.6.0}/setup.cfg +0 -0
  27. {sqlglot-27.5.1 → sqlglot-27.6.0}/setup.py +0 -0
  28. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/__init__.py +0 -0
  29. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/__main__.py +0 -0
  30. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/_typing.py +0 -0
  31. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/__init__.py +0 -0
  32. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/athena.py +0 -0
  33. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/clickhouse.py +0 -0
  34. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/databricks.py +0 -0
  35. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/dialect.py +0 -0
  36. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/doris.py +0 -0
  37. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/dremio.py +0 -0
  38. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/drill.py +0 -0
  39. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/druid.py +0 -0
  40. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/duckdb.py +0 -0
  41. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/dune.py +0 -0
  42. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/fabric.py +0 -0
  43. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/hive.py +0 -0
  44. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/materialize.py +0 -0
  45. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/mysql.py +0 -0
  46. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/oracle.py +0 -0
  47. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/postgres.py +0 -0
  48. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/presto.py +0 -0
  49. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/prql.py +0 -0
  50. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/redshift.py +0 -0
  51. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/risingwave.py +0 -0
  52. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/spark.py +0 -0
  53. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/spark2.py +0 -0
  54. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/sqlite.py +0 -0
  55. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/starrocks.py +0 -0
  56. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/tableau.py +0 -0
  57. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/teradata.py +0 -0
  58. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/trino.py +0 -0
  59. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/dialects/tsql.py +0 -0
  60. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/diff.py +0 -0
  61. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/errors.py +0 -0
  62. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/executor/__init__.py +0 -0
  63. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/executor/context.py +0 -0
  64. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/executor/env.py +0 -0
  65. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/executor/python.py +0 -0
  66. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/executor/table.py +0 -0
  67. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/helper.py +0 -0
  68. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/jsonpath.py +0 -0
  69. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/lineage.py +0 -0
  70. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/__init__.py +0 -0
  71. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/annotate_types.py +0 -0
  72. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/canonicalize.py +0 -0
  73. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/eliminate_ctes.py +0 -0
  74. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/eliminate_joins.py +0 -0
  75. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/eliminate_subqueries.py +0 -0
  76. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
  77. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/merge_subqueries.py +0 -0
  78. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/normalize.py +0 -0
  79. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
  80. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/optimize_joins.py +0 -0
  81. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/optimizer.py +0 -0
  82. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/pushdown_predicates.py +0 -0
  83. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/pushdown_projections.py +0 -0
  84. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/qualify.py +0 -0
  85. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/qualify_tables.py +0 -0
  86. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/scope.py +0 -0
  87. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/simplify.py +0 -0
  88. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/optimizer/unnest_subqueries.py +0 -0
  89. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/planner.py +0 -0
  90. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/py.typed +0 -0
  91. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/schema.py +0 -0
  92. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/serde.py +0 -0
  93. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/time.py +0 -0
  94. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/tokens.py +0 -0
  95. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/transforms.py +0 -0
  96. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot/trie.py +0 -0
  97. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot.egg-info/SOURCES.txt +0 -0
  98. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot.egg-info/dependency_links.txt +0 -0
  99. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot.egg-info/requires.txt +0 -0
  100. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot.egg-info/top_level.txt +0 -0
  101. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglot.png +0 -0
  102. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/Cargo.lock +0 -0
  103. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/Cargo.toml +0 -0
  104. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/benches/dialect_settings.json +0 -0
  105. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/benches/long.rs +0 -0
  106. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/benches/token_type_settings.json +0 -0
  107. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/benches/tokenizer_dialect_settings.json +0 -0
  108. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/benches/tokenizer_settings.json +0 -0
  109. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/pyproject.toml +0 -0
  110. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/src/lib.rs +0 -0
  111. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/src/settings.rs +0 -0
  112. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/src/token.rs +0 -0
  113. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/src/tokenizer.rs +0 -0
  114. {sqlglot-27.5.1 → sqlglot-27.6.0}/sqlglotrs/src/trie.rs +0 -0
  115. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/__init__.py +0 -0
  116. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/__init__.py +0 -0
  117. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_athena.py +0 -0
  118. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_bigquery.py +0 -0
  119. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_clickhouse.py +0 -0
  120. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_databricks.py +0 -0
  121. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_dialect.py +0 -0
  122. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_doris.py +0 -0
  123. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_dremio.py +0 -0
  124. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_drill.py +0 -0
  125. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_druid.py +0 -0
  126. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_duckdb.py +0 -0
  127. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_dune.py +0 -0
  128. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_fabric.py +0 -0
  129. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_hive.py +0 -0
  130. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_materialize.py +0 -0
  131. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_mysql.py +0 -0
  132. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_oracle.py +0 -0
  133. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_pipe_syntax.py +0 -0
  134. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_postgres.py +0 -0
  135. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_presto.py +0 -0
  136. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_prql.py +0 -0
  137. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_redshift.py +0 -0
  138. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_risingwave.py +0 -0
  139. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_spark.py +0 -0
  140. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_sqlite.py +0 -0
  141. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_starrocks.py +0 -0
  142. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_tableau.py +0 -0
  143. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_teradata.py +0 -0
  144. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_trino.py +0 -0
  145. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/dialects/test_tsql.py +0 -0
  146. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/identity.sql +0 -0
  147. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/jsonpath/LICENSE +0 -0
  148. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/jsonpath/cts.json +0 -0
  149. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/annotate_functions.sql +0 -0
  150. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/annotate_types.sql +0 -0
  151. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/canonicalize.sql +0 -0
  152. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/eliminate_ctes.sql +0 -0
  153. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/eliminate_joins.sql +0 -0
  154. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/eliminate_subqueries.sql +0 -0
  155. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/isolate_table_selects.sql +0 -0
  156. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/merge_subqueries.sql +0 -0
  157. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/normalize.sql +0 -0
  158. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/normalize_identifiers.sql +0 -0
  159. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/optimize_joins.sql +0 -0
  160. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/optimizer.sql +0 -0
  161. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/pushdown_cte_alias_columns.sql +0 -0
  162. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/pushdown_predicates.sql +0 -0
  163. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/pushdown_projections.sql +0 -0
  164. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/qualify_columns__invalid.sql +0 -0
  165. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/qualify_columns__with_invisible.sql +0 -0
  166. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/qualify_columns_ddl.sql +0 -0
  167. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/qualify_tables.sql +0 -0
  168. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/quote_identifiers.sql +0 -0
  169. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/simplify.sql +0 -0
  170. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/call_center.csv.gz +0 -0
  171. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/catalog_page.csv.gz +0 -0
  172. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/catalog_returns.csv.gz +0 -0
  173. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/catalog_sales.csv.gz +0 -0
  174. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/customer.csv.gz +0 -0
  175. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/customer_address.csv.gz +0 -0
  176. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/customer_demographics.csv.gz +0 -0
  177. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/date_dim.csv.gz +0 -0
  178. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/household_demographics.csv.gz +0 -0
  179. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/income_band.csv.gz +0 -0
  180. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/inventory.csv.gz +0 -0
  181. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/item.csv.gz +0 -0
  182. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/promotion.csv.gz +0 -0
  183. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/reason.csv.gz +0 -0
  184. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/ship_mode.csv.gz +0 -0
  185. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/store.csv.gz +0 -0
  186. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/store_returns.csv.gz +0 -0
  187. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/store_sales.csv.gz +0 -0
  188. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/time_dim.csv.gz +0 -0
  189. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/tpc-ds.sql +0 -0
  190. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/warehouse.csv.gz +0 -0
  191. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/web_page.csv.gz +0 -0
  192. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/web_returns.csv.gz +0 -0
  193. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/web_sales.csv.gz +0 -0
  194. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-ds/web_site.csv.gz +0 -0
  195. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-h/customer.csv.gz +0 -0
  196. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-h/lineitem.csv.gz +0 -0
  197. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-h/nation.csv.gz +0 -0
  198. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-h/orders.csv.gz +0 -0
  199. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-h/part.csv.gz +0 -0
  200. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-h/partsupp.csv.gz +0 -0
  201. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-h/region.csv.gz +0 -0
  202. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-h/supplier.csv.gz +0 -0
  203. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/tpc-h/tpc-h.sql +0 -0
  204. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/optimizer/unnest_subqueries.sql +0 -0
  205. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/partial.sql +0 -0
  206. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/fixtures/pretty.sql +0 -0
  207. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/gen_fixtures.py +0 -0
  208. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/helpers.py +0 -0
  209. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_build.py +0 -0
  210. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_dialect_imports.py +0 -0
  211. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_diff.py +0 -0
  212. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_docs.py +0 -0
  213. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_executor.py +0 -0
  214. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_expressions.py +0 -0
  215. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_generator.py +0 -0
  216. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_helper.py +0 -0
  217. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_jsonpath.py +0 -0
  218. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_lineage.py +0 -0
  219. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_optimizer.py +0 -0
  220. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_parser.py +0 -0
  221. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_schema.py +0 -0
  222. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_serde.py +0 -0
  223. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_time.py +0 -0
  224. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_tokens.py +0 -0
  225. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_transforms.py +0 -0
  226. {sqlglot-27.5.1 → sqlglot-27.6.0}/tests/test_transpile.py +0 -0
@@ -1,6 +1,11 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ## [v27.5.1] - 2025-07-30
5
+ ### :bug: Bug Fixes
6
+ - [`caf71d6`](https://github.com/tobymao/sqlglot/commit/caf71d687c0048d2346fddaee58b519e4f2e7945) - `between` builder should not set `symmetric` by default *(commit by [@georgesittas](https://github.com/georgesittas))*
7
+
8
+
4
9
  ## [v27.5.0] - 2025-07-30
5
10
  ### :boom: BREAKING CHANGES
6
11
  - due to [`002286e`](https://github.com/tobymao/sqlglot/commit/002286ee05a608e303a2238a9a74ab963709b5da) - remove AM/PM entries from postgres, oracle `TIME_MAPPING` *(PR [#5491](https://github.com/tobymao/sqlglot/pull/5491) by [@georgesittas](https://github.com/georgesittas))*:
@@ -6373,3 +6378,4 @@ Changelog
6373
6378
  [v27.4.0]: https://github.com/tobymao/sqlglot/compare/v27.3.1...v27.4.0
6374
6379
  [v27.4.1]: https://github.com/tobymao/sqlglot/compare/v27.4.0...v27.4.1
6375
6380
  [v27.5.0]: https://github.com/tobymao/sqlglot/compare/v27.4.1...v27.5.0
6381
+ [v27.5.1]: https://github.com/tobymao/sqlglot/compare/v27.5.0...v27.5.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 27.5.1
3
+ Version: 27.6.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.5.1'
21
- __version_tuple__ = version_tuple = (27, 5, 1)
20
+ __version__ = version = '27.6.0'
21
+ __version_tuple__ = version_tuple = (27, 6, 0)
@@ -434,7 +434,9 @@ class BigQuery(Dialect):
434
434
 
435
435
  # The _PARTITIONTIME and _PARTITIONDATE pseudo-columns are not returned by a SELECT * statement
436
436
  # https://cloud.google.com/bigquery/docs/querying-partitioned-tables#query_an_ingestion-time_partitioned_table
437
- PSEUDOCOLUMNS = {"_PARTITIONTIME", "_PARTITIONDATE"}
437
+ # https://cloud.google.com/bigquery/docs/querying-wildcard-tables#scanning_a_range_of_tables_using_table_suffix
438
+ # https://cloud.google.com/bigquery/docs/query-cloud-storage-data#query_the_file_name_pseudo-column
439
+ PSEUDOCOLUMNS = {"_PARTITIONTIME", "_PARTITIONDATE", "_TABLE_SUFFIX", "_FILE_NAME"}
438
440
 
439
441
  # All set operations require either a DISTINCT or ALL specifier
440
442
  SET_OP_DISTINCT_BY_DEFAULT = dict.fromkeys((exp.Except, exp.Intersect, exp.Union), None)
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
  import typing as t
4
4
 
5
5
  from sqlglot import exp, generator, parser, tokens
6
- from sqlglot.dialects.clickhouse import timestamptrunc_sql
7
6
  from sqlglot.dialects.dialect import (
8
7
  Dialect,
9
8
  binary_from_function,
@@ -12,6 +11,8 @@ from sqlglot.dialects.dialect import (
12
11
  strposition_sql,
13
12
  timestrtotime_sql,
14
13
  unit_to_str,
14
+ timestamptrunc_sql,
15
+ build_date_delta,
15
16
  )
16
17
  from sqlglot.generator import unsupported_args
17
18
  from sqlglot.helper import seq_get
@@ -46,6 +47,18 @@ def _build_trunc(args: t.List[exp.Expression], dialect: DialectType) -> exp.Expr
46
47
  return exp.Anonymous(this="TRUNC", expressions=args)
47
48
 
48
49
 
50
+ # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/zeroifnull.htm
51
+ def _build_zeroifnull(args: t.List) -> exp.If:
52
+ cond = exp.Is(this=seq_get(args, 0), expression=exp.Null())
53
+ return exp.If(this=cond, true=exp.Literal.number(0), false=seq_get(args, 0))
54
+
55
+
56
+ # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/nullifzero.htm
57
+ def _build_nullifzero(args: t.List) -> exp.If:
58
+ cond = exp.EQ(this=seq_get(args, 0), expression=exp.Literal.number(0))
59
+ return exp.If(this=cond, true=exp.Null(), false=seq_get(args, 0))
60
+
61
+
49
62
  class Exasol(Dialect):
50
63
  TIME_MAPPING = {
51
64
  "yyyy": "%Y",
@@ -79,11 +92,28 @@ class Exasol(Dialect):
79
92
  KEYWORDS = {
80
93
  **tokens.Tokenizer.KEYWORDS,
81
94
  "USER": TokenType.CURRENT_USER,
95
+ # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/if.htm
96
+ "ENDIF": TokenType.END,
97
+ "LONG VARCHAR": TokenType.TEXT,
82
98
  }
83
99
 
84
100
  class Parser(parser.Parser):
85
101
  FUNCTIONS = {
86
102
  **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"),
87
117
  "BIT_AND": binary_from_function(exp.BitwiseAnd),
88
118
  "BIT_OR": binary_from_function(exp.BitwiseOr),
89
119
  "BIT_XOR": binary_from_function(exp.BitwiseXor),
@@ -127,6 +157,8 @@ class Exasol(Dialect):
127
157
  timestamp=seq_get(args, 0),
128
158
  options=seq_get(args, 3),
129
159
  ),
160
+ "NULLIFZERO": _build_nullifzero,
161
+ "ZEROIFNULL": _build_zeroifnull,
130
162
  }
131
163
  CONSTRAINT_PARSERS = {
132
164
  **parser.Parser.CONSTRAINT_PARSERS,
@@ -146,7 +178,8 @@ class Exasol(Dialect):
146
178
  exp.DataType.Type.MEDIUMTEXT: "VARCHAR",
147
179
  exp.DataType.Type.TINYBLOB: "VARCHAR",
148
180
  exp.DataType.Type.TINYTEXT: "VARCHAR",
149
- exp.DataType.Type.TEXT: "VARCHAR",
181
+ # https://docs.exasol.com/db/latest/sql_references/data_types/datatypealiases.htm
182
+ exp.DataType.Type.TEXT: "LONG VARCHAR",
150
183
  exp.DataType.Type.VARBINARY: "VARCHAR",
151
184
  }
152
185
 
@@ -163,6 +196,16 @@ class Exasol(Dialect):
163
196
  exp.DataType.Type.DATETIME: "TIMESTAMP",
164
197
  }
165
198
 
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
+
166
209
  def datatype_sql(self, expression: exp.DataType) -> str:
167
210
  # Exasol supports a fixed default precision of 3 for TIMESTAMP WITH LOCAL TIME ZONE
168
211
  # and does not allow specifying a different custom precision
@@ -249,3 +292,18 @@ class Exasol(Dialect):
249
292
  options = expression.args.get("options")
250
293
 
251
294
  return self.func("CONVERT_TZ", datetime, from_tz, to_tz, options)
295
+
296
+ def if_sql(self, expression: exp.If) -> str:
297
+ this = self.sql(expression, "this")
298
+ true = self.sql(expression, "true")
299
+ false = self.sql(expression, "false")
300
+ return f"IF {this} THEN {true} ELSE {false} ENDIF"
301
+
302
+ def dateadd_sql(self, expression: exp.DateAdd) -> str:
303
+ unit = expression.text("unit").upper() or "DAY"
304
+ func_name = self.DATE_ADD_FUNCTION_BY_UNIT.get(unit)
305
+ if not func_name:
306
+ self.unsupported(f"'{unit}' is not supported in Exasol.")
307
+ return self.function_fallback_sql(expression)
308
+
309
+ return self.func(func_name, expression.this, expression.expression)
@@ -4,6 +4,7 @@ import typing as t
4
4
  from sqlglot import exp
5
5
  from sqlglot.dialects.dialect import build_formatted_time
6
6
  from sqlglot.dialects.mysql import MySQL
7
+ from sqlglot.generator import unsupported_args
7
8
  from sqlglot.helper import seq_get
8
9
 
9
10
 
@@ -65,6 +66,21 @@ class SingleStore(MySQL):
65
66
  ),
66
67
  }
67
68
 
69
+ CAST_COLUMN_OPERATORS = {TokenType.COLON_GT, TokenType.NCOLON_GT}
70
+
71
+ COLUMN_OPERATORS = {
72
+ TokenType.COLON_GT: lambda self, this, to: self.expression(
73
+ exp.Cast,
74
+ this=this,
75
+ to=to,
76
+ ),
77
+ TokenType.NCOLON_GT: lambda self, this, to: self.expression(
78
+ exp.TryCast,
79
+ this=this,
80
+ to=to,
81
+ ),
82
+ }
83
+
68
84
  class Generator(MySQL.Generator):
69
85
  TRANSFORMS = {
70
86
  **MySQL.Generator.TRANSFORMS,
@@ -89,6 +105,12 @@ class SingleStore(MySQL):
89
105
  inverse_time_trie=MySQL.INVERSE_TIME_TRIE,
90
106
  ),
91
107
  ),
108
+ exp.Cast: unsupported_args("format", "action", "default")(
109
+ lambda self, e: f"{self.sql(e, 'this')} :> {self.sql(e, 'to')}"
110
+ ),
111
+ exp.TryCast: unsupported_args("format", "action", "default")(
112
+ lambda self, e: f"{self.sql(e, 'this')} !:> {self.sql(e, 'to')}"
113
+ ),
92
114
  }
93
115
 
94
116
  # https://docs.singlestore.com/cloud/reference/sql-reference/restricted-keywords/list-of-restricted-keywords/
@@ -591,6 +591,7 @@ class Snowflake(Dialect):
591
591
  this=seq_get(args, 0), expression=seq_get(args, 1), max_dist=seq_get(args, 2)
592
592
  ),
593
593
  "FLATTEN": exp.Explode.from_arg_list,
594
+ "GET": exp.GetExtract.from_arg_list,
594
595
  "GET_PATH": lambda args, dialect: exp.JSONExtract(
595
596
  this=seq_get(args, 0),
596
597
  expression=dialect.to_json_path(seq_get(args, 1)),
@@ -1220,6 +1221,7 @@ class Snowflake(Dialect):
1220
1221
  exp.GenerateSeries: lambda self, e: self.func(
1221
1222
  "ARRAY_GENERATE_RANGE", e.args["start"], e.args["end"] + 1, e.args.get("step")
1222
1223
  ),
1224
+ exp.GetExtract: rename_func("GET"),
1223
1225
  exp.GroupConcat: lambda self, e: groupconcat_sql(self, e, sep=""),
1224
1226
  exp.If: if_sql(name="IFF", false_value="NULL"),
1225
1227
  exp.JSONExtractArray: _json_extract_value_array_sql,
@@ -6185,6 +6185,11 @@ class GenerateTimestampArray(Func):
6185
6185
  arg_types = {"start": True, "end": True, "step": True}
6186
6186
 
6187
6187
 
6188
+ # https://docs.snowflake.com/en/sql-reference/functions/get
6189
+ class GetExtract(Func):
6190
+ arg_types = {"this": True, "expression": True}
6191
+
6192
+
6188
6193
  class Greatest(Func):
6189
6194
  arg_types = {"this": True, "expressions": False}
6190
6195
  is_var_len_args = True
@@ -5113,3 +5113,17 @@ class Generator(metaclass=_Generator):
5113
5113
  where = self.sql(expression, "where")
5114
5114
  where = self.seg(f"WHERE {where}") if where else ""
5115
5115
  return f"SEMANTIC_VIEW({self.indent(this + metrics + dimensions + where)}{self.seg(')', sep='')}"
5116
+
5117
+ def getextract_sql(self, expression: exp.GetExtract) -> str:
5118
+ this = expression.this
5119
+ expr = expression.expression
5120
+
5121
+ if not this.type or not expression.type:
5122
+ from sqlglot.optimizer.annotate_types import annotate_types
5123
+
5124
+ this = annotate_types(this, dialect=self.dialect)
5125
+
5126
+ if this.is_type(*(exp.DataType.Type.ARRAY, exp.DataType.Type.MAP)):
5127
+ return self.sql(exp.Bracket(this=this, expressions=[expr]))
5128
+
5129
+ return self.sql(exp.JSONExtract(this=this, expression=self.dialect.to_json_path(expr)))
@@ -972,6 +972,44 @@ class Resolver:
972
972
  }
973
973
  return self._all_columns
974
974
 
975
+ def get_source_columns_from_set_op(self, expression: exp.Expression) -> t.List[str]:
976
+ if isinstance(expression, exp.Select):
977
+ return expression.named_selects
978
+ if isinstance(expression, exp.Subquery) and isinstance(expression.this, exp.SetOperation):
979
+ # Different types of SET modifiers can be chained together if they're explicitly grouped by nesting
980
+ return self.get_source_columns_from_set_op(expression.this)
981
+ if not isinstance(expression, exp.SetOperation):
982
+ raise OptimizeError(f"Unknown set operation: {expression}")
983
+
984
+ set_op = expression
985
+
986
+ # BigQuery specific set operations modifiers, e.g INNER UNION ALL BY NAME
987
+ on_column_list = set_op.args.get("on")
988
+
989
+ if on_column_list:
990
+ # The resulting columns are the columns in the ON clause:
991
+ # {INNER | LEFT | FULL} UNION ALL BY NAME ON (col1, col2, ...)
992
+ columns = [col.name for col in on_column_list]
993
+ elif set_op.side or set_op.kind:
994
+ side = set_op.side
995
+ kind = set_op.kind
996
+
997
+ # Visit the children UNIONs (if any) in a post-order traversal
998
+ left = self.get_source_columns_from_set_op(set_op.left)
999
+ right = self.get_source_columns_from_set_op(set_op.right)
1000
+
1001
+ # We use dict.fromkeys to deduplicate keys and maintain insertion order
1002
+ if side == "LEFT":
1003
+ columns = left
1004
+ elif side == "FULL":
1005
+ columns = list(dict.fromkeys(left + right))
1006
+ elif kind == "INNER":
1007
+ columns = list(dict.fromkeys(left).keys() & dict.fromkeys(right).keys())
1008
+ else:
1009
+ columns = set_op.named_selects
1010
+
1011
+ return columns
1012
+
975
1013
  def get_source_columns(self, name: str, only_visible: bool = False) -> t.Sequence[str]:
976
1014
  """Resolve the source columns for a given source `name`."""
977
1015
  cache_key = (name, only_visible)
@@ -996,31 +1034,8 @@ class Resolver:
996
1034
  for k in source.expression.type.expressions: # type: ignore
997
1035
  columns.append(k.name)
998
1036
  elif isinstance(source, Scope) and isinstance(source.expression, exp.SetOperation):
999
- set_op = source.expression
1000
-
1001
- # BigQuery specific set operations modifiers, e.g INNER UNION ALL BY NAME
1002
- on_column_list = set_op.args.get("on")
1003
-
1004
- if on_column_list:
1005
- # The resulting columns are the columns in the ON clause:
1006
- # {INNER | LEFT | FULL} UNION ALL BY NAME ON (col1, col2, ...)
1007
- columns = [col.name for col in on_column_list]
1008
- elif set_op.side or set_op.kind:
1009
- side = set_op.side
1010
- kind = set_op.kind
1011
-
1012
- left = set_op.left.named_selects
1013
- right = set_op.right.named_selects
1014
-
1015
- # We use dict.fromkeys to deduplicate keys and maintain insertion order
1016
- if side == "LEFT":
1017
- columns = left
1018
- elif side == "FULL":
1019
- columns = list(dict.fromkeys(left + right))
1020
- elif kind == "INNER":
1021
- columns = list(dict.fromkeys(left).keys() & dict.fromkeys(right).keys())
1022
- else:
1023
- columns = set_op.named_selects
1037
+ columns = self.get_source_columns_from_set_op(source.expression)
1038
+
1024
1039
  else:
1025
1040
  select = seq_get(source.expression.selects, 0)
1026
1041
 
@@ -792,6 +792,11 @@ class Parser(metaclass=_Parser):
792
792
  ),
793
793
  }
794
794
 
795
+ CAST_COLUMN_OPERATORS = {
796
+ TokenType.DOTCOLON,
797
+ TokenType.DCOLON,
798
+ }
799
+
795
800
  EXPRESSION_PARSERS = {
796
801
  exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
797
802
  exp.Column: lambda self: self._parse_column(),
@@ -5621,7 +5626,7 @@ class Parser(metaclass=_Parser):
5621
5626
  op_token = self._prev.token_type
5622
5627
  op = self.COLUMN_OPERATORS.get(op_token)
5623
5628
 
5624
- if op_token in (TokenType.DCOLON, TokenType.DOTCOLON):
5629
+ if op_token in self.CAST_COLUMN_OPERATORS:
5625
5630
  field = self._parse_dcolon()
5626
5631
  if not field:
5627
5632
  self.raise_error("Expected type")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 27.5.1
3
+ Version: 27.6.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/
@@ -13,7 +13,10 @@ class TestExasol(Validator):
13
13
  self.validate_identity("CAST(x AS MEDIUMTEXT)", "CAST(x AS VARCHAR)")
14
14
  self.validate_identity("CAST(x AS TINYBLOB)", "CAST(x AS VARCHAR)")
15
15
  self.validate_identity("CAST(x AS TINYTEXT)", "CAST(x AS VARCHAR)")
16
- self.validate_identity("CAST(x AS TEXT)", "CAST(x AS VARCHAR)")
16
+ self.validate_identity("CAST(x AS TEXT)", "CAST(x AS LONG VARCHAR)")
17
+ self.validate_identity(
18
+ "SELECT CAST((CAST(202305 AS INT) - 100) AS LONG VARCHAR) AS CAL_YEAR_WEEK_ADJUSTED"
19
+ )
17
20
  self.validate_identity("CAST(x AS VARBINARY)", "CAST(x AS VARCHAR)")
18
21
  self.validate_identity("CAST(x AS VARCHAR)", "CAST(x AS VARCHAR)")
19
22
  self.validate_identity("CAST(x AS CHAR)", "CAST(x AS CHAR)")
@@ -400,6 +403,32 @@ class TestExasol(Validator):
400
403
  "databricks": "SELECT DATE_TRUNC('MINUTE', CAST('2006-12-31 23:59:59' AS TIMESTAMP)) AS DATE_TRUNC",
401
404
  },
402
405
  )
406
+ test_cases = {
407
+ "ADD_DAYS": ("DAY", "add_days"),
408
+ "ADD_WEEKS": ("WEEK", "add_weeks"),
409
+ "ADD_MONTHS": ("MONTH", "add_months"),
410
+ "ADD_YEARS": ("YEAR", "add_years"),
411
+ "ADD_HOURS": ("HOUR", "add_hours"),
412
+ "ADD_MINUTES": ("MINUTE", "add_minutes"),
413
+ "ADD_SECONDS": ("SECOND", "add_seconds"),
414
+ }
415
+
416
+ for func_name, (unit, alias) in test_cases.items():
417
+ with self.subTest(f"Testing {func_name}"):
418
+ write = {
419
+ "exasol": f"SELECT {func_name}(CAST('2000-02-28' AS DATE), 1) AS {alias}",
420
+ "bigquery": f"SELECT DATE_ADD(CAST('2000-02-28' AS DATE), INTERVAL 1 {unit}) AS {alias}",
421
+ "duckdb": f"SELECT CAST('2000-02-28' AS DATE) + INTERVAL 1 {unit} AS {alias}",
422
+ "presto": f"SELECT DATE_ADD('{unit}', 1, CAST('2000-02-28' AS DATE)) AS {alias}",
423
+ "redshift": f"SELECT DATEADD({unit}, 1, CAST('2000-02-28' AS DATE)) AS {alias}",
424
+ "snowflake": f"SELECT DATEADD({unit}, 1, CAST('2000-02-28' AS DATE)) AS {alias}",
425
+ "tsql": f"SELECT DATEADD({unit}, 1, CAST('2000-02-28' AS DATE)) AS {alias}",
426
+ }
427
+
428
+ self.validate_all(
429
+ f"SELECT {func_name}(DATE '2000-02-28', 1) AS {alias}",
430
+ write=write,
431
+ )
403
432
 
404
433
  def test_number_functions(self):
405
434
  self.validate_identity("SELECT TRUNC(123.456, 2) AS TRUNC")
@@ -509,3 +538,30 @@ class TestExasol(Validator):
509
538
  "trino": "SHA512(x)",
510
539
  },
511
540
  )
541
+ self.validate_all(
542
+ "SELECT NULLIFZERO(1) NIZ1",
543
+ write={
544
+ "exasol": "SELECT IF 1 = 0 THEN NULL ELSE 1 ENDIF AS NIZ1",
545
+ "snowflake": "SELECT IFF(1 = 0, NULL, 1) AS NIZ1",
546
+ "sqlite": "SELECT IIF(1 = 0, NULL, 1) AS NIZ1",
547
+ "presto": "SELECT IF(1 = 0, NULL, 1) AS NIZ1",
548
+ "spark": "SELECT IF(1 = 0, NULL, 1) AS NIZ1",
549
+ "hive": "SELECT IF(1 = 0, NULL, 1) AS NIZ1",
550
+ "duckdb": "SELECT CASE WHEN 1 = 0 THEN NULL ELSE 1 END AS NIZ1",
551
+ },
552
+ )
553
+ self.validate_all(
554
+ "SELECT ZEROIFNULL(NULL) NIZ1",
555
+ write={
556
+ "exasol": "SELECT IF NULL IS NULL THEN 0 ELSE NULL ENDIF AS NIZ1",
557
+ "snowflake": "SELECT IFF(NULL IS NULL, 0, NULL) AS NIZ1",
558
+ "sqlite": "SELECT IIF(NULL IS NULL, 0, NULL) AS NIZ1",
559
+ "presto": "SELECT IF(NULL IS NULL, 0, NULL) AS NIZ1",
560
+ "spark": "SELECT IF(NULL IS NULL, 0, NULL) AS NIZ1",
561
+ "hive": "SELECT IF(NULL IS NULL, 0, NULL) AS NIZ1",
562
+ "duckdb": "SELECT CASE WHEN NULL IS NULL THEN 0 ELSE NULL END AS NIZ1",
563
+ },
564
+ )
565
+ self.validate_identity(
566
+ "SELECT name, age, IF age < 18 THEN 'underaged' ELSE 'adult' ENDIF AS LEGALITY FROM persons"
567
+ )
@@ -19,7 +19,6 @@ class TestSingleStore(Validator):
19
19
 
20
20
  self.validate_identity("SELECT 1")
21
21
  self.validate_identity("SELECT * FROM `users` ORDER BY ALL")
22
- self.validate_identity("SELECT CAST(x AS GEOGRAPHYPOINT)")
23
22
 
24
23
  def test_byte_strings(self):
25
24
  self.validate_identity("SELECT e'text'")
@@ -47,5 +46,30 @@ class TestSingleStore(Validator):
47
46
  )
48
47
  self.validate_identity(
49
48
  "SELECT TIME_FORMAT('12:05:47', '%s, %i, %h')",
50
- "SELECT DATE_FORMAT(CAST('12:05:47' AS TIME(6)), '%s, %i, %h')",
49
+ "SELECT DATE_FORMAT('12:05:47' :> TIME(6), '%s, %i, %h')",
51
50
  )
51
+
52
+ def test_cast(self):
53
+ self.validate_all(
54
+ "SELECT 1 :> INT",
55
+ read={
56
+ "": "SELECT CAST(1 AS INT)",
57
+ },
58
+ write={
59
+ "singlestore": "SELECT 1 :> INT",
60
+ "": "SELECT CAST(1 AS INT)",
61
+ },
62
+ )
63
+ self.validate_all(
64
+ "SELECT 1 !:> INT",
65
+ read={
66
+ "": "SELECT TRY_CAST(1 AS INT)",
67
+ },
68
+ write={
69
+ "singlestore": "SELECT 1 !:> INT",
70
+ "": "SELECT TRY_CAST(1 AS INT)",
71
+ },
72
+ )
73
+ self.validate_identity("SELECT '{\"a\" : 1}' :> JSON")
74
+ self.validate_identity("SELECT NOW() !:> TIMESTAMP(6)")
75
+ self.validate_identity("SELECT x :> GEOGRAPHYPOINT")
@@ -2746,7 +2746,7 @@ SINGLE = TRUE""",
2746
2746
 
2747
2747
  def test_get_from_stage(self):
2748
2748
  self.validate_identity('GET @"my_DB"."schEMA1"."MYstage" \'file:///dir/tmp.csv\'')
2749
- self.validate_identity("GET @s1/test 'file:///dir/tmp.csv'")
2749
+ self.validate_identity("GET @s1/test 'file:///dir/tmp.csv'").assert_is(exp.Get)
2750
2750
 
2751
2751
  # GET with file path and stage ref containing spaces (wrapped in single quotes)
2752
2752
  ast = parse_one("GET '@s1/my folder' 'file://my file.txt'", read="snowflake")
@@ -2950,3 +2950,30 @@ FROM SEMANTIC_VIEW(
2950
2950
  )""",
2951
2951
  pretty=True,
2952
2952
  )
2953
+
2954
+ def test_get_extract(self):
2955
+ self.validate_all(
2956
+ "SELECT GET([4, 5, 6], 1)",
2957
+ write={
2958
+ "snowflake": "SELECT GET([4, 5, 6], 1)",
2959
+ "duckdb": "SELECT [4, 5, 6][2]",
2960
+ },
2961
+ )
2962
+
2963
+ self.validate_all(
2964
+ "SELECT GET(col::MAP(INTEGER, VARCHAR), 1)",
2965
+ write={
2966
+ "snowflake": "SELECT GET(CAST(col AS MAP(INT, VARCHAR)), 1)",
2967
+ "duckdb": "SELECT CAST(col AS MAP(INT, TEXT))[1]",
2968
+ },
2969
+ )
2970
+
2971
+ self.validate_all(
2972
+ "SELECT GET(v, 'field')",
2973
+ write={
2974
+ "snowflake": "SELECT GET(v, 'field')",
2975
+ "duckdb": "SELECT v -> '$.field'",
2976
+ },
2977
+ )
2978
+
2979
+ self.validate_identity("GET(foo, bar)").assert_is(exp.GetExtract)
@@ -389,6 +389,25 @@ SELECT _q_0.foo AS foo, _q_0.qux AS qux FROM ((SELECT 1 AS foo, 2 AS bar LEFT UN
389
389
  SELECT * FROM (((SELECT 1 AS foo, 2 AS bar LEFT UNION ALL BY NAME SELECT 3 AS bar, 4 AS baz) FULL UNION ALL BY NAME ON (foo, qux) SELECT 3 AS qux, 4 AS bar) INNER UNION ALL BY NAME ON (foo) SELECT 6 AS foo);
390
390
  SELECT _q_0.foo AS foo FROM (((SELECT 1 AS foo, 2 AS bar LEFT UNION ALL BY NAME SELECT 3 AS bar, 4 AS baz) FULL UNION ALL BY NAME ON (foo, qux) SELECT 3 AS qux, 4 AS bar) INNER UNION ALL BY NAME ON (foo) SELECT 6 AS foo) AS _q_0;
391
391
 
392
+ # Title: Nested set operations with modifiers
393
+ # dialect: bigquery
394
+ # execute: false
395
+ WITH t1 AS (SELECT 1 AS a, 2 AS b), t2 AS (SELECT 2 AS b, 3 AS c), t3 AS (SELECT 2 AS c, 3 AS d), t4 AS (SELECT 2 AS e, 3 AS f) SELECT * FROM ((SELECT * FROM t1 FULL OUTER UNION ALL BY NAME (SELECT * FROM t2 FULL OUTER UNION ALL BY NAME (SELECT * FROM t3 FULL OUTER UNION ALL BY NAME SELECT * FROM t4))));
396
+ WITH t1 AS (SELECT 1 AS a, 2 AS b), t2 AS (SELECT 2 AS b, 3 AS c), t3 AS (SELECT 2 AS c, 3 AS d), t4 AS (SELECT 2 AS e, 3 AS f) SELECT _q_0.a AS a, _q_0.b AS b, _q_0.c AS c, _q_0.d AS d, _q_0.e AS e, _q_0.f AS f FROM ((SELECT t1.a AS a, t1.b AS b FROM t1 AS t1 FULL OUTER UNION ALL BY NAME (SELECT t2.b AS b, t2.c AS c FROM t2 AS t2 FULL OUTER UNION ALL BY NAME (SELECT t3.c AS c, t3.d AS d FROM t3 AS t3 FULL OUTER UNION ALL BY NAME SELECT t4.e AS e, t4.f AS f FROM t4 AS t4))) AS _q_0);
397
+
398
+
399
+ # Title: Nested set operations with different modifiers (FULL + INNER)
400
+ # dialect: bigquery
401
+ # execute: false
402
+ WITH t1 AS (SELECT 1 AS a, 2 AS b), t2 AS (SELECT 2 AS b, 3 AS c), t3 AS (SELECT 2 AS c, 3 AS d), t4 AS (SELECT 2 AS e, 3 AS f) SELECT * FROM ((SELECT * FROM t1 FULL OUTER UNION ALL BY NAME (SELECT * FROM t2 INNER UNION ALL BY NAME (SELECT * FROM t3 FULL OUTER UNION ALL BY NAME SELECT * FROM t4))));
403
+ WITH t1 AS (SELECT 1 AS a, 2 AS b), t2 AS (SELECT 2 AS b, 3 AS c), t3 AS (SELECT 2 AS c, 3 AS d), t4 AS (SELECT 2 AS e, 3 AS f) SELECT _q_0.a AS a, _q_0.b AS b, _q_0.c AS c FROM ((SELECT t1.a AS a, t1.b AS b FROM t1 AS t1 FULL OUTER UNION ALL BY NAME (SELECT t2.b AS b, t2.c AS c FROM t2 AS t2 INNER UNION ALL BY NAME (SELECT t3.c AS c, t3.d AS d FROM t3 AS t3 FULL OUTER UNION ALL BY NAME SELECT t4.e AS e, t4.f AS f FROM t4 AS t4))) AS _q_0);
404
+
405
+ # Title: Nested set operations with different modifiers (FULL + LEFT)
406
+ # dialect: bigquery
407
+ # execute: false
408
+ WITH t1 AS (SELECT 1 AS a, 2 AS b, 3 AS c, 4 AS d), t2 AS (SELECT 2 AS b, 3 AS c), t3 AS (SELECT 2 AS c, 3 AS d), t4 AS (SELECT 2 AS d, 3 AS e) SELECT * FROM ((SELECT * FROM t1 FULL OUTER UNION ALL BY NAME (SELECT * FROM t2 FULL UNION ALL BY NAME (SELECT * FROM t3 LEFT UNION ALL BY NAME SELECT * FROM t4))));
409
+ WITH t1 AS (SELECT 1 AS a, 2 AS b, 3 AS c, 4 AS d), t2 AS (SELECT 2 AS b, 3 AS c), t3 AS (SELECT 2 AS c, 3 AS d), t4 AS (SELECT 2 AS d, 3 AS e) SELECT _q_0.a AS a, _q_0.b AS b, _q_0.c AS c, _q_0.d AS d FROM ((SELECT t1.a AS a, t1.b AS b, t1.c AS c, t1.d AS d FROM t1 AS t1 FULL OUTER UNION ALL BY NAME (SELECT t2.b AS b, t2.c AS c FROM t2 AS t2 FULL UNION ALL BY NAME (SELECT t3.c AS c, t3.d AS d FROM t3 AS t3 LEFT UNION ALL BY NAME SELECT t4.d AS d, t4.e AS e FROM t4 AS t4))) AS _q_0);
410
+
392
411
  --------------------------------------
393
412
  -- Subqueries
394
413
  --------------------------------------
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes