sqlglot 27.19.0__tar.gz → 27.20.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 (228) hide show
  1. {sqlglot-27.19.0 → sqlglot-27.20.0}/CHANGELOG.md +41 -0
  2. {sqlglot-27.19.0 → sqlglot-27.20.0}/Makefile +8 -2
  3. {sqlglot-27.19.0 → sqlglot-27.20.0}/PKG-INFO +3 -1
  4. {sqlglot-27.19.0 → sqlglot-27.20.0}/README.md +2 -0
  5. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/_version.py +3 -3
  6. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/snowflake.py +21 -0
  7. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/sqlite.py +9 -0
  8. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/starrocks.py +3 -0
  9. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/expressions.py +78 -25
  10. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/generator.py +3 -0
  11. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/helper.py +0 -18
  12. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/parser.py +1 -1
  13. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot.egg-info/PKG-INFO +3 -1
  14. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_snowflake.py +23 -0
  15. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_sqlite.py +1 -0
  16. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_starrocks.py +3 -0
  17. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/annotate_functions.sql +44 -0
  18. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_expressions.py +8 -0
  19. {sqlglot-27.19.0 → sqlglot-27.20.0}/.gitignore +0 -0
  20. {sqlglot-27.19.0 → sqlglot-27.20.0}/.gitpod.yml +0 -0
  21. {sqlglot-27.19.0 → sqlglot-27.20.0}/.pre-commit-config.yaml +0 -0
  22. {sqlglot-27.19.0 → sqlglot-27.20.0}/CONTRIBUTING.md +0 -0
  23. {sqlglot-27.19.0 → sqlglot-27.20.0}/LICENSE +0 -0
  24. {sqlglot-27.19.0 → sqlglot-27.20.0}/MANIFEST.in +0 -0
  25. {sqlglot-27.19.0 → sqlglot-27.20.0}/pyproject.toml +0 -0
  26. {sqlglot-27.19.0 → sqlglot-27.20.0}/setup.cfg +0 -0
  27. {sqlglot-27.19.0 → sqlglot-27.20.0}/setup.py +0 -0
  28. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/__init__.py +0 -0
  29. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/__main__.py +0 -0
  30. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/_typing.py +0 -0
  31. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/__init__.py +0 -0
  32. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/athena.py +0 -0
  33. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/bigquery.py +0 -0
  34. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/clickhouse.py +0 -0
  35. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/databricks.py +0 -0
  36. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/dialect.py +0 -0
  37. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/doris.py +0 -0
  38. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/dremio.py +0 -0
  39. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/drill.py +0 -0
  40. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/druid.py +0 -0
  41. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/duckdb.py +0 -0
  42. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/dune.py +0 -0
  43. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/exasol.py +0 -0
  44. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/fabric.py +0 -0
  45. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/hive.py +0 -0
  46. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/materialize.py +0 -0
  47. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/mysql.py +0 -0
  48. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/oracle.py +0 -0
  49. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/postgres.py +0 -0
  50. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/presto.py +0 -0
  51. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/prql.py +0 -0
  52. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/redshift.py +0 -0
  53. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/risingwave.py +0 -0
  54. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/singlestore.py +0 -0
  55. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/solr.py +0 -0
  56. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/spark.py +0 -0
  57. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/spark2.py +0 -0
  58. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/tableau.py +0 -0
  59. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/teradata.py +0 -0
  60. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/trino.py +0 -0
  61. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/dialects/tsql.py +0 -0
  62. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/diff.py +0 -0
  63. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/errors.py +0 -0
  64. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/executor/__init__.py +0 -0
  65. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/executor/context.py +0 -0
  66. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/executor/env.py +0 -0
  67. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/executor/python.py +0 -0
  68. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/executor/table.py +0 -0
  69. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/jsonpath.py +0 -0
  70. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/lineage.py +0 -0
  71. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/__init__.py +0 -0
  72. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/annotate_types.py +0 -0
  73. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/canonicalize.py +0 -0
  74. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/eliminate_ctes.py +0 -0
  75. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/eliminate_joins.py +0 -0
  76. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/eliminate_subqueries.py +0 -0
  77. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
  78. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/merge_subqueries.py +0 -0
  79. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/normalize.py +0 -0
  80. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
  81. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/optimize_joins.py +0 -0
  82. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/optimizer.py +0 -0
  83. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/pushdown_predicates.py +0 -0
  84. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/pushdown_projections.py +0 -0
  85. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/qualify.py +0 -0
  86. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/qualify_columns.py +0 -0
  87. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/qualify_tables.py +0 -0
  88. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/scope.py +0 -0
  89. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/simplify.py +0 -0
  90. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/optimizer/unnest_subqueries.py +0 -0
  91. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/planner.py +0 -0
  92. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/py.typed +0 -0
  93. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/schema.py +0 -0
  94. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/serde.py +0 -0
  95. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/time.py +0 -0
  96. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/tokens.py +0 -0
  97. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/transforms.py +0 -0
  98. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot/trie.py +0 -0
  99. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot.egg-info/SOURCES.txt +0 -0
  100. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot.egg-info/dependency_links.txt +0 -0
  101. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot.egg-info/requires.txt +0 -0
  102. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot.egg-info/top_level.txt +0 -0
  103. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglot.png +0 -0
  104. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/Cargo.lock +0 -0
  105. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/Cargo.toml +0 -0
  106. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/benches/dialect_settings.json +0 -0
  107. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/benches/long.rs +0 -0
  108. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/benches/token_type_settings.json +0 -0
  109. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/benches/tokenizer_dialect_settings.json +0 -0
  110. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/benches/tokenizer_settings.json +0 -0
  111. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/pyproject.toml +0 -0
  112. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/src/lib.rs +0 -0
  113. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/src/settings.rs +0 -0
  114. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/src/token.rs +0 -0
  115. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/src/tokenizer.rs +0 -0
  116. {sqlglot-27.19.0 → sqlglot-27.20.0}/sqlglotrs/src/trie.rs +0 -0
  117. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/__init__.py +0 -0
  118. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/__init__.py +0 -0
  119. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_athena.py +0 -0
  120. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_bigquery.py +0 -0
  121. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_clickhouse.py +0 -0
  122. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_databricks.py +0 -0
  123. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_dialect.py +0 -0
  124. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_doris.py +0 -0
  125. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_dremio.py +0 -0
  126. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_drill.py +0 -0
  127. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_druid.py +0 -0
  128. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_duckdb.py +0 -0
  129. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_dune.py +0 -0
  130. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_exasol.py +0 -0
  131. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_fabric.py +0 -0
  132. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_hive.py +0 -0
  133. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_materialize.py +0 -0
  134. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_mysql.py +0 -0
  135. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_oracle.py +0 -0
  136. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_pipe_syntax.py +0 -0
  137. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_postgres.py +0 -0
  138. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_presto.py +0 -0
  139. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_prql.py +0 -0
  140. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_redshift.py +0 -0
  141. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_risingwave.py +0 -0
  142. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_singlestore.py +0 -0
  143. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_solr.py +0 -0
  144. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_spark.py +0 -0
  145. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_tableau.py +0 -0
  146. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_teradata.py +0 -0
  147. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_trino.py +0 -0
  148. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/dialects/test_tsql.py +0 -0
  149. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/identity.sql +0 -0
  150. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/jsonpath/LICENSE +0 -0
  151. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/jsonpath/cts.json +0 -0
  152. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/annotate_types.sql +0 -0
  153. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/canonicalize.sql +0 -0
  154. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/eliminate_ctes.sql +0 -0
  155. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/eliminate_joins.sql +0 -0
  156. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/eliminate_subqueries.sql +0 -0
  157. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/isolate_table_selects.sql +0 -0
  158. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/merge_subqueries.sql +0 -0
  159. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/normalize.sql +0 -0
  160. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/normalize_identifiers.sql +0 -0
  161. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/optimize_joins.sql +0 -0
  162. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/optimizer.sql +0 -0
  163. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/pushdown_cte_alias_columns.sql +0 -0
  164. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/pushdown_predicates.sql +0 -0
  165. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/pushdown_projections.sql +0 -0
  166. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/qualify_columns.sql +0 -0
  167. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/qualify_columns__invalid.sql +0 -0
  168. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/qualify_columns__with_invisible.sql +0 -0
  169. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/qualify_columns_ddl.sql +0 -0
  170. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/qualify_tables.sql +0 -0
  171. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/quote_identifiers.sql +0 -0
  172. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/simplify.sql +0 -0
  173. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/call_center.csv.gz +0 -0
  174. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/catalog_page.csv.gz +0 -0
  175. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/catalog_returns.csv.gz +0 -0
  176. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/catalog_sales.csv.gz +0 -0
  177. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/customer.csv.gz +0 -0
  178. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/customer_address.csv.gz +0 -0
  179. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/customer_demographics.csv.gz +0 -0
  180. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/date_dim.csv.gz +0 -0
  181. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/household_demographics.csv.gz +0 -0
  182. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/income_band.csv.gz +0 -0
  183. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/inventory.csv.gz +0 -0
  184. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/item.csv.gz +0 -0
  185. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/promotion.csv.gz +0 -0
  186. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/reason.csv.gz +0 -0
  187. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/ship_mode.csv.gz +0 -0
  188. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/store.csv.gz +0 -0
  189. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/store_returns.csv.gz +0 -0
  190. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/store_sales.csv.gz +0 -0
  191. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/time_dim.csv.gz +0 -0
  192. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/tpc-ds.sql +0 -0
  193. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/warehouse.csv.gz +0 -0
  194. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/web_page.csv.gz +0 -0
  195. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/web_returns.csv.gz +0 -0
  196. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/web_sales.csv.gz +0 -0
  197. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-ds/web_site.csv.gz +0 -0
  198. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-h/customer.csv.gz +0 -0
  199. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-h/lineitem.csv.gz +0 -0
  200. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-h/nation.csv.gz +0 -0
  201. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-h/orders.csv.gz +0 -0
  202. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-h/part.csv.gz +0 -0
  203. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-h/partsupp.csv.gz +0 -0
  204. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-h/region.csv.gz +0 -0
  205. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-h/supplier.csv.gz +0 -0
  206. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/tpc-h/tpc-h.sql +0 -0
  207. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/optimizer/unnest_subqueries.sql +0 -0
  208. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/partial.sql +0 -0
  209. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/fixtures/pretty.sql +0 -0
  210. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/gen_fixtures.py +0 -0
  211. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/helpers.py +0 -0
  212. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_build.py +0 -0
  213. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_dialect_imports.py +0 -0
  214. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_diff.py +0 -0
  215. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_docs.py +0 -0
  216. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_executor.py +0 -0
  217. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_generator.py +0 -0
  218. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_helper.py +0 -0
  219. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_jsonpath.py +0 -0
  220. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_lineage.py +0 -0
  221. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_optimizer.py +0 -0
  222. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_parser.py +0 -0
  223. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_schema.py +0 -0
  224. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_serde.py +0 -0
  225. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_time.py +0 -0
  226. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_tokens.py +0 -0
  227. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_transforms.py +0 -0
  228. {sqlglot-27.19.0 → sqlglot-27.20.0}/tests/test_transpile.py +0 -0
