sqlglot 30.17.0__tar.gz → 30.18.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 (340) hide show
  1. {sqlglot-30.17.0 → sqlglot-30.18.0}/CHANGELOG.md +87 -0
  2. {sqlglot-30.17.0/sqlglot.egg-info → sqlglot-30.18.0}/PKG-INFO +4 -4
  3. {sqlglot-30.17.0 → sqlglot-30.18.0}/setup.py +1 -1
  4. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/_version.py +3 -3
  5. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/__init__.py +3 -1
  6. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/bigquery.py +3 -1
  7. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/dialect.py +52 -14
  8. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/duckdb.py +1 -0
  9. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/mysql.py +3 -0
  10. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/postgres.py +3 -0
  11. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/snowflake.py +1 -0
  12. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/sqlite.py +1 -0
  13. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/starrocks.py +5 -0
  14. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/tsql.py +1 -0
  15. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/executor/context.py +15 -4
  16. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/executor/env.py +20 -4
  17. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/executor/python.py +159 -11
  18. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/executor/table.py +1 -1
  19. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/builders.py +9 -4
  20. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/constraints.py +4 -0
  21. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/ddl.py +1 -1
  22. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/json.py +4 -0
  23. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/query.py +2 -1
  24. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/string.py +2 -1
  25. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generator.py +50 -8
  26. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/clickhouse.py +2 -6
  27. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/dremio.py +3 -0
  28. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/duckdb.py +7 -9
  29. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/hive.py +1 -0
  30. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/oracle.py +2 -1
  31. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/postgres.py +8 -4
  32. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/presto.py +1 -1
  33. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/python.py +10 -2
  34. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/snowflake.py +4 -35
  35. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/sqlite.py +2 -0
  36. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/teradata.py +2 -3
  37. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/trino.py +1 -1
  38. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/tsql.py +11 -1
  39. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/annotate_types.py +29 -15
  40. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/normalize_identifiers.py +33 -11
  41. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/pushdown_predicates.py +17 -5
  42. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/pushdown_projections.py +58 -43
  43. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/qualify_columns.py +136 -12
  44. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/qualify_tables.py +10 -0
  45. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/resolver.py +2 -3
  46. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/scope.py +8 -4
  47. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/unnest_subqueries.py +11 -1
  48. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parser.py +118 -53
  49. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/bigquery.py +2 -1
  50. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/clickhouse.py +27 -6
  51. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/dremio.py +6 -0
  52. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/mysql.py +7 -0
  53. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/oracle.py +1 -0
  54. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/postgres.py +7 -2
  55. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/snowflake.py +11 -35
  56. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/spark2.py +16 -2
  57. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/starrocks.py +3 -0
  58. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/teradata.py +1 -1
  59. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/tsql.py +3 -1
  60. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/planner.py +11 -5
  61. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/transforms.py +43 -2
  62. sqlglot-30.18.0/sqlglot/typing/postgres.py +59 -0
  63. {sqlglot-30.17.0 → sqlglot-30.18.0/sqlglot.egg-info}/PKG-INFO +4 -4
  64. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot.egg-info/requires.txt +3 -3
  65. sqlglot-30.18.0/sqlglot.egg-info/scm_version.json +8 -0
  66. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglotc/pyproject.toml +2 -2
  67. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_bigquery.py +37 -0
  68. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_clickhouse.py +56 -4
  69. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_dremio.py +21 -0
  70. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_duckdb.py +6 -0
  71. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_hive.py +5 -5
  72. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_mysql.py +45 -0
  73. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_oracle.py +17 -0
  74. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_postgres.py +74 -7
  75. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_redshift.py +15 -7
  76. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_snowflake.py +16 -0
  77. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_spark.py +77 -2
  78. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_sqlite.py +34 -0
  79. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_starrocks.py +10 -0
  80. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_teradata.py +2 -0
  81. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_trino.py +17 -0
  82. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_tsql.py +43 -11
  83. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/identity.sql +7 -0
  84. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/annotate_functions.sql +145 -0
  85. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/normalize_identifiers.sql +30 -0
  86. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/pushdown_predicates.sql +11 -0
  87. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/pushdown_projections.sql +56 -0
  88. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/qualify_columns.sql +98 -0
  89. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/qualify_tables.sql +15 -0
  90. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/unnest_subqueries.sql +8 -1
  91. sqlglot-30.18.0/tests/test_dialect_imports.py +35 -0
  92. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_executor.py +459 -128
  93. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_expressions.py +6 -0
  94. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_lineage.py +32 -0
  95. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_optimizer.py +164 -0
  96. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_parser.py +57 -14
  97. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_transforms.py +28 -0
  98. sqlglot-30.17.0/sqlglot/typing/postgres.py +0 -21
  99. sqlglot-30.17.0/sqlglot.egg-info/scm_version.json +0 -8
  100. sqlglot-30.17.0/tests/test_dialect_imports.py +0 -48
  101. {sqlglot-30.17.0 → sqlglot-30.18.0}/.gitignore +0 -0
  102. {sqlglot-30.17.0 → sqlglot-30.18.0}/.gitmodules +0 -0
  103. {sqlglot-30.17.0 → sqlglot-30.18.0}/.gitpod.yml +0 -0
  104. {sqlglot-30.17.0 → sqlglot-30.18.0}/.pre-commit-config.yaml +0 -0
  105. {sqlglot-30.17.0 → sqlglot-30.18.0}/AGENTS.md +0 -0
  106. {sqlglot-30.17.0 → sqlglot-30.18.0}/CLAUDE.md +0 -0
  107. {sqlglot-30.17.0 → sqlglot-30.18.0}/CONTRIBUTING.md +0 -0
  108. {sqlglot-30.17.0 → sqlglot-30.18.0}/LICENSE +0 -0
  109. {sqlglot-30.17.0 → sqlglot-30.18.0}/MANIFEST.in +0 -0
  110. {sqlglot-30.17.0 → sqlglot-30.18.0}/Makefile +0 -0
  111. {sqlglot-30.17.0 → sqlglot-30.18.0}/README.md +0 -0
  112. {sqlglot-30.17.0 → sqlglot-30.18.0}/pyproject.toml +0 -0
  113. {sqlglot-30.17.0 → sqlglot-30.18.0}/setup.cfg +0 -0
  114. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/__init__.py +0 -0
  115. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/__main__.py +0 -0
  116. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/_typing.py +0 -0
  117. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/anonymize.py +0 -0
  118. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/athena.py +0 -0
  119. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/clickhouse.py +0 -0
  120. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/databricks.py +0 -0
  121. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/dax.py +0 -0
  122. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/doris.py +0 -0
  123. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/dremio.py +0 -0
  124. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/drill.py +0 -0
  125. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/druid.py +0 -0
  126. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/dune.py +0 -0
  127. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/exasol.py +0 -0
  128. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/fabric.py +0 -0
  129. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/hive.py +0 -0
  130. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/materialize.py +0 -0
  131. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/oracle.py +0 -0
  132. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/presto.py +0 -0
  133. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/prql.py +0 -0
  134. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/redshift.py +0 -0
  135. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/risingwave.py +0 -0
  136. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/singlestore.py +0 -0
  137. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/solr.py +0 -0
  138. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/spark.py +0 -0
  139. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/spark2.py +0 -0
  140. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/tableau.py +0 -0
  141. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/teradata.py +0 -0
  142. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/dialects/trino.py +0 -0
  143. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/diff.py +0 -0
  144. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/errors.py +0 -0
  145. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/executor/__init__.py +0 -0
  146. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/__init__.py +0 -0
  147. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/aggregate.py +0 -0
  148. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/array.py +0 -0
  149. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/core.py +0 -0
  150. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/datatypes.py +0 -0
  151. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/dml.py +0 -0
  152. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/functions.py +0 -0
  153. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/math.py +0 -0
  154. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/properties.py +0 -0
  155. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/expressions/temporal.py +0 -0
  156. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/__init__.py +0 -0
  157. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/athena.py +0 -0
  158. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/bigquery.py +0 -0
  159. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/databricks.py +0 -0
  160. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/dax.py +0 -0
  161. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/doris.py +0 -0
  162. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/drill.py +0 -0
  163. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/druid.py +0 -0
  164. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/dune.py +0 -0
  165. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/exasol.py +0 -0
  166. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/fabric.py +0 -0
  167. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/materialize.py +0 -0
  168. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/mysql.py +0 -0
  169. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/prql.py +0 -0
  170. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/redshift.py +0 -0
  171. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/risingwave.py +0 -0
  172. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/singlestore.py +0 -0
  173. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/solr.py +0 -0
  174. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/spark.py +0 -0
  175. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/spark2.py +0 -0
  176. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/starrocks.py +0 -0
  177. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/generators/tableau.py +0 -0
  178. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/helper.py +0 -0
  179. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/jsonpath.py +0 -0
  180. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/lineage.py +0 -0
  181. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/__init__.py +0 -0
  182. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/canonicalize.py +0 -0
  183. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/canonicalize_internal_names.py +0 -0
  184. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/eliminate_ctes.py +0 -0
  185. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/eliminate_joins.py +0 -0
  186. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/eliminate_subqueries.py +0 -0
  187. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
  188. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/journal.py +0 -0
  189. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/merge_subqueries.py +0 -0
  190. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/normalize.py +0 -0
  191. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/optimize_joins.py +0 -0
  192. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/optimizer.py +0 -0
  193. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/qualify.py +0 -0
  194. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/optimizer/simplify.py +0 -0
  195. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/__init__.py +0 -0
  196. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/athena.py +0 -0
  197. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/base.py +0 -0
  198. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/databricks.py +0 -0
  199. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/dax.py +0 -0
  200. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/doris.py +0 -0
  201. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/drill.py +0 -0
  202. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/druid.py +0 -0
  203. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/duckdb.py +0 -0
  204. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/dune.py +0 -0
  205. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/exasol.py +0 -0
  206. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/fabric.py +0 -0
  207. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/hive.py +0 -0
  208. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/materialize.py +0 -0
  209. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/presto.py +0 -0
  210. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/prql.py +0 -0
  211. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/redshift.py +0 -0
  212. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/risingwave.py +0 -0
  213. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/singlestore.py +0 -0
  214. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/solr.py +0 -0
  215. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/spark.py +0 -0
  216. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/sqlite.py +0 -0
  217. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/tableau.py +0 -0
  218. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/parsers/trino.py +0 -0
  219. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/py.typed +0 -0
  220. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/schema.py +0 -0
  221. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/serde.py +0 -0
  222. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/time.py +0 -0
  223. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/tokenizer_core.py +0 -0
  224. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/tokens.py +0 -0
  225. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/trie.py +0 -0
  226. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/__init__.py +0 -0
  227. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/bigquery.py +0 -0
  228. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/clickhouse.py +0 -0
  229. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/databricks.py +0 -0
  230. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/duckdb.py +0 -0
  231. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/hive.py +0 -0
  232. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/mysql.py +0 -0
  233. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/presto.py +0 -0
  234. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/redshift.py +0 -0
  235. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/snowflake.py +0 -0
  236. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/spark.py +0 -0
  237. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/spark2.py +0 -0
  238. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot/typing/tsql.py +0 -0
  239. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot.egg-info/SOURCES.txt +0 -0
  240. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot.egg-info/dependency_links.txt +0 -0
  241. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot.egg-info/scm_file_list.json +0 -0
  242. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot.egg-info/top_level.txt +0 -0
  243. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglot.png +0 -0
  244. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglotc/MANIFEST.in +0 -0
  245. {sqlglot-30.17.0 → sqlglot-30.18.0}/sqlglotc/setup.py +0 -0
  246. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/__init__.py +0 -0
  247. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/__init__.py +0 -0
  248. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_athena.py +0 -0
  249. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_databricks.py +0 -0
  250. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_dax.py +0 -0
  251. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_dialect.py +0 -0
  252. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_doris.py +0 -0
  253. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_drill.py +0 -0
  254. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_druid.py +0 -0
  255. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_dune.py +0 -0
  256. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_exasol.py +0 -0
  257. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_fabric.py +0 -0
  258. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_materialize.py +0 -0
  259. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_pipe_syntax.py +0 -0
  260. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_presto.py +0 -0
  261. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_prql.py +0 -0
  262. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_risingwave.py +0 -0
  263. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_singlestore.py +0 -0
  264. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_solr.py +0 -0
  265. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/dialects/test_tableau.py +0 -0
  266. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/jsonpath/LICENSE +0 -0
  267. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/jsonpath/cts.json +0 -0
  268. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/annotate_types.sql +0 -0
  269. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/canonicalize.sql +0 -0
  270. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/canonicalize_internal_names.sql +0 -0
  271. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/eliminate_ctes.sql +0 -0
  272. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/eliminate_joins.sql +0 -0
  273. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/eliminate_subqueries.sql +0 -0
  274. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/isolate_table_selects.sql +0 -0
  275. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/merge_subqueries.sql +0 -0
  276. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/normalize.sql +0 -0
  277. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/optimize_joins.sql +0 -0
  278. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/optimizer.sql +0 -0
  279. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/pushdown_cte_alias_columns.sql +0 -0
  280. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/qualify_columns__invalid.sql +0 -0
  281. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/qualify_columns__with_invisible.sql +0 -0
  282. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/qualify_columns_ddl.sql +0 -0
  283. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/quote_identifiers.sql +0 -0
  284. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/simplify.sql +0 -0
  285. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/call_center.csv.gz +0 -0
  286. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/catalog_page.csv.gz +0 -0
  287. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/catalog_returns.csv.gz +0 -0
  288. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/catalog_sales.csv.gz +0 -0
  289. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/customer.csv.gz +0 -0
  290. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/customer_address.csv.gz +0 -0
  291. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/customer_demographics.csv.gz +0 -0
  292. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/date_dim.csv.gz +0 -0
  293. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/household_demographics.csv.gz +0 -0
  294. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/income_band.csv.gz +0 -0
  295. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/inventory.csv.gz +0 -0
  296. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/item.csv.gz +0 -0
  297. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/promotion.csv.gz +0 -0
  298. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/reason.csv.gz +0 -0
  299. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/ship_mode.csv.gz +0 -0
  300. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/store.csv.gz +0 -0
  301. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/store_returns.csv.gz +0 -0
  302. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/store_sales.csv.gz +0 -0
  303. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/time_dim.csv.gz +0 -0
  304. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/tpc-ds.sql +0 -0
  305. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/warehouse.csv.gz +0 -0
  306. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/web_page.csv.gz +0 -0
  307. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/web_returns.csv.gz +0 -0
  308. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/web_sales.csv.gz +0 -0
  309. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-ds/web_site.csv.gz +0 -0
  310. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-h/customer.csv.gz +0 -0
  311. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-h/lineitem.csv.gz +0 -0
  312. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-h/nation.csv.gz +0 -0
  313. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-h/orders.csv.gz +0 -0
  314. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-h/part.csv.gz +0 -0
  315. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-h/partsupp.csv.gz +0 -0
  316. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-h/region.csv.gz +0 -0
  317. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-h/supplier.csv.gz +0 -0
  318. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/optimizer/tpc-h/tpc-h.sql +0 -0
  319. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/partial.sql +0 -0
  320. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/fixtures/pretty.sql +0 -0
  321. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/gen_fixtures.py +0 -0
  322. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/helpers.py +0 -0
  323. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/leakcheck.py +0 -0
  324. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/sqlglot/__init__.py +0 -0
  325. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_anonymize.py +0 -0
  326. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_build.py +0 -0
  327. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_dialect_entry_points.py +0 -0
  328. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_diff.py +0 -0
  329. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_docs.py +0 -0
  330. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_errors.py +0 -0
  331. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_generator.py +0 -0
  332. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_helper.py +0 -0
  333. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_integration_loader.py +0 -0
  334. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_jsonpath.py +0 -0
  335. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_schema.py +0 -0
  336. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_serde.py +0 -0
  337. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_time.py +0 -0
  338. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_tokens.py +0 -0
  339. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_transpile.py +0 -0
  340. {sqlglot-30.17.0 → sqlglot-30.18.0}/tests/test_typing.py +0 -0
@@ -1,6 +1,92 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ## [v30.17.0] - 2026-08-12
5
+ ### :boom: BREAKING CHANGES
6
+ - due to [`5c12472`](https://github.com/tobymao/sqlglot/commit/5c12472a8016dff6eb8d9aab9c9a029adab2d514) - stop optimizing OR-conditioned joins and anti joins *(PR [#8118](https://github.com/tobymao/sqlglot/pull/8118) by [@georgesittas](https://github.com/georgesittas))*:
7
+
8
+ stop optimizing OR-conditioned joins and anti joins (#8118)
9
+
10
+ - due to [`07c2241`](https://github.com/tobymao/sqlglot/commit/07c22415977c21b342d578bd01b0ea7352a8a726) - support `and`, `or` function syntax *(PR [#8065](https://github.com/tobymao/sqlglot/pull/8065) by [@fivetran-amrutabhimsenayachit](https://github.com/fivetran-amrutabhimsenayachit))*:
11
+
12
+ support `and`, `or` function syntax (#8065)
13
+
14
+ - due to [`3d74d62`](https://github.com/tobymao/sqlglot/commit/3d74d62c323ad3097c690092e7a4eb86aabb2f2d) - prevent pruning columns referenced by GROUP BY / HAVING / QUALIFY *(PR [#8121](https://github.com/tobymao/sqlglot/pull/8121) by [@fivetran-kwoodbeck](https://github.com/fivetran-kwoodbeck))*:
15
+
16
+ prevent pruning columns referenced by GROUP BY / HAVING / QUALIFY (#8121)
17
+
18
+ - due to [`7c56116`](https://github.com/tobymao/sqlglot/commit/7c561165fad44b1af9008dcdf1d636323a28ef58) - annoate lag for mysql *(PR [#8133](https://github.com/tobymao/sqlglot/pull/8133) by [@PiyaDaswadkar](https://github.com/PiyaDaswadkar))*:
19
+
20
+ annoate lag for mysql (#8133)
21
+
22
+ - due to [`ac7b6d9`](https://github.com/tobymao/sqlglot/commit/ac7b6d922b8ea2c318efe767603dd276f7a1c71f) - do not prune projections under INTERSECT/EXCEPT ALL or GROUP BY ALL *(commit by [@georgesittas](https://github.com/georgesittas))*:
23
+
24
+ do not prune projections under INTERSECT/EXCEPT ALL or GROUP BY ALL
25
+
26
+ - due to [`e8836e8`](https://github.com/tobymao/sqlglot/commit/e8836e8fb1a0c59ce40bbac9832565aa8898d3a5) - annotate width_bucket for postgres *(PR [#8135](https://github.com/tobymao/sqlglot/pull/8135) by [@PiyaDaswadkar](https://github.com/PiyaDaswadkar))*:
27
+
28
+ annotate width_bucket for postgres (#8135)
29
+
30
+ - due to [`e7685a7`](https://github.com/tobymao/sqlglot/commit/e7685a7480fa698e77ee0a209bf29c93c825738a) - represent shadowed clause column refs as qualified Columns *(PR [#8128](https://github.com/tobymao/sqlglot/pull/8128) by [@georgesittas](https://github.com/georgesittas))*:
31
+
32
+ represent shadowed clause column refs as qualified Columns (#8128)
33
+
34
+ - due to [`8a29419`](https://github.com/tobymao/sqlglot/commit/8a29419f98c88939080db8e4fe1df34225d9135a) - stop pruning implicit GROUP BY ALL keys during projection pushdown *(PR [#8129](https://github.com/tobymao/sqlglot/pull/8129) by [@fivetran-kwoodbeck](https://github.com/fivetran-kwoodbeck))*:
35
+
36
+ stop pruning implicit GROUP BY ALL keys during projection pushdown (#8129)
37
+
38
+ - due to [`8ba0435`](https://github.com/tobymao/sqlglot/commit/8ba04354d37cb60031d3b14249743620dc7b2732) - escape `gen` delimited names (strings, etc) *(PR [#8134](https://github.com/tobymao/sqlglot/pull/8134) by [@georgesittas](https://github.com/georgesittas))*:
39
+
40
+ escape `gen` delimited names (strings, etc) (#8134)
41
+
42
+ - due to [`9312212`](https://github.com/tobymao/sqlglot/commit/9312212f2f3bda9b8bca191679e22c386c11edf9) - properly support `UNION BY NAME` in qualify, type inference *(PR [#8136](https://github.com/tobymao/sqlglot/pull/8136) by [@georgesittas](https://github.com/georgesittas))*:
43
+
44
+ properly support `UNION BY NAME` in qualify, type inference (#8136)
45
+
46
+ - due to [`3a76dfd`](https://github.com/tobymao/sqlglot/commit/3a76dfdbb0c4409e81fd30795c0d978fd827d23e) - annotate encode for postgresql *(PR [#8137](https://github.com/tobymao/sqlglot/pull/8137) by [@PiyaDaswadkar](https://github.com/PiyaDaswadkar))*:
47
+
48
+ annotate encode for postgresql (#8137)
49
+
50
+ - due to [`b7386b7`](https://github.com/tobymao/sqlglot/commit/b7386b756675567f89a098b7a5dbe598264ec2d5) - scope DML / DDL query fragments properly *(PR [#8140](https://github.com/tobymao/sqlglot/pull/8140) by [@georgesittas](https://github.com/georgesittas))*:
51
+
52
+ scope DML / DDL query fragments properly (#8140)
53
+
54
+
55
+ ### :sparkles: New Features
56
+ - [`31f3751`](https://github.com/tobymao/sqlglot/commit/31f375116dbd504615b0ebf50e4be917bc4e9305) - **trino**: parse WHILE/DO/END WHILE routine statements [CLAUDE] *(PR [#8122](https://github.com/tobymao/sqlglot/pull/8122) by [@rusackas](https://github.com/rusackas))*
57
+ - [`07c2241`](https://github.com/tobymao/sqlglot/commit/07c22415977c21b342d578bd01b0ea7352a8a726) - **databricks**: support `and`, `or` function syntax *(PR [#8065](https://github.com/tobymao/sqlglot/pull/8065) by [@fivetran-amrutabhimsenayachit](https://github.com/fivetran-amrutabhimsenayachit))*
58
+ - [`9815786`](https://github.com/tobymao/sqlglot/commit/9815786785604e8d580a229b31dc90b94a58b3ad) - **trino**: parse LOOP/REPEAT/ITERATE/LEAVE routine statements [CLAUDE] *(PR [#8130](https://github.com/tobymao/sqlglot/pull/8130) by [@rusackas](https://github.com/rusackas))*
59
+ - [`7c56116`](https://github.com/tobymao/sqlglot/commit/7c561165fad44b1af9008dcdf1d636323a28ef58) - **optimizer**: annoate lag for mysql *(PR [#8133](https://github.com/tobymao/sqlglot/pull/8133) by [@PiyaDaswadkar](https://github.com/PiyaDaswadkar))*
60
+ - [`e8836e8`](https://github.com/tobymao/sqlglot/commit/e8836e8fb1a0c59ce40bbac9832565aa8898d3a5) - **optimizer**: annotate width_bucket for postgres *(PR [#8135](https://github.com/tobymao/sqlglot/pull/8135) by [@PiyaDaswadkar](https://github.com/PiyaDaswadkar))*
61
+ - [`3a76dfd`](https://github.com/tobymao/sqlglot/commit/3a76dfdbb0c4409e81fd30795c0d978fd827d23e) - **optimizer**: annotate encode for postgresql *(PR [#8137](https://github.com/tobymao/sqlglot/pull/8137) by [@PiyaDaswadkar](https://github.com/PiyaDaswadkar))*
62
+ - [`98f3d66`](https://github.com/tobymao/sqlglot/commit/98f3d663c9f110216a5495e8d5b779d9d4e8cc61) - **executor**: implement ILIKE [CLAUDE] *(PR [#8144](https://github.com/tobymao/sqlglot/pull/8144) by [@jbylund](https://github.com/jbylund))*
63
+ - [`9a8129b`](https://github.com/tobymao/sqlglot/commit/9a8129b6f2667673f24713f4b49162ebae1f699d) - **executor**: implement LENGTH [CLAUDE] *(PR [#8145](https://github.com/tobymao/sqlglot/pull/8145) by [@jbylund](https://github.com/jbylund))*
64
+
65
+ ### :bug: Bug Fixes
66
+ - [`36bc768`](https://github.com/tobymao/sqlglot/commit/36bc768fc122337e9c79eaaee900610aef4b7d42) - **prql**: `_select_all` accepts the Optional its callers pass *(commit by [@tobymao](https://github.com/tobymao))*
67
+ - [`5c12472`](https://github.com/tobymao/sqlglot/commit/5c12472a8016dff6eb8d9aab9c9a029adab2d514) - **optimizer**: stop optimizing OR-conditioned joins and anti joins *(PR [#8118](https://github.com/tobymao/sqlglot/pull/8118) by [@georgesittas](https://github.com/georgesittas))*
68
+ - :arrow_lower_right: *fixes issue [#8101](https://github.com/tobymao/sqlglot/issues/8101) opened by [@dev-willbird1936](https://github.com/dev-willbird1936)*
69
+ - [`84447c0`](https://github.com/tobymao/sqlglot/commit/84447c08e98b4006c0a87209dfb23708c2f4f177) - **sqlite**: drop a dead `is not None` guard on a sentinel-typed Token *(commit by [@tobymao](https://github.com/tobymao))*
70
+ - [`353d0ff`](https://github.com/tobymao/sqlglot/commit/353d0ffca96acbd5407e73b832cadf5c1fedc9fe) - **sqlite**: emit STORED for generated columns instead of PERSISTED *(PR [#8123](https://github.com/tobymao/sqlglot/pull/8123) by [@dgvj-work](https://github.com/dgvj-work))*
71
+ - [`3d74d62`](https://github.com/tobymao/sqlglot/commit/3d74d62c323ad3097c690092e7a4eb86aabb2f2d) - **optimizer**: prevent pruning columns referenced by GROUP BY / HAVING / QUALIFY *(PR [#8121](https://github.com/tobymao/sqlglot/pull/8121) by [@fivetran-kwoodbeck](https://github.com/fivetran-kwoodbeck))*
72
+ - [`ac7b6d9`](https://github.com/tobymao/sqlglot/commit/ac7b6d922b8ea2c318efe767603dd276f7a1c71f) - **optimizer**: do not prune projections under INTERSECT/EXCEPT ALL or GROUP BY ALL *(commit by [@georgesittas](https://github.com/georgesittas))*
73
+ - [`8a29419`](https://github.com/tobymao/sqlglot/commit/8a29419f98c88939080db8e4fe1df34225d9135a) - **optimizer**: stop pruning implicit GROUP BY ALL keys during projection pushdown *(PR [#8129](https://github.com/tobymao/sqlglot/pull/8129) by [@fivetran-kwoodbeck](https://github.com/fivetran-kwoodbeck))*
74
+ - [`8ba0435`](https://github.com/tobymao/sqlglot/commit/8ba04354d37cb60031d3b14249743620dc7b2732) - **optimizer**: escape `gen` delimited names (strings, etc) *(PR [#8134](https://github.com/tobymao/sqlglot/pull/8134) by [@georgesittas](https://github.com/georgesittas))*
75
+ - [`9312212`](https://github.com/tobymao/sqlglot/commit/9312212f2f3bda9b8bca191679e22c386c11edf9) - **optimizer**: properly support `UNION BY NAME` in qualify, type inference *(PR [#8136](https://github.com/tobymao/sqlglot/pull/8136) by [@georgesittas](https://github.com/georgesittas))*
76
+ - [`1dae76b`](https://github.com/tobymao/sqlglot/commit/1dae76b5833a47c9e2bc0a72a93d94d829377a0c) - **executor**: only truncate typed division when both operands are integers [CLAUDE] *(PR [#8138](https://github.com/tobymao/sqlglot/pull/8138) by [@jbylund](https://github.com/jbylund))*
77
+ - :arrow_lower_right: *fixes issue [#8132](https://github.com/tobymao/sqlglot/issues/8132) opened by [@jbylund](https://github.com/jbylund)*
78
+ - [`7cab581`](https://github.com/tobymao/sqlglot/commit/7cab581ffea8df170402381d942b6ac0781d2125) - **executor**: honor the negate flag on LIKE and ILIKE [CLAUDE] *(PR [#8139](https://github.com/tobymao/sqlglot/pull/8139) by [@jbylund](https://github.com/jbylund))*
79
+ - [`44b73a0`](https://github.com/tobymao/sqlglot/commit/44b73a002328aea0fe0f655921ce43e43084e2d3) - **executor**: fullmatch like semantics *(commit by [@georgesittas](https://github.com/georgesittas))*
80
+ - [`8619582`](https://github.com/tobymao/sqlglot/commit/86195827b827a34d324d6e21e0076d20031fb8a6) - **optimizer**: preserve identifier meta when restoring JSON dot part case *(commit by [@georgesittas](https://github.com/georgesittas))*
81
+ - [`b7386b7`](https://github.com/tobymao/sqlglot/commit/b7386b756675567f89a098b7a5dbe598264ec2d5) - **optimizer**: scope DML / DDL query fragments properly *(PR [#8140](https://github.com/tobymao/sqlglot/pull/8140) by [@georgesittas](https://github.com/georgesittas))*
82
+
83
+ ### :recycle: Refactors
84
+ - [`e7685a7`](https://github.com/tobymao/sqlglot/commit/e7685a7480fa698e77ee0a209bf29c93c825738a) - **optimizer**: represent shadowed clause column refs as qualified Columns *(PR [#8128](https://github.com/tobymao/sqlglot/pull/8128) by [@georgesittas](https://github.com/georgesittas))*
85
+
86
+ ### :wrench: Chores
87
+ - [`1183e88`](https://github.com/tobymao/sqlglot/commit/1183e88c9661f98220c1a3719b5570e2efd645d0) - **mypy**: Bump version to v.2.3.0.post1 *(PR [#8126](https://github.com/tobymao/sqlglot/pull/8126) by [@VaggelisD](https://github.com/VaggelisD))*
88
+
89
+
4
90
  ## [v30.16.0] - 2026-08-10
5
91
  ### :boom: BREAKING CHANGES
6
92
  - due to [`32d44c5`](https://github.com/tobymao/sqlglot/commit/32d44c50d0138762c812a9326bb394eebd862464) - annotate bit_and for mysql *(PR [#8038](https://github.com/tobymao/sqlglot/pull/8038) by [@PiyaDaswadkar](https://github.com/PiyaDaswadkar))*:
@@ -15397,3 +15483,4 @@ pip install "sqlglot[c]" # compiled — faster, but no subclassing
15397
15483
  [v30.13.0]: https://github.com/tobymao/sqlglot/compare/v30.12.0...v30.13.0
15398
15484
  [v30.14.0]: https://github.com/tobymao/sqlglot/compare/v30.13.0...v30.14.0
15399
15485
  [v30.16.0]: https://github.com/tobymao/sqlglot/compare/v30.15.0...v30.16.0
15486
+ [v30.17.0]: https://github.com/tobymao/sqlglot/compare/v30.16.0...v30.17.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglot
3
- Version: 30.17.0
3
+ Version: 30.18.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
@@ -19,7 +19,7 @@ Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
20
  Provides-Extra: dev
21
21
  Requires-Dist: duckdb>=0.6; extra == "dev"
22
- Requires-Dist: sqlglot-mypy>=2.3.0.post1; python_version >= "3.10" and extra == "dev"
22
+ Requires-Dist: sqlglot-mypy>=2.3.0.post2; python_version >= "3.10" and extra == "dev"
23
23
  Requires-Dist: mypy; python_version < "3.10" and extra == "dev"
24
24
  Requires-Dist: setuptools_scm; extra == "dev"
25
25
  Requires-Dist: pandas; extra == "dev"
@@ -34,10 +34,10 @@ Requires-Dist: types-pytz; extra == "dev"
34
34
  Requires-Dist: typing_extensions; extra == "dev"
35
35
  Requires-Dist: pyperf; extra == "dev"
36
36
  Provides-Extra: c
37
- Requires-Dist: sqlglotc==30.17.0; python_version >= "3.10" and extra == "c"
37
+ Requires-Dist: sqlglotc==30.18.0; python_version >= "3.10" and extra == "c"
38
38
  Provides-Extra: rs
39
39
  Requires-Dist: sqlglotrs==0.13.0; extra == "rs"
40
- Requires-Dist: sqlglotc==30.17.0; python_version >= "3.10" and extra == "rs"
40
+ Requires-Dist: sqlglotc==30.18.0; python_version >= "3.10" and extra == "rs"
41
41
  Dynamic: license-file
42
42
  Dynamic: provides-extra
43
43
 
@@ -9,7 +9,7 @@ setup(
9
9
  "duckdb>=0.6",
10
10
  # sqlglot-mypy 1.20+ is the build dep for sqlglotc and only ships
11
11
  # for py3.10+; on py3.9 just use upstream mypy for type checking.
12
- "sqlglot-mypy >= 2.3.0.post1; python_version >= '3.10'",
12
+ "sqlglot-mypy >= 2.3.0.post2; python_version >= '3.10'",
13
13
  "mypy; python_version < '3.10'",
14
14
  "setuptools_scm",
15
15
  "pandas",
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '30.17.0'
22
- __version_tuple__ = version_tuple = (30, 17, 0)
21
+ __version__ = version = '30.18.0'
22
+ __version_tuple__ = version_tuple = (30, 18, 0)
23
23
 
24
- __commit_id__ = commit_id = 'g9a8129b6f'
24
+ __commit_id__ = commit_id = 'g2e86ded7d'
@@ -122,6 +122,8 @@ def __getattr__(name):
122
122
  if module_name:
123
123
  with _import_lock:
124
124
  module = importlib.import_module(f"sqlglot.dialects.{module_name}")
125
- return getattr(module, name)
125
+ attr = getattr(module, name)
126
+ globals()[name] = attr
127
+ return attr
126
128
 
127
129
  raise AttributeError(f"module {__name__} has no attribute {name}")
@@ -10,6 +10,7 @@ from sqlglot._typing import E
10
10
  from sqlglot.parsers.bigquery import BigQueryParser
11
11
  from sqlglot.generators.bigquery import BigQueryGenerator
12
12
  from sqlglot.dialects.dialect import (
13
+ ASCII_LOWER,
13
14
  Dialect,
14
15
  NormalizationStrategy,
15
16
  )
@@ -50,6 +51,7 @@ class BigQuery(Dialect):
50
51
 
51
52
  # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#case_sensitivity
52
53
  NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
54
+ ASCII_ONLY_NORMALIZATION = True
53
55
 
54
56
  # bigquery udfs are case sensitive
55
57
  NORMALIZE_FUNCTIONS = False
@@ -152,7 +154,7 @@ class BigQuery(Dialect):
152
154
  or expression.meta_get("is_table")
153
155
  )
154
156
  if not case_sensitive:
155
- expression.set("this", expression.this.lower())
157
+ expression.set("this", expression.this.translate(ASCII_LOWER))
156
158
 
157
159
  return t.cast(E, expression)
158
160
 
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import importlib
4
4
  import logging
5
+ import string
5
6
  import typing as t
6
7
  import sys
7
8
  from collections.abc import Iterable, MutableSequence
@@ -11,7 +12,7 @@ from builtins import type as Type
11
12
 
12
13
  from sqlglot import exp
13
14
  from sqlglot.dialects import DIALECT_MODULE_NAMES
14
- from sqlglot.errors import ParseError
15
+ from sqlglot.errors import ParseError, TokenError
15
16
  from sqlglot.generator import Generator, unsupported_args
16
17
  from sqlglot.expressions import apply_index_offset
17
18
  from sqlglot.helper import (
@@ -77,6 +78,9 @@ UNESCAPED_SEQUENCES = {
77
78
 
78
79
  PLUGIN_GROUP_NAME = "sqlglot.dialects"
79
80
 
81
+ ASCII_LOWER = str.maketrans(string.ascii_uppercase, string.ascii_lowercase)
82
+ ASCII_UPPER = str.maketrans(string.ascii_lowercase, string.ascii_uppercase)
83
+
80
84
 
81
85
  class Dialects(str, Enum):
82
86
  """Dialects supported by SQLGLot."""
@@ -375,6 +379,10 @@ class Dialect(metaclass=_Dialect):
375
379
  NORMALIZATION_STRATEGY = NormalizationStrategy.LOWERCASE
376
380
  """Specifies the strategy according to which identifiers should be normalized."""
377
381
 
382
+ ASCII_ONLY_NORMALIZATION = False
383
+ """Whether identifiers are only normalized with respect to ASCII characters, e.g. `Ä` and
384
+ `ä` are different identifiers in DuckDB, but the same identifier in Spark."""
385
+
378
386
  IDENTIFIERS_CAN_START_WITH_DIGIT = False
379
387
  """Whether an unquoted identifier can start with a digit."""
380
388
 
@@ -473,6 +481,9 @@ class Dialect(metaclass=_Dialect):
473
481
  For example, such columns may be excluded from `SELECT *` queries.
474
482
  """
475
483
 
484
+ SUPPORTS_POSITIONAL_COLUMN_REFS = False
485
+ """Whether qualified `$N` references the Nth column of their source."""
486
+
476
487
  PREFER_CTE_ALIAS_COLUMN = False
477
488
  """
478
489
  Some dialects, such as Snowflake, allow you to reference a CTE column alias in the
@@ -1079,15 +1090,22 @@ class Dialect(metaclass=_Dialect):
1079
1090
  )
1080
1091
  )
1081
1092
  ):
1082
- normalized = (
1083
- expression.this.upper()
1084
- if self.normalization_strategy
1085
- in (
1086
- NormalizationStrategy.UPPERCASE,
1087
- NormalizationStrategy.CASE_INSENSITIVE_UPPERCASE,
1093
+ if self.normalization_strategy in (
1094
+ NormalizationStrategy.UPPERCASE,
1095
+ NormalizationStrategy.CASE_INSENSITIVE_UPPERCASE,
1096
+ ):
1097
+ normalized = (
1098
+ expression.this.translate(ASCII_UPPER)
1099
+ if self.ASCII_ONLY_NORMALIZATION
1100
+ else expression.this.upper()
1088
1101
  )
1089
- else expression.this.lower()
1090
- )
1102
+ else:
1103
+ normalized = (
1104
+ expression.this.translate(ASCII_LOWER)
1105
+ if self.ASCII_ONLY_NORMALIZATION
1106
+ else expression.this.lower()
1107
+ )
1108
+
1091
1109
  expression.set("this", normalized)
1092
1110
 
1093
1111
  return expression
@@ -1157,7 +1175,7 @@ class Dialect(metaclass=_Dialect):
1157
1175
  path_text = f"[{path_text}]"
1158
1176
  try:
1159
1177
  return parse_json_path(path_text, self)
1160
- except ParseError as e:
1178
+ except (ParseError, TokenError) as e:
1161
1179
  if self.STRICT_JSON_PATH_SYNTAX and not path_text.lstrip().startswith(
1162
1180
  ("lax", "strict")
1163
1181
  ):
@@ -1247,12 +1265,20 @@ def if_sql(
1247
1265
  return _if_sql
1248
1266
 
1249
1267
 
1250
- def arrow_json_extract_sql(self: Generator, expression: JSON_EXTRACT_TYPE) -> str:
1268
+ def arrow_json_extract_sql(
1269
+ self: Generator,
1270
+ expression: JSON_EXTRACT_TYPE,
1271
+ op: str | None = None,
1272
+ ) -> str:
1251
1273
  this = expression.this
1252
1274
  if self.JSON_TYPE_REQUIRED_FOR_EXTRACTION and isinstance(this, exp.Literal) and this.is_string:
1253
1275
  this.replace(exp.cast(this, exp.DType.JSON))
1254
1276
 
1255
- return self.binary(expression, "->" if isinstance(expression, exp.JSONExtract) else "->>")
1277
+ if isinstance(expression.expression, (exp.Binary, exp.Predicate, exp.Not)):
1278
+ expression.set("expression", exp.paren(expression.expression, copy=False))
1279
+
1280
+ op = op or ("->" if isinstance(expression, exp.JSONExtract) else "->>")
1281
+ return self.binary(expression, op)
1256
1282
 
1257
1283
 
1258
1284
  def inline_array_sql(self: Generator, expression: exp.Expr) -> str:
@@ -1838,7 +1864,9 @@ def trim_sql(self: Generator, expression: exp.Trim, default_trim_type: str = "")
1838
1864
 
1839
1865
 
1840
1866
  def concat_to_dpipe_sql(self: Generator, expression: exp.Concat) -> str:
1841
- return self.sql(reduce(lambda x, y: exp.DPipe(this=x, expression=y), expression.expressions))
1867
+ return self.sql(
1868
+ reduce(lambda x, y: exp.DPipe(this=x, expression=y), self.convert_concat_args(expression))
1869
+ )
1842
1870
 
1843
1871
 
1844
1872
  def concat_ws_to_dpipe_sql(self: Generator, expression: exp.ConcatWs) -> str:
@@ -1901,7 +1929,7 @@ def binary_from_function(expr_type: Type[B]) -> t.Callable[[BuilderArgs], B]:
1901
1929
 
1902
1930
  # Used to represent DATE_TRUNC in Doris, Postgres and Starrocks dialects
1903
1931
  def build_timestamp_trunc(args: BuilderArgs) -> exp.TimestampTrunc:
1904
- return exp.TimestampTrunc(this=seq_get(args, 1), unit=seq_get(args, 0))
1932
+ return exp.TimestampTrunc(this=seq_get(args, 1), unit=seq_get(args, 0), zone=seq_get(args, 2))
1905
1933
 
1906
1934
 
1907
1935
  def build_trunc(
@@ -2623,6 +2651,16 @@ def regexp_replace_global_modifier(expression: exp.RegexpReplace) -> exp.Expr |
2623
2651
  return modifiers
2624
2652
 
2625
2653
 
2654
+ def nth_value_from_sql(self: Generator, expression: exp.NthValue) -> str:
2655
+ this = self.func("NTH_VALUE", expression.this, expression.args.get("offset"))
2656
+ from_first = expression.args.get("from_first")
2657
+
2658
+ if from_first is None:
2659
+ return this
2660
+
2661
+ return f"{this} FROM {'FIRST' if from_first else 'LAST'}"
2662
+
2663
+
2626
2664
  def getbit_sql(self: Generator, expression: exp.Getbit) -> str:
2627
2665
  """
2628
2666
  Generates SQL for Getbit according to DuckDB and Postgres, transpiling it if either:
@@ -28,6 +28,7 @@ class DuckDB(Dialect):
28
28
 
29
29
  # https://duckdb.org/docs/sql/introduction.html#creating-a-new-table
30
30
  NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
31
+ ASCII_ONLY_NORMALIZATION = True
31
32
 
32
33
  DATE_PART_MAPPING = {
33
34
  **Dialect.DATE_PART_MAPPING,
@@ -44,8 +44,11 @@ class MySQL(Dialect):
44
44
  "%u": "%W",
45
45
  "%k": "%-H",
46
46
  "%l": "%-I",
47
+ "%r": "%I:%M:%S %p",
47
48
  "%T": "%H:%M:%S",
48
49
  "%W": "%A",
50
+ "%x": "%G",
51
+ # %v (ISO week) is unmapped due to collision with %V (roundtrip issue)
49
52
  }
50
53
 
51
54
  VALID_INTERVAL_UNITS = {
@@ -11,6 +11,7 @@ from sqlglot.typing.postgres import EXPRESSION_METADATA
11
11
  class Postgres(Dialect):
12
12
  EXPRESSION_METADATA = EXPRESSION_METADATA.copy()
13
13
  INDEX_OFFSET = 1
14
+ ASCII_ONLY_NORMALIZATION = True
14
15
  # Normalizing `x IS NOT NULL` to `NOT x IS NULL` is unsafe due to row values,
15
16
  # e.g. `ROW(1, NULL) IS NOT NULL` is false whereas `NOT ROW(1, NULL) IS NULL` is true
16
17
  NORMALIZE_NOT_NULL = False
@@ -79,6 +80,8 @@ class Postgres(Dialect):
79
80
  HEREDOC_TAG_IS_IDENTIFIER = True
80
81
  HEREDOC_STRING_ALTERNATIVE = TokenType.PARAMETER
81
82
 
83
+ COMMANDS = {*tokens.Tokenizer.COMMANDS, TokenType.LOCK}
84
+
82
85
  KEYWORDS = {
83
86
  **tokens.Tokenizer.KEYWORDS,
84
87
  "~": TokenType.RLIKE,
@@ -22,6 +22,7 @@ class Snowflake(Dialect):
22
22
  TIME_FORMAT = "'YYYY-MM-DD HH24:MI:SS'"
23
23
  SUPPORTS_USER_DEFINED_TYPES = False
24
24
  PREFER_CTE_ALIAS_COLUMN = True
25
+ SUPPORTS_POSITIONAL_COLUMN_REFS = True
25
26
  TABLESAMPLE_SIZE_IS_PERCENT = True
26
27
  COPY_PARAMS_ARE_CSV = False
27
28
  ARRAY_AGG_INCLUDES_NULLS = None
@@ -13,6 +13,7 @@ from sqlglot.tokens import TokenType
13
13
  class SQLite(Dialect):
14
14
  # https://sqlite.org/forum/forumpost/5e575586ac5c711b?raw
15
15
  NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
16
+ ASCII_ONLY_NORMALIZATION = True
16
17
  TYPED_DIVISION = True
17
18
  SAFE_DIVISION = True
18
19
  SAFE_TO_ELIMINATE_DOUBLE_NEGATION = False
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from sqlglot import exp
3
4
  from sqlglot.dialects.mysql import MySQL
4
5
  from sqlglot.generators.starrocks import StarRocksGenerator
5
6
  from sqlglot.parsers.starrocks import StarRocksParser
@@ -10,6 +11,10 @@ class StarRocks(MySQL):
10
11
  STRICT_JSON_PATH_SYNTAX = False
11
12
  INDEX_OFFSET = 1
12
13
 
14
+ DEFAULT_FUNCTIONS_COLUMN_NAMES = {
15
+ exp.GenerateSeries: "generate_series",
16
+ }
17
+
13
18
  class Tokenizer(MySQL.Tokenizer):
14
19
  KEYWORDS = {
15
20
  **MySQL.Tokenizer.KEYWORDS,
@@ -19,6 +19,7 @@ class TSQL(Dialect):
19
19
  TYPED_DIVISION = True
20
20
  CONCAT_COALESCE = True
21
21
  CONCAT_WS_COALESCE = True
22
+ JSON_EXTRACT_SCALAR_SCALAR_ONLY = True
22
23
  NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
23
24
  ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False
24
25
 
@@ -19,16 +19,27 @@ class Context:
19
19
  evaluation of aggregation functions.
20
20
  """
21
21
 
22
- def __init__(self, tables: dict[str, Table], env: dict | None = None) -> None:
22
+ def __init__(
23
+ self, tables: dict[str, Table], env: dict | None = None, outer: dict | None = None
24
+ ) -> None:
23
25
  """
24
26
  Args
25
27
  tables: representing the scope of the current execution context.
26
28
  env: dictionary of functions within the execution context.
29
+ outer: readers of an enclosing query, for a subquery run once per outer row.
30
+ Own tables shadow them, as an inner alias shadows an outer one in SQL.
27
31
  """
28
32
  self.tables = tables
29
33
  self._table: Table | None = None
30
- self.range_readers = {name: table.range_reader for name, table in self.tables.items()}
31
- self.row_readers = {name: table.reader for name, table in tables.items()}
34
+ range_readers = {name: table.range_reader for name, table in self.tables.items()}
35
+ row_readers = {name: table.reader for name, table in tables.items()}
36
+
37
+ if outer:
38
+ range_readers = {**outer, **range_readers}
39
+ row_readers = {**outer, **row_readers}
40
+
41
+ self.range_readers = range_readers
42
+ self.row_readers = row_readers
32
43
  self.env = {**ENV, **(env or {}), "scope": self.row_readers}
33
44
 
34
45
  def eval(self, code):
@@ -56,7 +67,7 @@ class Context:
56
67
 
57
68
  @property
58
69
  def columns(self) -> tuple:
59
- return self.table.columns
70
+ return self.table.columns if self.tables else ()
60
71
 
61
72
  def __iter__(self):
62
73
  self.env["scope"] = self.row_readers
@@ -179,10 +179,15 @@ def cast(this, to):
179
179
  raise NotImplementedError(f"Casting {this} to '{to}' not implemented.")
180
180
 
181
181
 
182
+ FIRST = 0
183
+ LAST = 1
184
+ NULL_PLACEHOLDER = 0
185
+
186
+
182
187
  def ordered(this, desc, nulls_first):
183
- if desc:
184
- return reverse_key(this)
185
- return this
188
+ if this is None:
189
+ return (FIRST if nulls_first else LAST, NULL_PLACEHOLDER)
190
+ return (LAST if nulls_first else FIRST, reverse_key(this) if desc else this)
186
191
 
187
192
 
188
193
  def _like(this, e, flags=0):
@@ -199,6 +204,14 @@ def interval(this, unit):
199
204
  return datetime.timedelta(**{unit.lower(): float(this)})
200
205
 
201
206
 
207
+ @null_if_any
208
+ def arrayconcat(*args):
209
+ result = []
210
+ for arg in args:
211
+ result.extend(arg if isinstance(arg, list) else [arg])
212
+ return result
213
+
214
+
202
215
  @null_if_any("this", "expression")
203
216
  def arraytostring(this, expression, null=None):
204
217
  return expression.join(x for x in (x if x is not None else null for x in this) if x is not None)
@@ -235,6 +248,7 @@ ENV = {
235
248
  "ABS": null_if_any(lambda this: abs(this)),
236
249
  "ADD": null_if_any(lambda e, this: e + this),
237
250
  "ARRAYANY": null_if_any(lambda arr, func: any(func(e) for e in arr)),
251
+ "ARRAYCONCAT": arrayconcat,
238
252
  "ARRAYTOSTRING": arraytostring,
239
253
  "BETWEEN": null_if_any(lambda this, low, high: low <= this and this <= high),
240
254
  "BITWISEAND": null_if_any(lambda this, e: this & e),
@@ -257,6 +271,7 @@ ENV = {
257
271
  "GTE": null_if_any(lambda this, e: this >= e),
258
272
  "IF": lambda predicate, true, false: true if predicate else false,
259
273
  "IN": sql_in,
274
+ "INT": null_if_any(int),
260
275
  "INTDIV": null_if_any(lambda e, this: e // this),
261
276
  "INTERVAL": interval,
262
277
  "JSONEXTRACT": jsonextract,
@@ -275,7 +290,8 @@ ENV = {
275
290
  "NOT": sql_not,
276
291
  "OR": sql_or,
277
292
  "ORDERED": ordered,
278
- "POW": pow,
293
+ "POW": null_if_any(pow),
294
+ "REVERSE": null_if_any(lambda this: this[::-1]),
279
295
  "RIGHT": null_if_any(lambda this, e: this[-e:]),
280
296
  "ROUND": null_if_any(lambda this, decimals=None, truncate=None: round(this, ndigits=decimals)),
281
297
  "STRPOSITION": str_position,