sqlglot 26.27.1__tar.gz → 26.29.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 (217) hide show
  1. {sqlglot-26.27.1 → sqlglot-26.29.0}/CHANGELOG.md +62 -0
  2. {sqlglot-26.27.1 → sqlglot-26.29.0}/PKG-INFO +1 -1
  3. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/_version.py +2 -2
  4. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/athena.py +1 -0
  5. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/dialect.py +4 -1
  6. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/duckdb.py +7 -0
  7. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/snowflake.py +38 -1
  8. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/tsql.py +2 -2
  9. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/expressions.py +9 -2
  10. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/generator.py +20 -3
  11. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/annotate_types.py +44 -1
  12. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/qualify_columns.py +7 -0
  13. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/scope.py +19 -3
  14. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/parser.py +194 -96
  15. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot.egg-info/PKG-INFO +1 -1
  16. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot.egg-info/SOURCES.txt +1 -0
  17. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_athena.py +4 -0
  18. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_dialect.py +0 -219
  19. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_duckdb.py +22 -1
  20. sqlglot-26.29.0/tests/dialects/test_pipe_syntax.py +452 -0
  21. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_snowflake.py +38 -1
  22. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_tsql.py +4 -0
  23. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/qualify_columns.sql +5 -0
  24. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_optimizer.py +37 -0
  25. {sqlglot-26.27.1 → sqlglot-26.29.0}/.gitignore +0 -0
  26. {sqlglot-26.27.1 → sqlglot-26.29.0}/.gitpod.yml +0 -0
  27. {sqlglot-26.27.1 → sqlglot-26.29.0}/.pre-commit-config.yaml +0 -0
  28. {sqlglot-26.27.1 → sqlglot-26.29.0}/CONTRIBUTING.md +0 -0
  29. {sqlglot-26.27.1 → sqlglot-26.29.0}/LICENSE +0 -0
  30. {sqlglot-26.27.1 → sqlglot-26.29.0}/MANIFEST.in +0 -0
  31. {sqlglot-26.27.1 → sqlglot-26.29.0}/Makefile +0 -0
  32. {sqlglot-26.27.1 → sqlglot-26.29.0}/README.md +0 -0
  33. {sqlglot-26.27.1 → sqlglot-26.29.0}/pyproject.toml +0 -0
  34. {sqlglot-26.27.1 → sqlglot-26.29.0}/setup.cfg +0 -0
  35. {sqlglot-26.27.1 → sqlglot-26.29.0}/setup.py +0 -0
  36. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/__init__.py +0 -0
  37. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/__main__.py +0 -0
  38. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/_typing.py +0 -0
  39. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/__init__.py +0 -0
  40. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/bigquery.py +0 -0
  41. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/clickhouse.py +0 -0
  42. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/databricks.py +0 -0
  43. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/doris.py +0 -0
  44. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/drill.py +0 -0
  45. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/druid.py +0 -0
  46. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/dune.py +0 -0
  47. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/hive.py +0 -0
  48. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/materialize.py +0 -0
  49. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/mysql.py +0 -0
  50. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/oracle.py +0 -0
  51. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/postgres.py +0 -0
  52. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/presto.py +0 -0
  53. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/prql.py +0 -0
  54. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/redshift.py +0 -0
  55. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/risingwave.py +0 -0
  56. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/spark.py +0 -0
  57. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/spark2.py +0 -0
  58. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/sqlite.py +0 -0
  59. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/starrocks.py +0 -0
  60. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/tableau.py +0 -0
  61. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/teradata.py +0 -0
  62. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/dialects/trino.py +0 -0
  63. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/diff.py +0 -0
  64. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/errors.py +0 -0
  65. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/executor/__init__.py +0 -0
  66. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/executor/context.py +0 -0
  67. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/executor/env.py +0 -0
  68. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/executor/python.py +0 -0
  69. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/executor/table.py +0 -0
  70. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/helper.py +0 -0
  71. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/jsonpath.py +0 -0
  72. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/lineage.py +0 -0
  73. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/__init__.py +0 -0
  74. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/canonicalize.py +0 -0
  75. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/eliminate_ctes.py +0 -0
  76. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/eliminate_joins.py +0 -0
  77. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/eliminate_subqueries.py +0 -0
  78. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
  79. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/merge_subqueries.py +0 -0
  80. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/normalize.py +0 -0
  81. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
  82. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/optimize_joins.py +0 -0
  83. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/optimizer.py +0 -0
  84. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/pushdown_predicates.py +0 -0
  85. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/pushdown_projections.py +0 -0
  86. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/qualify.py +0 -0
  87. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/qualify_tables.py +0 -0
  88. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/simplify.py +0 -0
  89. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/optimizer/unnest_subqueries.py +0 -0
  90. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/planner.py +0 -0
  91. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/py.typed +0 -0
  92. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/schema.py +0 -0
  93. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/serde.py +0 -0
  94. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/time.py +0 -0
  95. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/tokens.py +0 -0
  96. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/transforms.py +0 -0
  97. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot/trie.py +0 -0
  98. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot.egg-info/dependency_links.txt +0 -0
  99. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot.egg-info/requires.txt +0 -0
  100. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot.egg-info/top_level.txt +0 -0
  101. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglot.png +0 -0
  102. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/Cargo.lock +0 -0
  103. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/Cargo.toml +0 -0
  104. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/benches/dialect_settings.json +0 -0
  105. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/benches/long.rs +0 -0
  106. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/benches/token_type_settings.json +0 -0
  107. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/benches/tokenizer_dialect_settings.json +0 -0
  108. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/benches/tokenizer_settings.json +0 -0
  109. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/pyproject.toml +0 -0
  110. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/src/lib.rs +0 -0
  111. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/src/settings.rs +0 -0
  112. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/src/token.rs +0 -0
  113. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/src/tokenizer.rs +0 -0
  114. {sqlglot-26.27.1 → sqlglot-26.29.0}/sqlglotrs/src/trie.rs +0 -0
  115. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/__init__.py +0 -0
  116. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/__init__.py +0 -0
  117. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_bigquery.py +0 -0
  118. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_clickhouse.py +0 -0
  119. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_databricks.py +0 -0
  120. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_doris.py +0 -0
  121. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_drill.py +0 -0
  122. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_druid.py +0 -0
  123. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_dune.py +0 -0
  124. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_hive.py +0 -0
  125. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_materialize.py +0 -0
  126. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_mysql.py +0 -0
  127. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_oracle.py +0 -0
  128. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_postgres.py +0 -0
  129. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_presto.py +0 -0
  130. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_prql.py +0 -0
  131. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_redshift.py +0 -0
  132. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_risingwave.py +0 -0
  133. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_spark.py +0 -0
  134. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_sqlite.py +0 -0
  135. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_starrocks.py +0 -0
  136. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_tableau.py +0 -0
  137. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_teradata.py +0 -0
  138. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/dialects/test_trino.py +0 -0
  139. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/identity.sql +0 -0
  140. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/jsonpath/LICENSE +0 -0
  141. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/jsonpath/cts.json +0 -0
  142. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/annotate_functions.sql +0 -0
  143. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/annotate_types.sql +0 -0
  144. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/canonicalize.sql +0 -0
  145. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/eliminate_ctes.sql +0 -0
  146. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/eliminate_joins.sql +0 -0
  147. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/eliminate_subqueries.sql +0 -0
  148. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/isolate_table_selects.sql +0 -0
  149. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/merge_subqueries.sql +0 -0
  150. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/normalize.sql +0 -0
  151. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/normalize_identifiers.sql +0 -0
  152. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/optimize_joins.sql +0 -0
  153. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/optimizer.sql +0 -0
  154. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/pushdown_cte_alias_columns.sql +0 -0
  155. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/pushdown_predicates.sql +0 -0
  156. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/pushdown_projections.sql +0 -0
  157. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/qualify_columns__invalid.sql +0 -0
  158. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/qualify_columns__with_invisible.sql +0 -0
  159. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/qualify_columns_ddl.sql +0 -0
  160. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/qualify_tables.sql +0 -0
  161. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/quote_identifiers.sql +0 -0
  162. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/simplify.sql +0 -0
  163. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/call_center.csv.gz +0 -0
  164. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/catalog_page.csv.gz +0 -0
  165. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/catalog_returns.csv.gz +0 -0
  166. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/catalog_sales.csv.gz +0 -0
  167. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/customer.csv.gz +0 -0
  168. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/customer_address.csv.gz +0 -0
  169. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/customer_demographics.csv.gz +0 -0
  170. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/date_dim.csv.gz +0 -0
  171. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/household_demographics.csv.gz +0 -0
  172. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/income_band.csv.gz +0 -0
  173. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/inventory.csv.gz +0 -0
  174. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/item.csv.gz +0 -0
  175. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/promotion.csv.gz +0 -0
  176. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/reason.csv.gz +0 -0
  177. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/ship_mode.csv.gz +0 -0
  178. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/store.csv.gz +0 -0
  179. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/store_returns.csv.gz +0 -0
  180. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/store_sales.csv.gz +0 -0
  181. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/time_dim.csv.gz +0 -0
  182. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/tpc-ds.sql +0 -0
  183. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/warehouse.csv.gz +0 -0
  184. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/web_page.csv.gz +0 -0
  185. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/web_returns.csv.gz +0 -0
  186. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/web_sales.csv.gz +0 -0
  187. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-ds/web_site.csv.gz +0 -0
  188. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-h/customer.csv.gz +0 -0
  189. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-h/lineitem.csv.gz +0 -0
  190. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-h/nation.csv.gz +0 -0
  191. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-h/orders.csv.gz +0 -0
  192. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-h/part.csv.gz +0 -0
  193. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-h/partsupp.csv.gz +0 -0
  194. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-h/region.csv.gz +0 -0
  195. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-h/supplier.csv.gz +0 -0
  196. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/tpc-h/tpc-h.sql +0 -0
  197. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/optimizer/unnest_subqueries.sql +0 -0
  198. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/partial.sql +0 -0
  199. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/fixtures/pretty.sql +0 -0
  200. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/gen_fixtures.py +0 -0
  201. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/helpers.py +0 -0
  202. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_build.py +0 -0
  203. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_diff.py +0 -0
  204. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_docs.py +0 -0
  205. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_executor.py +0 -0
  206. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_expressions.py +0 -0
  207. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_generator.py +0 -0
  208. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_helper.py +0 -0
  209. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_jsonpath.py +0 -0
  210. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_lineage.py +0 -0
  211. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_parser.py +0 -0
  212. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_schema.py +0 -0
  213. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_serde.py +0 -0
  214. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_time.py +0 -0
  215. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_tokens.py +0 -0
  216. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_transforms.py +0 -0
  217. {sqlglot-26.27.1 → sqlglot-26.29.0}/tests/test_transpile.py +0 -0
@@ -1,6 +1,66 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ## [v26.28.1] - 2025-06-13
5
+ ### :boom: BREAKING CHANGES
6
+ - due to [`44297f1`](https://github.com/tobymao/sqlglot/commit/44297f1c5c8c2cb16fe77c318312f417b4281708) - JOIN pipe syntax, Set Operators as CTEs *(PR [#5215](https://github.com/tobymao/sqlglot/pull/5215) by [@geooo109](https://github.com/geooo109))*:
7
+
8
+ JOIN pipe syntax, Set Operators as CTEs (#5215)
9
+
10
+
11
+ ### :sparkles: New Features
12
+ - [`44297f1`](https://github.com/tobymao/sqlglot/commit/44297f1c5c8c2cb16fe77c318312f417b4281708) - **parser**: JOIN pipe syntax, Set Operators as CTEs *(PR [#5215](https://github.com/tobymao/sqlglot/pull/5215) by [@geooo109](https://github.com/geooo109))*
13
+ - [`21cd3eb`](https://github.com/tobymao/sqlglot/commit/21cd3ebf5d0b57f5b102c5aadc3b24a598ebe918) - **parser**: PIVOT/UNPIVOT pipe syntax *(PR [#5222](https://github.com/tobymao/sqlglot/pull/5222) by [@geooo109](https://github.com/geooo109))*
14
+
15
+ ### :bug: Bug Fixes
16
+ - [`28fed58`](https://github.com/tobymao/sqlglot/commit/28fed586a39df83aade4792217743a1a859fd039) - **optimizer**: UnboundLocalError in scope module *(commit by [@georgesittas](https://github.com/georgesittas))*
17
+ - [`809e05a`](https://github.com/tobymao/sqlglot/commit/809e05a743d5a2904a1d6f6813f24ca7549ac7ef) - **snowflake**: preserve STRTOK_TO_ARRAY roundtrip *(commit by [@georgesittas](https://github.com/georgesittas))*
18
+
19
+ ### :recycle: Refactors
20
+ - [`aac70aa`](https://github.com/tobymao/sqlglot/commit/aac70aaaa8d840c267129e2307ccb65058cef0c9) - **parser**: simpler _parse_pipe_syntax_select *(commit by [@geooo109](https://github.com/geooo109))*
21
+
22
+
23
+ ## [v26.27.0] - 2025-06-12
24
+ ### :boom: BREAKING CHANGES
25
+ - due to [`ac6555b`](https://github.com/tobymao/sqlglot/commit/ac6555b4d6c162ef7b14b63307d01fd560138ea0) - preserve DIV binary operator, fixes [#5198](https://github.com/tobymao/sqlglot/pull/5198) *(PR [#5199](https://github.com/tobymao/sqlglot/pull/5199) by [@georgesittas](https://github.com/georgesittas))*:
26
+
27
+ preserve DIV binary operator, fixes #5198 (#5199)
28
+
29
+ - due to [`dfdd84b`](https://github.com/tobymao/sqlglot/commit/dfdd84bbc50da70f40a17b39935f8171d961f7d2) - CTEs instead of subqueries for pipe syntax *(PR [#5205](https://github.com/tobymao/sqlglot/pull/5205) by [@geooo109](https://github.com/geooo109))*:
30
+
31
+ CTEs instead of subqueries for pipe syntax (#5205)
32
+
33
+ - due to [`5f95299`](https://github.com/tobymao/sqlglot/commit/5f9529940d83e89704f7d25eda63cd73fdb503ae) - support multi-part (>3) dotted functions *(PR [#5211](https://github.com/tobymao/sqlglot/pull/5211) by [@georgesittas](https://github.com/georgesittas))*:
34
+
35
+ support multi-part (>3) dotted functions (#5211)
36
+
37
+ - due to [`02afa2a`](https://github.com/tobymao/sqlglot/commit/02afa2a1941fc67086d50dffac2857262f1c3c4f) - Preserve quoting for UDT *(PR [#5216](https://github.com/tobymao/sqlglot/pull/5216) by [@VaggelisD](https://github.com/VaggelisD))*:
38
+
39
+ Preserve quoting for UDT (#5216)
40
+
41
+
42
+ ### :sparkles: New Features
43
+ - [`c20f85e`](https://github.com/tobymao/sqlglot/commit/c20f85e3e171e502fc51f74894d3313f0ad61535) - **spark**: support ALTER ADD PARTITION *(PR [#5208](https://github.com/tobymao/sqlglot/pull/5208) by [@georgesittas](https://github.com/georgesittas))*
44
+ - :arrow_lower_right: *addresses issue [#5204](https://github.com/tobymao/sqlglot/issues/5204) opened by [@cosinequanon](https://github.com/cosinequanon)*
45
+
46
+ ### :bug: Bug Fixes
47
+ - [`99bbae3`](https://github.com/tobymao/sqlglot/commit/99bbae370329c5f5cd132b711c714359cf96ba58) - **sqlite**: allow ALTER RENAME without COLUMN keyword fixes [#5195](https://github.com/tobymao/sqlglot/pull/5195) *(commit by [@georgesittas](https://github.com/georgesittas))*
48
+ - [`ac6555b`](https://github.com/tobymao/sqlglot/commit/ac6555b4d6c162ef7b14b63307d01fd560138ea0) - **hive**: preserve DIV binary operator, fixes [#5198](https://github.com/tobymao/sqlglot/pull/5198) *(PR [#5199](https://github.com/tobymao/sqlglot/pull/5199) by [@georgesittas](https://github.com/georgesittas))*
49
+ - [`d0eeb26`](https://github.com/tobymao/sqlglot/commit/d0eeb2639e771e8f8b6feabd41c65f16ed5a9829) - eliminate_join_marks has multiple issues fixes [#5188](https://github.com/tobymao/sqlglot/pull/5188) *(PR [#5189](https://github.com/tobymao/sqlglot/pull/5189) by [@snovik75](https://github.com/snovik75))*
50
+ - :arrow_lower_right: *fixes issue [#5188](https://github.com/tobymao/sqlglot/issues/5188) opened by [@snovik75](https://github.com/snovik75)*
51
+ - [`dfdd84b`](https://github.com/tobymao/sqlglot/commit/dfdd84bbc50da70f40a17b39935f8171d961f7d2) - **parser**: CTEs instead of subqueries for pipe syntax *(PR [#5205](https://github.com/tobymao/sqlglot/pull/5205) by [@geooo109](https://github.com/geooo109))*
52
+ - [`77e9d9a`](https://github.com/tobymao/sqlglot/commit/77e9d9a0269e2013379967cf2f46fbd79c036277) - **mysql**: properly parse STORED/VIRTUAL computed columns *(PR [#5210](https://github.com/tobymao/sqlglot/pull/5210) by [@georgesittas](https://github.com/georgesittas))*
53
+ - :arrow_lower_right: *fixes issue [#5203](https://github.com/tobymao/sqlglot/issues/5203) opened by [@mdebski](https://github.com/mdebski)*
54
+ - [`5f95299`](https://github.com/tobymao/sqlglot/commit/5f9529940d83e89704f7d25eda63cd73fdb503ae) - **parser**: support multi-part (>3) dotted functions *(PR [#5211](https://github.com/tobymao/sqlglot/pull/5211) by [@georgesittas](https://github.com/georgesittas))*
55
+ - :arrow_lower_right: *fixes issue [#5200](https://github.com/tobymao/sqlglot/issues/5200) opened by [@mateuszpoleski](https://github.com/mateuszpoleski)*
56
+ - [`02afa2a`](https://github.com/tobymao/sqlglot/commit/02afa2a1941fc67086d50dffac2857262f1c3c4f) - **postgres**: Preserve quoting for UDT *(PR [#5216](https://github.com/tobymao/sqlglot/pull/5216) by [@VaggelisD](https://github.com/VaggelisD))*
57
+ - :arrow_lower_right: *fixes issue [#5212](https://github.com/tobymao/sqlglot/issues/5212) opened by [@NickCrews](https://github.com/NickCrews)*
58
+ - [`f37c0b1`](https://github.com/tobymao/sqlglot/commit/f37c0b1197321dd610648ce652a171ab063deeeb) - **snowflake**: ensure a standalone GET() expression can be parsed *(PR [#5219](https://github.com/tobymao/sqlglot/pull/5219) by [@georgesittas](https://github.com/georgesittas))*
59
+
60
+ ### :wrench: Chores
61
+ - [`ad8a4e7`](https://github.com/tobymao/sqlglot/commit/ad8a4e73e1a9e4234f0b711163fb49630acf736c) - refactor join mark elimination to use is_correlated_subquery *(commit by [@georgesittas](https://github.com/georgesittas))*
62
+
63
+
4
64
  ## [v26.26.0] - 2025-06-09
5
65
  ### :boom: BREAKING CHANGES
6
66
  - due to [`434c45b`](https://github.com/tobymao/sqlglot/commit/434c45b547c3a5ea155dc8d7da2baab326eb6d4f) - improve support for ENDSWITH closes [#5170](https://github.com/tobymao/sqlglot/pull/5170) *(commit by [@georgesittas](https://github.com/georgesittas))*:
@@ -4840,3 +4900,5 @@ Changelog
4840
4900
  [v26.25.2]: https://github.com/tobymao/sqlglot/compare/v26.25.1...v26.25.2
4841
4901
  [v26.25.3]: https://github.com/tobymao/sqlglot/compare/v26.25.2...v26.25.3
4842
4902
  [v26.26.0]: https://github.com/tobymao/sqlglot/compare/v26.25.3...v26.26.0
4903
+ [v26.27.0]: https://github.com/tobymao/sqlglot/compare/v26.26.0...v26.27.0
4904
+ [v26.28.1]: https://github.com/tobymao/sqlglot/compare/v26.27.1...v26.28.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 26.27.1
3
+ Version: 26.29.0
4
4
  Summary: An easily customizable SQL parser and transpiler
5
5
  Author-email: Toby Mao <toby.mao@gmail.com>
6
6
  License: MIT License
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '26.27.1'
21
- __version_tuple__ = version_tuple = (26, 27, 1)
20
+ __version__ = version = '26.29.0'
21
+ __version_tuple__ = version_tuple = (26, 29, 0)
@@ -108,6 +108,7 @@ class Athena(Trino):
108
108
  """
109
109
 
110
110
  IDENTIFIERS = ['"', "`"]
111
+ STRING_ESCAPES = ["'", "\\"]
111
112
  KEYWORDS = {
112
113
  **Hive.Tokenizer.KEYWORDS,
113
114
  **Trino.Tokenizer.KEYWORDS,
@@ -1621,7 +1621,10 @@ def map_date_part(part, dialect: DialectType = Dialect):
1621
1621
  mapped = (
1622
1622
  Dialect.get_or_raise(dialect).DATE_PART_MAPPING.get(part.name.upper()) if part else None
1623
1623
  )
1624
- return exp.var(mapped) if mapped else part
1624
+ if mapped:
1625
+ return exp.Literal.string(mapped) if part.is_string else exp.var(mapped)
1626
+
1627
+ return part
1625
1628
 
1626
1629
 
1627
1630
  def no_last_day_sql(self: Generator, expression: exp.LastDay) -> str:
@@ -290,6 +290,12 @@ class DuckDB(Dialect):
290
290
  # https://duckdb.org/docs/sql/introduction.html#creating-a-new-table
291
291
  NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
292
292
 
293
+ DATE_PART_MAPPING = {
294
+ **Dialect.DATE_PART_MAPPING,
295
+ "DAYOFWEEKISO": "ISODOW",
296
+ }
297
+ DATE_PART_MAPPING.pop("WEEKDAY")
298
+
293
299
  def to_json_path(self, path: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
294
300
  if isinstance(path, exp.Literal):
295
301
  # DuckDB also supports the JSON pointer syntax, where every path starts with a `/`.
@@ -620,6 +626,7 @@ class DuckDB(Dialect):
620
626
  PAD_FILL_PATTERN_IS_REQUIRED = True
621
627
  ARRAY_CONCAT_IS_VAR_LEN = False
622
628
  ARRAY_SIZE_DIM_REQUIRED = False
629
+ NORMALIZE_EXTRACT_DATE_PARTS = True
623
630
 
624
631
  TRANSFORMS = {
625
632
  **generator.Generator.TRANSFORMS,
@@ -31,6 +31,7 @@ from sqlglot.dialects.dialect import (
31
31
  )
32
32
  from sqlglot.generator import unsupported_args
33
33
  from sqlglot.helper import flatten, is_float, is_int, seq_get
34
+ from sqlglot.optimizer.scope import find_all_in_scope
34
35
  from sqlglot.tokens import TokenType
35
36
 
36
37
  if t.TYPE_CHECKING:
@@ -333,6 +334,34 @@ def _json_extract_value_array_sql(
333
334
  return self.func("TRANSFORM", json_extract, transform_lambda)
334
335
 
335
336
 
337
+ def _eliminate_dot_variant_lookup(expression: exp.Expression) -> exp.Expression:
338
+ if isinstance(expression, exp.Select):
339
+ # This transformation is used to facilitate transpilation of BigQuery `UNNEST` operations
340
+ # to Snowflake. It should not affect roundtrip because `Unnest` nodes cannot be produced
341
+ # by Snowflake's parser.
342
+ #
343
+ # Additionally, at the time of writing this, BigQuery is the only dialect that produces a
344
+ # `TableAlias` node that only fills `columns` and not `this`, due to `UNNEST_COLUMN_ONLY`.
345
+ unnest_aliases = set()
346
+ for unnest in find_all_in_scope(expression, exp.Unnest):
347
+ unnest_alias = unnest.args.get("alias")
348
+ if (
349
+ isinstance(unnest_alias, exp.TableAlias)
350
+ and not unnest_alias.this
351
+ and len(unnest_alias.columns) == 1
352
+ ):
353
+ unnest_aliases.add(unnest_alias.columns[0].name)
354
+
355
+ if unnest_aliases:
356
+ for c in find_all_in_scope(expression, exp.Column):
357
+ if c.table in unnest_aliases:
358
+ bracket_lhs = c.args["table"]
359
+ bracket_rhs = exp.Literal.string(c.name)
360
+ c.replace(exp.Bracket(this=bracket_lhs, expressions=[bracket_rhs]))
361
+
362
+ return expression
363
+
364
+
336
365
  class Snowflake(Dialect):
337
366
  # https://docs.snowflake.com/en/sql-reference/identifiers-syntax
338
367
  NORMALIZATION_STRATEGY = NormalizationStrategy.UPPERCASE
@@ -1096,6 +1125,7 @@ class Snowflake(Dialect):
1096
1125
  transforms.explode_projection_to_unnest(),
1097
1126
  transforms.eliminate_semi_and_anti_joins,
1098
1127
  _transform_generate_date_array,
1128
+ _eliminate_dot_variant_lookup,
1099
1129
  ]
1100
1130
  ),
1101
1131
  exp.SHA: rename_func("SHA1"),
@@ -1314,7 +1344,14 @@ class Snowflake(Dialect):
1314
1344
  start = f" START {start}" if start else ""
1315
1345
  increment = expression.args.get("increment")
1316
1346
  increment = f" INCREMENT {increment}" if increment else ""
1317
- return f"AUTOINCREMENT{start}{increment}"
1347
+
1348
+ order = expression.args.get("order")
1349
+ if order is not None:
1350
+ order_clause = " ORDER" if order else " NOORDER"
1351
+ else:
1352
+ order_clause = ""
1353
+
1354
+ return f"AUTOINCREMENT{start}{increment}{order_clause}"
1318
1355
 
1319
1356
  def cluster_sql(self, expression: exp.Cluster) -> str:
1320
1357
  return f"CLUSTER BY ({self.expressions(expression, flat=True)})"
@@ -1224,8 +1224,6 @@ class TSQL(Dialect):
1224
1224
  # to amend the AST by moving the CTEs to the CREATE VIEW statement's query.
1225
1225
  ctas_expression.set("with", with_.pop())
1226
1226
 
1227
- sql = super().create_sql(expression)
1228
-
1229
1227
  table = expression.find(exp.Table)
1230
1228
 
1231
1229
  # Convert CTAS statement to SELECT .. INTO ..
@@ -1243,6 +1241,8 @@ class TSQL(Dialect):
1243
1241
  select_into.limit(0, copy=False)
1244
1242
 
1245
1243
  sql = self.sql(select_into)
1244
+ else:
1245
+ sql = super().create_sql(expression)
1246
1246
 
1247
1247
  if exists:
1248
1248
  identifier = self.sql(exp.Literal.string(exp.table_name(table) if table else ""))
@@ -51,8 +51,8 @@ class _Expression(type):
51
51
  def __new__(cls, clsname, bases, attrs):
52
52
  klass = super().__new__(cls, clsname, bases, attrs)
53
53
 
54
- # When an Expression class is created, its key is automatically set to be
55
- # the lowercase version of the class' name.
54
+ # When an Expression class is created, its key is automatically set
55
+ # to be the lowercase version of the class' name.
56
56
  klass.key = clsname.lower()
57
57
 
58
58
  # This is so that docstrings are not inherited in pdoc
@@ -1947,6 +1947,7 @@ class GeneratedAsIdentityColumnConstraint(ColumnConstraintKind):
1947
1947
  "minvalue": False,
1948
1948
  "maxvalue": False,
1949
1949
  "cycle": False,
1950
+ "order": False,
1950
1951
  }
1951
1952
 
1952
1953
 
@@ -7044,6 +7045,12 @@ class Semicolon(Expression):
7044
7045
  arg_types = {}
7045
7046
 
7046
7047
 
7048
+ # BigQuery allows SELECT t FROM t and treats the projection as a struct value. This expression
7049
+ # type is intended to be constructed by qualify so that we can properly annotate its type later
7050
+ class TableColumn(Expression):
7051
+ pass
7052
+
7053
+
7047
7054
  def _norm_arg(arg):
7048
7055
  return arg.lower() if type(arg) is str else arg
7049
7056
 
@@ -201,6 +201,7 @@ class Generator(metaclass=_Generator):
201
201
  exp.StreamingTableProperty: lambda *_: "STREAMING",
202
202
  exp.StrictProperty: lambda *_: "STRICT",
203
203
  exp.SwapTable: lambda self, e: f"SWAP WITH {self.sql(e, 'this')}",
204
+ exp.TableColumn: lambda self, e: self.sql(e.this),
204
205
  exp.Tags: lambda self, e: f"TAG ({self.expressions(e, flat=True)})",
205
206
  exp.TemporaryProperty: lambda *_: "TEMPORARY",
206
207
  exp.TitleColumnConstraint: lambda self, e: f"TITLE {self.sql(e, 'this')}",
@@ -463,6 +464,11 @@ class Generator(metaclass=_Generator):
463
464
  # Whether to wrap <props> in `AlterSet`, e.g., ALTER ... SET (<props>)
464
465
  ALTER_SET_WRAPPED = False
465
466
 
467
+ # Whether to normalize the date parts in EXTRACT(<date_part> FROM <expr>) into a common representation
468
+ # For instance, to extract the day of week in ISO semantics, one can use ISODOW, DAYOFWEEKISO etc depending on the dialect.
469
+ # TODO: The normalization should be done by default once we've tested it across all dialects.
470
+ NORMALIZE_EXTRACT_DATE_PARTS = False
471
+
466
472
  # The name to generate for the JSONPath expression. If `None`, only `this` will be generated
467
473
  PARSE_JSON_NAME: t.Optional[str] = "PARSE_JSON"
468
474
 
@@ -2909,9 +2915,17 @@ class Generator(metaclass=_Generator):
2909
2915
  return f"NEXT VALUE FOR {self.sql(expression, 'this')}{order}"
2910
2916
 
2911
2917
  def extract_sql(self, expression: exp.Extract) -> str:
2912
- this = self.sql(expression, "this") if self.EXTRACT_ALLOWS_QUOTES else expression.this.name
2918
+ from sqlglot.dialects.dialect import map_date_part
2919
+
2920
+ this = (
2921
+ map_date_part(expression.this, self.dialect)
2922
+ if self.NORMALIZE_EXTRACT_DATE_PARTS
2923
+ else expression.this
2924
+ )
2925
+ this_sql = self.sql(this) if self.EXTRACT_ALLOWS_QUOTES else this.name
2913
2926
  expression_sql = self.sql(expression, "expression")
2914
- return f"EXTRACT({this} FROM {expression_sql})"
2927
+
2928
+ return f"EXTRACT({this_sql} FROM {expression_sql})"
2915
2929
 
2916
2930
  def trim_sql(self, expression: exp.Trim) -> str:
2917
2931
  trim_type = self.sql(expression, "position")
@@ -4766,7 +4780,10 @@ class Generator(metaclass=_Generator):
4766
4780
 
4767
4781
  def detach_sql(self, expression: exp.Detach) -> str:
4768
4782
  this = self.sql(expression, "this")
4769
- exists_sql = " IF EXISTS" if expression.args.get("exists") else ""
4783
+ # the DATABASE keyword is required if IF EXISTS is set
4784
+ # without it, DuckDB throws an error: Parser Error: syntax error at or near "exists" (Line Number: 1)
4785
+ # ref: https://duckdb.org/docs/stable/sql/statements/attach.html#detach-syntax
4786
+ exists_sql = " DATABASE IF EXISTS" if expression.args.get("exists") else ""
4770
4787
 
4771
4788
  return f"DETACH{exists_sql} {this}"
4772
4789
 
@@ -12,7 +12,7 @@ from sqlglot.helper import (
12
12
  seq_get,
13
13
  )
14
14
  from sqlglot.optimizer.scope import Scope, traverse_scope
15
- from sqlglot.schema import Schema, ensure_schema
15
+ from sqlglot.schema import MappingSchema, Schema, ensure_schema
16
16
  from sqlglot.dialects.dialect import Dialect
17
17
 
18
18
  if t.TYPE_CHECKING:
@@ -290,9 +290,52 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
290
290
  elif isinstance(source.expression, exp.Unnest):
291
291
  self._set_type(col, source.expression.type)
292
292
 
293
+ if isinstance(self.schema, MappingSchema):
294
+ for table_column in scope.table_columns:
295
+ source = scope.sources.get(table_column.name)
296
+
297
+ if isinstance(source, exp.Table):
298
+ schema = self.schema.find(
299
+ source, raise_on_missing=False, ensure_data_types=True
300
+ )
301
+ if not isinstance(schema, dict):
302
+ continue
303
+
304
+ struct_type = exp.DataType(
305
+ this=exp.DataType.Type.STRUCT,
306
+ expressions=[
307
+ exp.ColumnDef(this=exp.to_identifier(c), kind=kind)
308
+ for c, kind in schema.items()
309
+ ],
310
+ nested=True,
311
+ )
312
+ self._set_type(table_column, struct_type)
313
+ elif (
314
+ isinstance(source, Scope)
315
+ and isinstance(source.expression, exp.Query)
316
+ and source.expression.is_type(exp.DataType.Type.STRUCT)
317
+ ):
318
+ self._set_type(table_column, source.expression.type)
319
+
293
320
  # Then (possibly) annotate the remaining expressions in the scope
294
321
  self._maybe_annotate(scope.expression)
295
322
 
323
+ if self.schema.dialect == "bigquery" and isinstance(scope.expression, exp.Query):
324
+ struct_type = exp.DataType(
325
+ this=exp.DataType.Type.STRUCT,
326
+ expressions=[
327
+ exp.ColumnDef(this=exp.to_identifier(select.output_name), kind=select.type)
328
+ for select in scope.expression.selects
329
+ ],
330
+ nested=True,
331
+ )
332
+ if not any(
333
+ cd.kind.is_type(exp.DataType.Type.UNKNOWN)
334
+ for cd in struct_type.expressions
335
+ if cd.kind
336
+ ):
337
+ self._set_type(scope.expression, struct_type)
338
+
296
339
  def _maybe_annotate(self, expression: E) -> E:
297
340
  if id(expression) in self._visited:
298
341
  return expression # We've already inferred the expression's type
@@ -529,6 +529,13 @@ def _qualify_columns(scope: Scope, resolver: Resolver, allow_partial_qualificati
529
529
  column_table = resolver.get_table(column_name)
530
530
  if column_table:
531
531
  column.set("table", column_table)
532
+ elif (
533
+ resolver.schema.dialect == "bigquery"
534
+ and len(column.parts) == 1
535
+ and column_name in scope.selected_sources
536
+ ):
537
+ # BigQuery allows tables to be referenced as columns, treating them as structs
538
+ scope.replace(column, exp.TableColumn(this=column.this))
532
539
 
533
540
  for pivot in scope.pivots:
534
541
  for column in pivot.find_all(exp.Column):
@@ -88,6 +88,7 @@ class Scope:
88
88
  def clear_cache(self):
89
89
  self._collected = False
90
90
  self._raw_columns = None
91
+ self._table_columns = None
91
92
  self._stars = None
92
93
  self._derived_tables = None
93
94
  self._udtfs = None
@@ -125,6 +126,7 @@ class Scope:
125
126
  self._derived_tables = []
126
127
  self._udtfs = []
127
128
  self._raw_columns = []
129
+ self._table_columns = []
128
130
  self._stars = []
129
131
  self._join_hints = []
130
132
  self._semi_anti_join_tables = set()
@@ -156,6 +158,8 @@ class Scope:
156
158
  self._derived_tables.append(node)
157
159
  elif isinstance(node, exp.UNWRAPPED_QUERIES):
158
160
  self._subqueries.append(node)
161
+ elif isinstance(node, exp.TableColumn):
162
+ self._table_columns.append(node)
159
163
 
160
164
  self._collected = True
161
165
 
@@ -309,6 +313,13 @@ class Scope:
309
313
 
310
314
  return self._columns
311
315
 
316
+ @property
317
+ def table_columns(self):
318
+ if self._table_columns is None:
319
+ self._ensure_collected()
320
+
321
+ return self._table_columns
322
+
312
323
  @property
313
324
  def selected_sources(self):
314
325
  """
@@ -758,6 +769,8 @@ def _traverse_tables(scope):
758
769
  expressions.extend(join.this for join in expression.args.get("joins") or [])
759
770
  continue
760
771
 
772
+ child_scope = None
773
+
761
774
  for child_scope in _traverse_scope(
762
775
  scope.branch(
763
776
  expression,
@@ -775,8 +788,9 @@ def _traverse_tables(scope):
775
788
  sources[expression.alias] = child_scope
776
789
 
777
790
  # append the final child_scope yielded
778
- scopes.append(child_scope)
779
- scope.table_scopes.append(child_scope)
791
+ if child_scope:
792
+ scopes.append(child_scope)
793
+ scope.table_scopes.append(child_scope)
780
794
 
781
795
  scope.sources.update(sources)
782
796
 
@@ -846,12 +860,14 @@ def walk_in_scope(expression, bfs=True, prune=None):
846
860
 
847
861
  if node is expression:
848
862
  continue
863
+
849
864
  if (
850
865
  isinstance(node, exp.CTE)
851
866
  or (
852
867
  isinstance(node.parent, (exp.From, exp.Join, exp.Subquery))
853
- and (_is_derived_table(node) or isinstance(node, exp.UDTF))
868
+ and _is_derived_table(node)
854
869
  )
870
+ or (isinstance(node.parent, exp.UDTF) and isinstance(node, exp.Query))
855
871
  or isinstance(node, exp.UNWRAPPED_QUERIES)
856
872
  ):
857
873
  crossed_scope_boundary = True