@@ -1,6 +1,46 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ## [v27.19.0] - 2025-09-26
5
+ ### :boom: BREAKING CHANGES
6
+ - due to [`68473ac`](https://github.com/tobymao/sqlglot/commit/68473ac3ec8dc76512dc76819892a1b0324c7ddc) - Annotate type for snowflake PARSE_URL function *(PR [#5962](https://github.com/tobymao/sqlglot/pull/5962) by [@fivetran-amrutabhimsenayachit](https://github.com/fivetran-amrutabhimsenayachit))*:
7
+
8
+ Annotate type for snowflake PARSE_URL function (#5962)
9
+
10
+ - due to [`b015a9d`](https://github.com/tobymao/sqlglot/commit/b015a9d944d0a87069a7750ad74953c399d7da34) - annotate type for Snowflake REGEXP_INSTR function *(commit by [@fivetran-BradfordPaskewitz](https://github.com/fivetran-BradfordPaskewitz))*:
11
+
12
+ annotate type for Snowflake REGEXP_INSTR function
13
+
14
+ - due to [`1f29ba7`](https://github.com/tobymao/sqlglot/commit/1f29ba710f4213beb1a2f993244d7d824f3536ce) - annotate type for Snowflake PARSE_IP function *(PR [#5961](https://github.com/tobymao/sqlglot/pull/5961) by [@fivetran-BradfordPaskewitz](https://github.com/fivetran-BradfordPaskewitz))*:
15
+
16
+ annotate type for Snowflake PARSE_IP function (#5961)
17
+
18
+ - due to [`bf45d5d`](https://github.com/tobymao/sqlglot/commit/bf45d5d3cb0c0f380824019eb32ec29049268a61) - annotate types for Snowflake RTRIMMED_LENGTH function *(PR [#5968](https://github.com/tobymao/sqlglot/pull/5968) by [@fivetran-BradfordPaskewitz](https://github.com/fivetran-BradfordPaskewitz))*:
19
+
20
+ annotate types for Snowflake RTRIMMED_LENGTH function (#5968)
21
+
22
+ - due to [`13caa69`](https://github.com/tobymao/sqlglot/commit/13caa6991f003ad7abb590073451e591b6fd888c) - Annotate type for snowflake POSITION function *(PR [#5964](https://github.com/tobymao/sqlglot/pull/5964) by [@fivetran-amrutabhimsenayachit](https://github.com/fivetran-amrutabhimsenayachit))*:
23
+
24
+ Annotate type for snowflake POSITION function (#5964)
25
+
26
+
27
+ ### :sparkles: New Features
28
+ - [`88e4e4c`](https://github.com/tobymao/sqlglot/commit/88e4e4c55f3a113127eb3c82c0be46c29bcf15ab) - **optimizer**: Annotate type for OCTET_LENGTH function *(PR [#5960](https://github.com/tobymao/sqlglot/pull/5960) by [@fivetran-amrutabhimsenayachit](https://github.com/fivetran-amrutabhimsenayachit))*
29
+ - [`68473ac`](https://github.com/tobymao/sqlglot/commit/68473ac3ec8dc76512dc76819892a1b0324c7ddc) - **optimizer**: Annotate type for snowflake PARSE_URL function *(PR [#5962](https://github.com/tobymao/sqlglot/pull/5962) by [@fivetran-amrutabhimsenayachit](https://github.com/fivetran-amrutabhimsenayachit))*
30
+ - [`b015a9d`](https://github.com/tobymao/sqlglot/commit/b015a9d944d0a87069a7750ad74953c399d7da34) - **optimizer**: annotate type for Snowflake REGEXP_INSTR function *(commit by [@fivetran-BradfordPaskewitz](https://github.com/fivetran-BradfordPaskewitz))*
31
+ - [`1f29ba7`](https://github.com/tobymao/sqlglot/commit/1f29ba710f4213beb1a2f993244d7d824f3536ce) - **optimizer**: annotate type for Snowflake PARSE_IP function *(PR [#5961](https://github.com/tobymao/sqlglot/pull/5961) by [@fivetran-BradfordPaskewitz](https://github.com/fivetran-BradfordPaskewitz))*
32
+ - [`bf45d5d`](https://github.com/tobymao/sqlglot/commit/bf45d5d3cb0c0f380824019eb32ec29049268a61) - **optimizer**: annotate types for Snowflake RTRIMMED_LENGTH function *(PR [#5968](https://github.com/tobymao/sqlglot/pull/5968) by [@fivetran-BradfordPaskewitz](https://github.com/fivetran-BradfordPaskewitz))*
33
+ - [`13caa69`](https://github.com/tobymao/sqlglot/commit/13caa6991f003ad7abb590073451e591b6fd888c) - **optimizer**: Annotate type for snowflake POSITION function *(PR [#5964](https://github.com/tobymao/sqlglot/pull/5964) by [@fivetran-amrutabhimsenayachit](https://github.com/fivetran-amrutabhimsenayachit))*
34
+ - [`1471306`](https://github.com/tobymao/sqlglot/commit/1471306ed317830c294e3654075f55424d14bf5a) - support parse into grant principal and privilege *(PR [#5971](https://github.com/tobymao/sqlglot/pull/5971) by [@eakmanrq](https://github.com/eakmanrq))*
35
+
36
+ ### :bug: Bug Fixes
37
+ - [`5432976`](https://github.com/tobymao/sqlglot/commit/543297680755344185e0f306843bc4909f4f75ed) - **bigquery**: allow GRANT as an id var *(PR [#5965](https://github.com/tobymao/sqlglot/pull/5965) by [@treysp](https://github.com/treysp))*
38
+
39
+ ### :wrench: Chores
40
+ - [`1514bc6`](https://github.com/tobymao/sqlglot/commit/1514bc640ec129a96aedd9e89bfd5d61e832d6b1) - **optimizer**: add type inference tests for Snowflake RPAD function *(PR [#5967](https://github.com/tobymao/sqlglot/pull/5967) by [@fivetran-BradfordPaskewitz](https://github.com/fivetran-BradfordPaskewitz))*
41
+ - [`050b89d`](https://github.com/tobymao/sqlglot/commit/050b89deb9be842f2ddd07c78ea201ec4eae4779) - **optimizer**: Annotate type for snowflake regexp function *(PR [#5970](https://github.com/tobymao/sqlglot/pull/5970) by [@fivetran-amrutabhimsenayachit](https://github.com/fivetran-amrutabhimsenayachit))*
42
+
43
+
4
44
  ## [v27.18.0] - 2025-09-25
5
45
  ### :boom: BREAKING CHANGES
6
46
  - due to [`7f13eaf`](https://github.com/tobymao/sqlglot/commit/7f13eaf7769a3381a56c9209af590835be2f95cd) - Annotate type for snowflake DECOMPRESS_BINARY function *(PR [#5945](https://github.com/tobymao/sqlglot/pull/5945) by [@fivetran-amrutabhimsenayachit](https://github.com/fivetran-amrutabhimsenayachit))*:
@@ -7520,3 +7560,4 @@ Changelog
7520
7560
  [v27.16.3]: https://github.com/tobymao/sqlglot/compare/v27.16.2...v27.16.3
7521
7561
  [v27.17.0]: https://github.com/tobymao/sqlglot/compare/v27.16.3...v27.17.0
7522
7562
  [v27.18.0]: https://github.com/tobymao/sqlglot/compare/v27.17.0...v27.18.0
7563
+ [v27.19.0]: https://github.com/tobymao/sqlglot/compare/v27.18.0...v27.19.0
@@ -1,7 +1,13 @@
1
1
  .PHONY: install install-dev install-pre-commit test unit style check docs docs-serve
2
2
 
3
+ ifdef UV
4
+ PIP := uv pip
5
+ else
6
+ PIP := pip
7
+ endif
8
+
3
9
  install:
4
- pip install -e .
10
+ $(PIP) install -e .
5
11
 
6
12
  bench: install-dev-rs-release
7
13
  python -m benchmarks.bench
@@ -17,7 +23,7 @@ install-dev-rs:
17
23
  cd sqlglotrs/ && python -m maturin develop
18
24
 
19
25
  install-dev-core:
20
- pip install -e ".[dev]"
26
+ $(PIP) install -e ".[dev]"
21
27
 
22
28
  install-dev: install-dev-core install-dev-rs
23
29
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 27.19.0
3
+ Version: 27.20.0
4
4
  Summary: An easily customizable SQL parser and transpiler
5
5
  Author-email: Toby Mao <toby.mao@gmail.com>
6
6
  License-Expression: MIT
@@ -89,12 +89,14 @@ pip3 install "sqlglot[rs]"
89
89
  Or with a local checkout:
90
90
 
91
91
  ```
92
+ # Optionally prefix with UV=1 to use uv for the installation
92
93
  make install
93
94
  ```
94
95
 
95
96
  Requirements for development (optional):
96
97
 
97
98
  ```
99
+ # Optionally prefix with UV=1 to use uv for the installation
98
100
  make install-dev
99
101
  ```
100
102
 
@@ -50,12 +50,14 @@ pip3 install "sqlglot[rs]"
50
50
  Or with a local checkout:
51
51
 
52
52
  ```
53
+ # Optionally prefix with UV=1 to use uv for the installation
53
54
  make install
54
55
  ```
55
56
 
56
57
  Requirements for development (optional):
57
58
 
58
59
  ```
60
+ # Optionally prefix with UV=1 to use uv for the installation
59
61
  make install-dev
60
62
  ```
61
63
 
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '27.19.0'
32
- __version_tuple__ = version_tuple = (27, 19, 0)
31
+ __version__ = version = '27.20.0'
32
+ __version_tuple__ = version_tuple = (27, 20, 0)
33
33
 
34
- __commit_id__ = commit_id = 'g1471306ed'
34
+ __commit_id__ = commit_id = 'g0d772e0b9'
@@ -543,6 +543,7 @@ class Snowflake(Dialect):
543
543
  exp.DataType.Type.VARCHAR: {
544
544
  *Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.VARCHAR],
545
545
  exp.Base64DecodeString,
546
+ exp.TryBase64DecodeString,
546
547
  exp.Base64Encode,
547
548
  exp.DecompressString,
548
549
  exp.MD5,
@@ -553,6 +554,7 @@ class Snowflake(Dialect):
553
554
  exp.Collate,
554
555
  exp.Collation,
555
556
  exp.HexDecodeString,
557
+ exp.TryHexDecodeString,
556
558
  exp.HexEncode,
557
559
  exp.Initcap,
558
560
  exp.RegexpExtract,
@@ -561,12 +563,16 @@ class Snowflake(Dialect):
561
563
  exp.Replace,
562
564
  exp.SHA,
563
565
  exp.SHA2,
566
+ exp.Soundex,
564
567
  exp.Space,
568
+ exp.SplitPart,
565
569
  exp.Uuid,
566
570
  },
567
571
  exp.DataType.Type.BINARY: {
568
572
  *Dialect.TYPE_TO_EXPRESSIONS[exp.DataType.Type.BINARY],
569
573
  exp.Base64DecodeBinary,
574
+ exp.TryBase64DecodeBinary,
575
+ exp.TryHexDecodeBinary,
570
576
  exp.Compress,
571
577
  exp.DecompressBinary,
572
578
  exp.MD5Digest,
@@ -586,6 +592,9 @@ class Snowflake(Dialect):
586
592
  exp.ParseUrl,
587
593
  exp.ParseIp,
588
594
  },
595
+ exp.DataType.Type.DECIMAL: {
596
+ exp.RegexpCount,
597
+ },
589
598
  }
590
599
 
591
600
  ANNOTATORS = {
@@ -607,6 +616,9 @@ class Snowflake(Dialect):
607
616
  },
608
617
  exp.ConcatWs: lambda self, e: self._annotate_by_args(e, "expressions"),
609
618
  exp.Reverse: _annotate_reverse,
619
+ exp.RegexpCount: lambda self, e: self._annotate_with_type(
620
+ e, exp.DataType.build("NUMBER", dialect="snowflake")
621
+ ),
610
622
  }
611
623
 
612
624
  TIME_MAPPING = {
@@ -793,6 +805,7 @@ class Snowflake(Dialect):
793
805
  FUNCTION_PARSERS = {
794
806
  **parser.Parser.FUNCTION_PARSERS,
795
807
  "DATE_PART": lambda self: self._parse_date_part(),
808
+ "DIRECTORY": lambda self: self._parse_directory(),
796
809
  "OBJECT_CONSTRUCT_KEEP_NULL": lambda self: self._parse_json_object(),
797
810
  "LISTAGG": lambda self: self._parse_string_agg(),
798
811
  "SEMANTIC_VIEW": lambda self: self._parse_semantic_view(),
@@ -902,6 +915,14 @@ class Snowflake(Dialect):
902
915
  ),
903
916
  }
904
917
 
918
+ def _parse_directory(self) -> exp.DirectoryStage:
919
+ table = self._parse_table_parts()
920
+
921
+ if isinstance(table, exp.Table):
922
+ table = table.this
923
+
924
+ return self.expression(exp.DirectoryStage, this=table)
925
+
905
926
  def _parse_use(self) -> exp.Use:
906
927
  if self._match_text_seq("SECONDARY", "ROLES"):
907
928
  this = self._match_texts(("ALL", "NONE")) and exp.var(self._prev.text.upper())
@@ -342,3 +342,12 @@ class SQLite(Dialect):
342
342
 
343
343
  def respectnulls_sql(self, expression: exp.RespectNulls) -> str:
344
344
  return self.sql(expression.this)
345
+
346
+ def windowspec_sql(self, expression: exp.WindowSpec) -> str:
347
+ if (
348
+ expression.text("kind").upper() == "RANGE"
349
+ and expression.text("start").upper() == "CURRENT ROW"
350
+ ):
351
+ return "RANGE CURRENT ROW"
352
+
353
+ return super().windowspec_sql(expression)
@@ -32,6 +32,7 @@ def st_distance_sphere(self, expression: exp.StDistance) -> str:
32
32
 
33
33
  class StarRocks(MySQL):
34
34
  STRICT_JSON_PATH_SYNTAX = False
35
+ INDEX_OFFSET = 1
35
36
 
36
37
  class Tokenizer(MySQL.Tokenizer):
37
38
  KEYWORDS = {
@@ -49,6 +50,7 @@ class StarRocks(MySQL):
49
50
  "DATE_DIFF": lambda args: exp.DateDiff(
50
51
  this=seq_get(args, 1), expression=seq_get(args, 2), unit=seq_get(args, 0)
51
52
  ),
53
+ "ARRAY_FLATTEN": exp.Flatten.from_arg_list,
52
54
  "REGEXP": exp.RegexpLike.from_arg_list,
53
55
  }
54
56
 
@@ -152,6 +154,7 @@ class StarRocks(MySQL):
152
154
  exp.DateDiff: lambda self, e: self.func(
153
155
  "DATE_DIFF", unit_to_str(e), e.this, e.expression
154
156
  ),
157
+ exp.Flatten: rename_func("ARRAY_FLATTEN"),
155
158
  exp.JSONExtractScalar: arrow_json_extract_sql,
156
159
  exp.JSONExtract: arrow_json_extract_sql,
157
160
  exp.Property: property_sql,
@@ -120,19 +120,43 @@ class Expression(metaclass=_Expression):
120
120
  def __eq__(self, other) -> bool:
121
121
  return type(self) is type(other) and hash(self) == hash(other)
122
122
 
123
- @property
124
- def hashable_args(self) -> t.Any:
125
- return frozenset(
126
- (k, tuple(_norm_arg(a) for a in v) if type(v) is list else _norm_arg(v))
127
- for k, v in self.args.items()
128
- if not (v is None or v is False or (type(v) is list and not v))
129
- )
130
-
131
123
  def __hash__(self) -> int:
132
- if self._hash is not None:
133
- return self._hash
134
-
135
- return hash((self.__class__, self.hashable_args))
124
+ if self._hash is None:
125
+ nodes = []
126
+ queue = deque([self])
127
+
128
+ while queue:
129
+ node = queue.popleft()
130
+ nodes.append(node)
131
+
132
+ for v in node.iter_expressions():
133
+ if v._hash is None:
134
+ queue.append(v)
135
+
136
+ for node in reversed(nodes):
137
+ hash_ = hash(node.key)
138
+ t = type(node)
139
+
140
+ if t is Literal or t is Identifier:
141
+ for k, v in sorted(node.args.items()):
142
+ if v:
143
+ hash_ = hash((hash_, k, v))
144
+ else:
145
+ for k, v in sorted(node.args.items()):
146
+ t = type(v)
147
+
148
+ if t is list:
149
+ for x in v:
150
+ if x is not None and x is not False:
151
+ hash_ = hash((hash_, k, x.lower() if type(x) is str else x))
152
+ else:
153
+ hash_ = hash((hash_, k))
154
+ elif v is not None and v is not False:
155
+ hash_ = hash((hash_, k, v.lower() if t is str else v))
156
+
157
+ node._hash = hash_
158
+ assert self._hash
159
+ return self._hash
136
160
 
137
161
  def __reduce__(self) -> t.Tuple[t.Callable, t.Tuple[t.List[t.Dict[str, t.Any]]]]:
138
162
  from sqlglot.serde import dump, load
@@ -369,6 +393,12 @@ class Expression(metaclass=_Expression):
369
393
  overwrite: assuming an index is given, this determines whether to overwrite the
370
394
  list entry instead of only inserting a new value (i.e., like list.insert).
371
395
  """
396
+ expression: t.Optional[Expression] = self
397
+
398
+ while expression and expression._hash is not None:
399
+ expression._hash = None
400
+ expression = expression.parent
401
+
372
402
  if index is not None:
373
403
  expressions = self.args.get(arg_key) or []
374
404
 
@@ -2235,10 +2265,14 @@ class Prior(Expression):
2235
2265
 
2236
2266
 
2237
2267
  class Directory(Expression):
2238
- # https://spark.apache.org/docs/3.0.0-preview/sql-ref-syntax-dml-insert-overwrite-directory-hive.html
2239
2268
  arg_types = {"this": True, "local": False, "row_format": False}
2240
2269
 
2241
2270
 
2271
+ # https://docs.snowflake.com/en/user-guide/data-load-dirtables-query
2272
+ class DirectoryStage(Expression):
2273
+ pass
2274
+
2275
+
2242
2276
  class ForeignKey(Expression):
2243
2277
  arg_types = {
2244
2278
  "expressions": False,
@@ -2298,10 +2332,6 @@ class Identifier(Expression):
2298
2332
  def quoted(self) -> bool:
2299
2333
  return bool(self.args.get("quoted"))
2300
2334
 
2301
- @property
2302
- def hashable_args(self) -> t.Any:
2303
- return (self.this, self.quoted)
2304
-
2305
2335
  @property
2306
2336
  def output_name(self) -> str:
2307
2337
  return self.name
@@ -2536,10 +2566,6 @@ class LimitOptions(Expression):
2536
2566
  class Literal(Condition):
2537
2567
  arg_types = {"this": True, "is_string": True}
2538
2568
 
2539
- @property
2540
- def hashable_args(self) -> t.Any:
2541
- return (self.this, self.args.get("is_string"))
2542
-
2543
2569
  @classmethod
2544
2570
  def number(cls, number) -> Literal:
2545
2571
  return cls(this=str(number), is_string=False)
@@ -6427,14 +6453,36 @@ class Base64DecodeBinary(Func):
6427
6453
  arg_types = {"this": True, "alphabet": False}
6428
6454
 
6429
6455
 
6456
+ # https://docs.snowflake.com/en/sql-reference/functions/base64_decode_string
6430
6457
  class Base64DecodeString(Func):
6431
6458
  arg_types = {"this": True, "alphabet": False}
6432
6459
 
6433
6460
 
6461
+ # https://docs.snowflake.com/en/sql-reference/functions/base64_encode
6434
6462
  class Base64Encode(Func):
6435
6463
  arg_types = {"this": True, "max_line_length": False, "alphabet": False}
6436
6464
 
6437
6465
 
6466
+ # https://docs.snowflake.com/en/sql-reference/functions/try_base64_decode_binary
6467
+ class TryBase64DecodeBinary(Func):
6468
+ arg_types = {"this": True, "alphabet": False}
6469
+
6470
+
6471
+ # https://docs.snowflake.com/en/sql-reference/functions/try_base64_decode_string
6472
+ class TryBase64DecodeString(Func):
6473
+ arg_types = {"this": True, "alphabet": False}
6474
+
6475
+
6476
+ # https://docs.snowflake.com/en/sql-reference/functions/try_hex_decode_binary
6477
+ class TryHexDecodeBinary(Func):
6478
+ pass
6479
+
6480
+
6481
+ # https://docs.snowflake.com/en/sql-reference/functions/try_hex_decode_string
6482
+ class TryHexDecodeString(Func):
6483
+ pass
6484
+
6485
+
6438
6486
  # https://trino.io/docs/current/functions/datetime.html#from_iso8601_timestamp
6439
6487
  class FromISO8601Timestamp(Func):
6440
6488
  _sql_names = ["FROM_ISO8601_TIMESTAMP"]
@@ -7249,6 +7297,15 @@ class RegexpSplit(Func):
7249
7297
  arg_types = {"this": True, "expression": True, "limit": False}
7250
7298
 
7251
7299
 
7300
+ class RegexpCount(Func):
7301
+ arg_types = {
7302
+ "this": True,
7303
+ "expression": True,
7304
+ "position": False,
7305
+ "parameters": False,
7306
+ }
7307
+
7308
+
7252
7309
  class Repeat(Func):
7253
7310
  arg_types = {"this": True, "times": True}
7254
7311
 
@@ -7712,10 +7769,6 @@ class TableColumn(Expression):
7712
7769
  pass
7713
7770
 
7714
7771
 
7715
- def _norm_arg(arg):
7716
- return arg.lower() if type(arg) is str else arg
7717
-
7718
-
7719
7772
  ALL_FUNCTIONS = subclasses(__name__, Func, (AggFunc, Anonymous, Func))
7720
7773
  FUNCTION_BY_NAME = {name: func for func in ALL_FUNCTIONS for name in func.sql_names()}
7721
7774
 
@@ -5334,3 +5334,6 @@ class Generator(metaclass=_Generator):
5334
5334
  def modelattribute_sql(self, expression: exp.ModelAttribute) -> str:
5335
5335
  self.unsupported("The model!attribute syntax is not supported")
5336
5336
  return ""
5337
+
5338
+ def directorystage_sql(self, expression: exp.DirectoryStage) -> str:
5339
+ return self.func("DIRECTORY", expression.this)
@@ -226,31 +226,13 @@ def while_changing(expression: Expression, func: t.Callable[[Expression], E]) ->
226
226
  Returns:
227
227
  The transformed expression.
228
228
  """
229
- end_hash: t.Optional[int] = None
230
229
 
231
230
  while True:
232
- # No need to walk the AST– we've already cached the hashes in the previous iteration
233
- if end_hash is None:
234
- for n in reversed(tuple(expression.walk())):
235
- n._hash = hash(n)
236
-
237
231
  start_hash = hash(expression)
238
232
  expression = func(expression)
239
-
240
- expression_nodes = tuple(expression.walk())
241
-
242
- # Uncache previous caches so we can recompute them
243
- for n in reversed(expression_nodes):
244
- n._hash = None
245
- n._hash = hash(n)
246
-
247
233
  end_hash = hash(expression)
248
234
 
249
235
  if start_hash == end_hash:
250
- # ... and reset the hash so we don't risk it becoming out of date if a mutation happens
251
- for n in expression_nodes:
252
- n._hash = None
253
-
254
236
  break
255
237
 
256
238
  return expression
@@ -1411,7 +1411,7 @@ class Parser(metaclass=_Parser):
1411
1411
 
1412
1412
  VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1413
1413
 
1414
- WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1414
+ WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.RANGE, TokenType.ROWS}
1415
1415
  WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1416
1416
  WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1417
1417
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 27.19.0
3
+ Version: 27.20.0
4
4
  Summary: An easily customizable SQL parser and transpiler
5
5
  Author-email: Toby Mao <toby.mao@gmail.com>
6
6
  License-Expression: MIT
@@ -89,12 +89,14 @@ pip3 install "sqlglot[rs]"
89
89
  Or with a local checkout:
90
90
 
91
91
  ```
92
+ # Optionally prefix with UV=1 to use uv for the installation
92
93
  make install
93
94
  ```
94
95
 
95
96
  Requirements for development (optional):
96
97
 
97
98
  ```
99
+ # Optionally prefix with UV=1 to use uv for the installation
98
100
  make install-dev
99
101
  ```
100
102
 
@@ -44,7 +44,9 @@ class TestSnowflake(Validator):
44
44
  self.validate_identity("SELECT LPAD(tbl.bin_col, 10)")
45
45
  self.validate_identity("SELECT RPAD('Hello', 10, '*')")
46
46
  self.validate_identity("SELECT RPAD(tbl.bin_col, 10)")
47
+ self.validate_identity("SELECT SOUNDEX(column_name)")
47
48
  self.validate_identity("SELECT JAROWINKLER_SIMILARITY('hello', 'world')")
49
+ self.validate_identity("SELECT SPLIT_PART('11.22.33', '.', 1)")
48
50
  self.validate_identity("PARSE_URL('https://example.com/path')")
49
51
  self.validate_identity("PARSE_URL('https://example.com/path', 1)")
50
52
  self.validate_identity("SELECT {*} FROM my_table")
@@ -121,6 +123,9 @@ class TestSnowflake(Validator):
121
123
  self.validate_identity("SELECT GET_PATH(foo, 'bar')")
122
124
  self.validate_identity("SELECT a, exclude, b FROM xxx")
123
125
  self.validate_identity("SELECT ARRAY_SORT(x, TRUE, FALSE)")
126
+ self.validate_identity("SELECT FILE_URL FROM DIRECTORY(@mystage) WHERE SIZE > 100000").args[
127
+ "from"
128
+ ].this.this.assert_is(exp.DirectoryStage).this.assert_is(exp.Var)
124
129
  self.validate_identity(
125
130
  "SELECT AI_CLASSIFY('text', ['travel', 'cooking'], OBJECT_CONSTRUCT('output_mode', 'multi'))"
126
131
  )
@@ -1392,6 +1397,20 @@ class TestSnowflake(Validator):
1392
1397
  "SELECT BASE64_ENCODE('Hello World', 76, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')"
1393
1398
  )
1394
1399
 
1400
+ self.validate_identity("SELECT TRY_BASE64_DECODE_BINARY('SGVsbG8=')")
1401
+ self.validate_identity(
1402
+ "SELECT TRY_BASE64_DECODE_BINARY('SGVsbG8=', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')"
1403
+ )
1404
+
1405
+ self.validate_identity("SELECT TRY_BASE64_DECODE_STRING('SGVsbG8gV29ybGQ=')")
1406
+ self.validate_identity(
1407
+ "SELECT TRY_BASE64_DECODE_STRING('SGVsbG8gV29ybGQ=', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')"
1408
+ )
1409
+
1410
+ self.validate_identity("SELECT TRY_HEX_DECODE_BINARY('48656C6C6F')")
1411
+
1412
+ self.validate_identity("SELECT TRY_HEX_DECODE_STRING('48656C6C6F')")
1413
+
1395
1414
  def test_null_treatment(self):
1396
1415
  self.validate_all(
1397
1416
  r"SELECT FIRST_VALUE(TABLE1.COLUMN1) OVER (PARTITION BY RANDOM_COLUMN1, RANDOM_COLUMN2 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS MY_ALIAS FROM TABLE1",
@@ -2407,6 +2426,10 @@ FROM persons AS p, LATERAL FLATTEN(input => p.c, path => 'contact') AS _flattene
2407
2426
  "REGEXP_EXTRACT_ALL(subject, pattern)",
2408
2427
  )
2409
2428
 
2429
+ self.validate_identity("SELECT REGEXP_COUNT('hello world', 'l')")
2430
+ self.validate_identity("SELECT REGEXP_COUNT('hello world', 'l', 1)")
2431
+ self.validate_identity("SELECT REGEXP_COUNT('hello world', 'l', 1, 'i')")
2432
+
2410
2433
  @mock.patch("sqlglot.generator.logger")
2411
2434
  def test_regexp_replace(self, logger):
2412
2435
  self.validate_all(
@@ -7,6 +7,7 @@ class TestSQLite(Validator):
7
7
  dialect = "sqlite"
8
8
 
9
9
  def test_sqlite(self):
10
+ self.validate_identity("SELECT RANK() OVER (RANGE CURRENT ROW) FROM tbl")
10
11
  self.validate_identity("UNHEX(a, b)")
11
12
  self.validate_identity("SELECT DATE()")
12
13
  self.validate_identity("SELECT DATE('now', 'start of month', '+1 month', '-1 day')")
@@ -1,3 +1,4 @@
1
+ from sqlglot import exp
1
2
  from sqlglot.errors import UnsupportedError
2
3
  from tests.dialects.test_dialect import Validator
3
4
 
@@ -12,6 +13,8 @@ class TestStarrocks(Validator):
12
13
  self.validate_identity("SELECT ARRAY_AGG(a) FROM x")
13
14
  self.validate_identity("SELECT ST_POINT(10, 20)")
14
15
  self.validate_identity("SELECT ST_DISTANCE_SPHERE(10.1, 20.2, 30.3, 40.4)")
16
+ self.validate_identity("ARRAY_FLATTEN(arr)").assert_is(exp.Flatten)
17
+ self.assertEqual(self.validate_identity("arr[1]").expressions[0], exp.Literal.number(0))
15
18
 
16
19
  def test_ddl(self):
17
20
  self.validate_identity("CREATE TABLE t (c INT) COMMENT 'c'")
@@ -1883,6 +1883,18 @@ BOOLEAN;
1883
1883
  REGEXP_LIKE('foo', NULL, 'baz');
1884
1884
  BOOLEAN;
1885
1885
 
1886
+ # dialect: snowflake
1887
+ REGEXP_COUNT('hello world', 'l');
1888
+ DECIMAL(38, 0);
1889
+
1890
+ # dialect: snowflake
1891
+ REGEXP_COUNT('hello world', 'l', 1);
1892
+ DECIMAL(38, 0);
1893
+
1894
+ # dialect: snowflake
1895
+ REGEXP_COUNT('hello world', 'l', 1, 'i');
1896
+ DECIMAL(38, 0);
1897
+
1886
1898
  # dialect: snowflake
1887
1899
  REGEXP_REPLACE('hello world', 'world', 'universe');
1888
1900
  VARCHAR;
@@ -2067,6 +2079,10 @@ VARCHAR;
2067
2079
  SHA2_HEX('foo', null);
2068
2080
  VARCHAR;
2069
2081
 
2082
+ # dialect: snowflake
2083
+ SOUNDEX(tbl.str_col);
2084
+ VARCHAR;
2085
+
2070
2086
  # dialect: snowflake
2071
2087
  SPACE(5);
2072
2088
  VARCHAR;
@@ -2091,6 +2107,10 @@ ARRAY;
2091
2107
  SPLIT(NULL, ',');
2092
2108
  ARRAY;
2093
2109
 
2110
+ # dialect: snowflake
2111
+ SPLIT_PART('11.22.33', '.', 1);
2112
+ VARCHAR;
2113
+
2094
2114
  # dialect: snowflake
2095
2115
  STARTSWITH('hello world', 'hello');
2096
2116
  BOOLEAN;
@@ -2143,6 +2163,30 @@ VARCHAR;
2143
2163
  TRIM(NULL);
2144
2164
  VARCHAR;
2145
2165
 
2166
+ # dialect: snowflake
2167
+ TRY_BASE64_DECODE_BINARY('SGVsbG8=');
2168
+ BINARY;
2169
+
2170
+ # dialect: snowflake
2171
+ TRY_BASE64_DECODE_BINARY('SGVsbG8=', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
2172
+ BINARY;
2173
+
2174
+ # dialect: snowflake
2175
+ TRY_BASE64_DECODE_STRING('SGVsbG8gV29ybGQ=');
2176
+ VARCHAR;
2177
+
2178
+ # dialect: snowflake
2179
+ TRY_BASE64_DECODE_STRING('SGVsbG8gV29ybGQ=', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
2180
+ VARCHAR;
2181
+
2182
+ # dialect: snowflake
2183
+ TRY_HEX_DECODE_BINARY('48656C6C6F');
2184
+ BINARY;
2185
+
2186
+ # dialect: snowflake
2187
+ TRY_HEX_DECODE_STRING('48656C6C6F');
2188
+ VARCHAR;
2189
+
2146
2190
  # dialect: snowflake
2147
2191
  UPPER('Hello, world!');
2148
2192
  VARCHAR;
@@ -73,6 +73,10 @@ class TestExpressions(unittest.TestCase):
73
73
  self.assertEqual(
74
74
  exp.DataType.build("int"), exp.DataType(this=exp.DataType.Type.INT, nested=False)
75
75
  )
76
+ self.assertNotEqual(
77
+ exp.Identifier(this="a", temporary=True),
78
+ exp.Identifier(this="a"),
79
+ )
76
80
 
77
81
  def test_find(self):
78
82
  expression = parse_one("CREATE TABLE x STORED AS PARQUET AS SELECT * FROM y")
@@ -1262,3 +1266,7 @@ FROM foo""",
1262
1266
 
1263
1267
  self.assertIsInstance(result, exp.TsOrDsToTime)
1264
1268
  self.assertEqual(result.sql(), "CAST('12:00:00' AS TIME)")
1269
+
1270
+ def test_hash_large_ast(self):
1271
+ expr = parse_one("SELECT 1 UNION ALL " * 3000 + "SELECT 1")
1272
+ assert expr == expr
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes