1
0
Fork 0

Merging upstream version 26.8.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-03-04 07:54:36 +01:00
parent d551ab0954
commit 010433ad9a
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
61 changed files with 43883 additions and 41898 deletions

View file

@ -1,6 +1,134 @@
Changelog Changelog
========= =========
## [v26.7.0] - 2025-02-26
### :boom: BREAKING CHANGES
- due to [`466c839`](https://github.com/tobymao/sqlglot/commit/466c839c2cfc94b398dd619b738df165f2876cdb) - Remove extra MAP bracket and ARRAY wrap *(PR [#4712](https://github.com/tobymao/sqlglot/pull/4712) by [@VaggelisD](https://github.com/VaggelisD))*:
Remove extra MAP bracket and ARRAY wrap (#4712)
- due to [`79ab311`](https://github.com/tobymao/sqlglot/commit/79ab3116758c240786ab4353a26f1646e242a61b) - add generate_series table column alias *(PR [#4741](https://github.com/tobymao/sqlglot/pull/4741) by [@georgesittas](https://github.com/georgesittas))*:
add generate_series table column alias (#4741)
- due to [`66b3ea9`](https://github.com/tobymao/sqlglot/commit/66b3ea905af34cfedc961c68ba738ba90d16221d) - respect type nullability when casting in strtodate_sql *(PR [#4744](https://github.com/tobymao/sqlglot/pull/4744) by [@sleshJdev](https://github.com/sleshJdev))*:
respect type nullability when casting in strtodate_sql (#4744)
- due to [`91f47fe`](https://github.com/tobymao/sqlglot/commit/91f47fec2a8c727f7e4c93fa54b6f06a36a6b42f) - Support for exp.HexString in DuckDB/Presto/Trino *(PR [#4743](https://github.com/tobymao/sqlglot/pull/4743) by [@VaggelisD](https://github.com/VaggelisD))*:
Support for exp.HexString in DuckDB/Presto/Trino (#4743)
- due to [`0596176`](https://github.com/tobymao/sqlglot/commit/0596176dd59737f945624d6453259072917e2fee) - generate CASE expression instead of COUNT_IF for <v1.2 *(PR [#4755](https://github.com/tobymao/sqlglot/pull/4755) by [@georgesittas](https://github.com/georgesittas))*:
generate CASE expression instead of COUNT_IF for <v1.2 (#4755)
- due to [`01008a9`](https://github.com/tobymao/sqlglot/commit/01008a91144a20e830df3783ff04beba7d029fec) - enable transpilation of CURDATE fixes [#4758](https://github.com/tobymao/sqlglot/pull/4758) *(commit by [@georgesittas](https://github.com/georgesittas))*:
enable transpilation of CURDATE fixes #4758
- due to [`dc69192`](https://github.com/tobymao/sqlglot/commit/dc691923655d022f2a4b23e9df24a9d1518e7048) - column qualify not applying in an order by inside within group when it also the alias *(PR [#4780](https://github.com/tobymao/sqlglot/pull/4780) by [@ran-lakeway](https://github.com/ran-lakeway))*:
column qualify not applying in an order by inside within group when it also the alias (#4780)
- due to [`ae00c92`](https://github.com/tobymao/sqlglot/commit/ae00c9203197a436bdb81289580eba0e7fc374ec) - properly alias generate series *(PR [#4789](https://github.com/tobymao/sqlglot/pull/4789) by [@georgesittas](https://github.com/georgesittas))*:
properly alias generate series (#4789)
- due to [`14c3de9`](https://github.com/tobymao/sqlglot/commit/14c3de91072435a68dd8d0f024dff0a0fd236cb8) - parse unqualified names in DISTINCT ON (...) as identifiers *(PR [#4795](https://github.com/tobymao/sqlglot/pull/4795) by [@georgesittas](https://github.com/georgesittas))*:
parse unqualified names in DISTINCT ON (...) as identifiers (#4795)
- due to [`00c7f05`](https://github.com/tobymao/sqlglot/commit/00c7f05f348eeb6b60d4e70d7e29e564caf38f64) - do not coerce parameterized types *(PR [#4796](https://github.com/tobymao/sqlglot/pull/4796) by [@georgesittas](https://github.com/georgesittas))*:
do not coerce parameterized types (#4796)
- due to [`513fad4`](https://github.com/tobymao/sqlglot/commit/513fad47cd321fe8431e673351bdd5f0674d5af1) - show databases, functions, procedures and warehouses *(PR [#4787](https://github.com/tobymao/sqlglot/pull/4787) by [@tekumara](https://github.com/tekumara))*:
show databases, functions, procedures and warehouses (#4787)
- due to [`a9ae2d2`](https://github.com/tobymao/sqlglot/commit/a9ae2d229640f22134410ca5826c6f19df7ef523) - support TOP with PERCENT and WITH TIES *(PR [#4801](https://github.com/tobymao/sqlglot/pull/4801) by [@geooo109](https://github.com/geooo109))*:
support TOP with PERCENT and WITH TIES (#4801)
- due to [`e05983a`](https://github.com/tobymao/sqlglot/commit/e05983a62ee9b3689e8a277924f2b1e36744a2a9) - make hex literal tokenization more robust *(PR [#4802](https://github.com/tobymao/sqlglot/pull/4802) by [@georgesittas](https://github.com/georgesittas))*:
make hex literal tokenization more robust (#4802)
- due to [`e9c8eae`](https://github.com/tobymao/sqlglot/commit/e9c8eae060c05d02f6f65916d59f1792098679c8) - bump sqlglotrs to 0.4.0 *(commit by [@georgesittas](https://github.com/georgesittas))*:
bump sqlglotrs to 0.4.0
### :sparkles: New Features
- [`5c59943`](https://github.com/tobymao/sqlglot/commit/5c599434fbe4d4f1059196b1530d02d7d204d3a9) - **mysql**: add unsigned double type *(PR [#4734](https://github.com/tobymao/sqlglot/pull/4734) by [@GabrielVSMachado](https://github.com/GabrielVSMachado))*
- [`31b2139`](https://github.com/tobymao/sqlglot/commit/31b21391cc521cf15a098c335d4202378ad96c0b) - **duckdb**: transpile JSONB into JSON *(PR [#4753](https://github.com/tobymao/sqlglot/pull/4753) by [@georgesittas](https://github.com/georgesittas))*
- [`0596176`](https://github.com/tobymao/sqlglot/commit/0596176dd59737f945624d6453259072917e2fee) - **duckdb**: generate CASE expression instead of COUNT_IF for <v1.2 *(PR [#4755](https://github.com/tobymao/sqlglot/pull/4755) by [@georgesittas](https://github.com/georgesittas))*
- [`2b3ec0f`](https://github.com/tobymao/sqlglot/commit/2b3ec0fbd6bd84dd893c244892fc1a63e2eab7bd) - **snowflake**: add support for USE SECONDARY ROLES *(PR [#4761](https://github.com/tobymao/sqlglot/pull/4761) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *addresses issue [#4760](https://github.com/tobymao/sqlglot/issues/4760) opened by [@merlindso](https://github.com/merlindso)*
- [`2079bdb`](https://github.com/tobymao/sqlglot/commit/2079bdbb5d72d7fe02019a9ba6d1684403e30b00) - **postgres**: Add support for WITH RECURSIVE search options *(PR [#4773](https://github.com/tobymao/sqlglot/pull/4773) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *addresses issue [#4763](https://github.com/tobymao/sqlglot/issues/4763) opened by [@psanjeev-cellino](https://github.com/psanjeev-cellino)*
- [`70eefc6`](https://github.com/tobymao/sqlglot/commit/70eefc694c20600cdd99d682393cae81812d0b00) - **duckdb**: add support for underscored numbers fixes [#4777](https://github.com/tobymao/sqlglot/pull/4777) *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`f6be1d4`](https://github.com/tobymao/sqlglot/commit/f6be1d4b2c34ea4e3e98c3ae5e272e2f2b1912f3) - **clickhouse**: add support for dynamic json casting *(PR [#4784](https://github.com/tobymao/sqlglot/pull/4784) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *addresses issue [#4776](https://github.com/tobymao/sqlglot/issues/4776) opened by [@pkit](https://github.com/pkit)*
- [`513fad4`](https://github.com/tobymao/sqlglot/commit/513fad47cd321fe8431e673351bdd5f0674d5af1) - **snowflake**: show databases, functions, procedures and warehouses *(PR [#4787](https://github.com/tobymao/sqlglot/pull/4787) by [@tekumara](https://github.com/tekumara))*
- [`575c979`](https://github.com/tobymao/sqlglot/commit/575c979b77831bd356cc7e9b39e78fcca2b344be) - **clickhouse**: support `GLOBAL NOT IN` *(PR [#4798](https://github.com/tobymao/sqlglot/pull/4798) by [@hdhoang](https://github.com/hdhoang))*
- [`856faa9`](https://github.com/tobymao/sqlglot/commit/856faa9773dea3b214571932c7d65e5773c5dc76) - **mysql**: add support for `ALTER INDEX` *(PR [#4800](https://github.com/tobymao/sqlglot/pull/4800) by [@burnison](https://github.com/burnison))*
### :bug: Bug Fixes
- [`7cad7f0`](https://github.com/tobymao/sqlglot/commit/7cad7f06d676bf230238bf08aea91701e1fa1d95) - Add additional allowed tokens for parsing aggregate functions in DDL *(PR [#4727](https://github.com/tobymao/sqlglot/pull/4727) by [@dorranh](https://github.com/dorranh))*
- :arrow_lower_right: *fixes issue [#4723](https://github.com/tobymao/sqlglot/issues/4723) opened by [@dorranh](https://github.com/dorranh)*
- [`466c839`](https://github.com/tobymao/sqlglot/commit/466c839c2cfc94b398dd619b738df165f2876cdb) - **duckdb**: Remove extra MAP bracket and ARRAY wrap *(PR [#4712](https://github.com/tobymao/sqlglot/pull/4712) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4710](https://github.com/tobymao/sqlglot/issues/4710) opened by [@eakmanrq](https://github.com/eakmanrq)*
- [`2c7dbe2`](https://github.com/tobymao/sqlglot/commit/2c7dbe2f84fcba044881776ebdeed6ee980fe0dd) - **duckdb**: Fix INTERVAL roundtrip of DATE_ADD *(PR [#4732](https://github.com/tobymao/sqlglot/pull/4732) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4728](https://github.com/tobymao/sqlglot/issues/4728) opened by [@whao89](https://github.com/whao89)*
- [`cbad48d`](https://github.com/tobymao/sqlglot/commit/cbad48d4102412ea3fd20272cf75974a8c53bb34) - infinite traversal in eliminate_qualify closes [#4735](https://github.com/tobymao/sqlglot/pull/4735) *(commit by [@tobymao](https://github.com/tobymao))*
- [`79ab311`](https://github.com/tobymao/sqlglot/commit/79ab3116758c240786ab4353a26f1646e242a61b) - **clickhouse**: add generate_series table column alias *(PR [#4741](https://github.com/tobymao/sqlglot/pull/4741) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#4740](https://github.com/tobymao/sqlglot/issues/4740) opened by [@martijnthe](https://github.com/martijnthe)*
- [`f0ce5ce`](https://github.com/tobymao/sqlglot/commit/f0ce5ce80d5a0ac24da4295a2f660bad9d7934be) - **snowflake**: unqualify ANY ORDER BY columns *(PR [#4737](https://github.com/tobymao/sqlglot/pull/4737) by [@georgesittas](https://github.com/georgesittas))*
- [`66b3ea9`](https://github.com/tobymao/sqlglot/commit/66b3ea905af34cfedc961c68ba738ba90d16221d) - **clickhouse**: respect type nullability when casting in strtodate_sql *(PR [#4744](https://github.com/tobymao/sqlglot/pull/4744) by [@sleshJdev](https://github.com/sleshJdev))*
- [`fda40a9`](https://github.com/tobymao/sqlglot/commit/fda40a9e670f30822dee05651d2336494c0d4f3b) - **clickhouse**: add BOTH if trim type is unspecified fixes [#4746](https://github.com/tobymao/sqlglot/pull/4746) *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`91f47fe`](https://github.com/tobymao/sqlglot/commit/91f47fec2a8c727f7e4c93fa54b6f06a36a6b42f) - Support for exp.HexString in DuckDB/Presto/Trino *(PR [#4743](https://github.com/tobymao/sqlglot/pull/4743) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4739](https://github.com/tobymao/sqlglot/issues/4739) opened by [@sk-](https://github.com/sk-)*
- [`f94656d`](https://github.com/tobymao/sqlglot/commit/f94656d06b118cee69ec8305fde948caa250cb69) - **clickhouse**: Generation of exp.ArrayConcat *(PR [#4754](https://github.com/tobymao/sqlglot/pull/4754) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4751](https://github.com/tobymao/sqlglot/issues/4751) opened by [@maximlipiev](https://github.com/maximlipiev)*
- [`cf33711`](https://github.com/tobymao/sqlglot/commit/cf337114a2259058b2a8cbde22d0a560001df9a5) - **tokenizer-rs**: use is_whitespace in token scan loop *(PR [#4756](https://github.com/tobymao/sqlglot/pull/4756) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#4748](https://github.com/tobymao/sqlglot/issues/4748) opened by [@gesoges0](https://github.com/gesoges0)*
- [`01008a9`](https://github.com/tobymao/sqlglot/commit/01008a91144a20e830df3783ff04beba7d029fec) - **mysql**: enable transpilation of CURDATE fixes [#4758](https://github.com/tobymao/sqlglot/pull/4758) *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`1fbd108`](https://github.com/tobymao/sqlglot/commit/1fbd108e8e9b85ae873bb702ff8f73c5ae94b392) - **sqlite**: correct json key value pair separator *(PR [#4774](https://github.com/tobymao/sqlglot/pull/4774) by [@geooo109](https://github.com/geooo109))*
- :arrow_lower_right: *fixes issue [#4770](https://github.com/tobymao/sqlglot/issues/4770) opened by [@ori-n](https://github.com/ori-n)*
- [`ccdb92a`](https://github.com/tobymao/sqlglot/commit/ccdb92a7b676d3454cf9f6a18a2b0becec676169) - **optimizer**: do not qualify ctes that are pivoted *(PR [#4775](https://github.com/tobymao/sqlglot/pull/4775) by [@georgesittas](https://github.com/georgesittas))*
- [`ec4e97c`](https://github.com/tobymao/sqlglot/commit/ec4e97c31c16a1c8b5eb1acfba0ef77f064505b4) - **parser**: Do not preemptively create chunks for comment only statements *(PR [#4772](https://github.com/tobymao/sqlglot/pull/4772) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4762](https://github.com/tobymao/sqlglot/issues/4762) opened by [@dbittenbender](https://github.com/dbittenbender)*
- [`fc8aec3`](https://github.com/tobymao/sqlglot/commit/fc8aec35b211395ca603b2feabd1e5a5006fd677) - **parser**: Revert [#4772](https://github.com/tobymao/sqlglot/pull/4772) *(PR [#4783](https://github.com/tobymao/sqlglot/pull/4783) by [@VaggelisD](https://github.com/VaggelisD))*
- [`dc69192`](https://github.com/tobymao/sqlglot/commit/dc691923655d022f2a4b23e9df24a9d1518e7048) - **optimizer**: column qualify not applying in an order by inside within group when it also the alias *(PR [#4780](https://github.com/tobymao/sqlglot/pull/4780) by [@ran-lakeway](https://github.com/ran-lakeway))*
- [`ae00c92`](https://github.com/tobymao/sqlglot/commit/ae00c9203197a436bdb81289580eba0e7fc374ec) - **postgres**: properly alias generate series *(PR [#4789](https://github.com/tobymao/sqlglot/pull/4789) by [@georgesittas](https://github.com/georgesittas))*
- [`14c3de9`](https://github.com/tobymao/sqlglot/commit/14c3de91072435a68dd8d0f024dff0a0fd236cb8) - **optimizer**: parse unqualified names in DISTINCT ON (...) as identifiers *(PR [#4795](https://github.com/tobymao/sqlglot/pull/4795) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#4791](https://github.com/tobymao/sqlglot/issues/4791) opened by [@Fosly](https://github.com/Fosly)*
- [`00c7f05`](https://github.com/tobymao/sqlglot/commit/00c7f05f348eeb6b60d4e70d7e29e564caf38f64) - **optimizer**: do not coerce parameterized types *(PR [#4796](https://github.com/tobymao/sqlglot/pull/4796) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#4792](https://github.com/tobymao/sqlglot/issues/4792) opened by [@georgesittas](https://github.com/georgesittas)*
- [`9f6b4f7`](https://github.com/tobymao/sqlglot/commit/9f6b4f7dd6ea8eb80d8d5d3b75eeff9e262ceba2) - **snowflake**: add missing clauses in SHOW statements *(PR [#4797](https://github.com/tobymao/sqlglot/pull/4797) by [@georgesittas](https://github.com/georgesittas))*
- [`a9ae2d2`](https://github.com/tobymao/sqlglot/commit/a9ae2d229640f22134410ca5826c6f19df7ef523) - **tsql**: support TOP with PERCENT and WITH TIES *(PR [#4801](https://github.com/tobymao/sqlglot/pull/4801) by [@geooo109](https://github.com/geooo109))*
- :arrow_lower_right: *fixes issue [#4793](https://github.com/tobymao/sqlglot/issues/4793) opened by [@gleb-daax](https://github.com/gleb-daax)*
- [`e05983a`](https://github.com/tobymao/sqlglot/commit/e05983a62ee9b3689e8a277924f2b1e36744a2a9) - **tokenizer-rs**: make hex literal tokenization more robust *(PR [#4802](https://github.com/tobymao/sqlglot/pull/4802) by [@georgesittas](https://github.com/georgesittas))*
### :wrench: Chores
- [`6c4c69e`](https://github.com/tobymao/sqlglot/commit/6c4c69e95d504ec839f7abd571eb2f614ea3c9ca) - move t-sql generators to base, clean up set_sql *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`4bf897d`](https://github.com/tobymao/sqlglot/commit/4bf897da6332175c22b772beb0b0cb6e6e941ebb) - remove redundant "parts" arg from CH ast, move gen methods to base *(PR [#4779](https://github.com/tobymao/sqlglot/pull/4779) by [@georgesittas](https://github.com/georgesittas))*
- [`e9c8eae`](https://github.com/tobymao/sqlglot/commit/e9c8eae060c05d02f6f65916d59f1792098679c8) - bump sqlglotrs to 0.4.0 *(commit by [@georgesittas](https://github.com/georgesittas))*
## [v26.6.0] - 2025-02-10
### :boom: BREAKING CHANGES
- due to [`a790e41`](https://github.com/tobymao/sqlglot/commit/a790e41736884bde7a8172f458db92d80064556f) - avoid redundant casts in FROM/TO_UTC_TIMESTAMP *(PR [#4725](https://github.com/tobymao/sqlglot/pull/4725) by [@georgesittas](https://github.com/georgesittas))*:
avoid redundant casts in FROM/TO_UTC_TIMESTAMP (#4725)
### :bug: Bug Fixes
- [`a790e41`](https://github.com/tobymao/sqlglot/commit/a790e41736884bde7a8172f458db92d80064556f) - **spark**: avoid redundant casts in FROM/TO_UTC_TIMESTAMP *(PR [#4725](https://github.com/tobymao/sqlglot/pull/4725) by [@georgesittas](https://github.com/georgesittas))*
## [v26.5.0] - 2025-02-10 ## [v26.5.0] - 2025-02-10
### :boom: BREAKING CHANGES ### :boom: BREAKING CHANGES
- due to [`da52181`](https://github.com/tobymao/sqlglot/commit/da52181f1cd3ec22e5ac597de50036278d2e66e5) - TO_DATE parsing with safe flag true *(PR [#4713](https://github.com/tobymao/sqlglot/pull/4713) by [@geooo109](https://github.com/geooo109))*: - due to [`da52181`](https://github.com/tobymao/sqlglot/commit/da52181f1cd3ec22e5ac597de50036278d2e66e5) - TO_DATE parsing with safe flag true *(PR [#4713](https://github.com/tobymao/sqlglot/pull/4713) by [@geooo109](https://github.com/geooo109))*:
@ -5873,3 +6001,5 @@ Changelog
[v26.4.0]: https://github.com/tobymao/sqlglot/compare/v26.3.9...v26.4.0 [v26.4.0]: https://github.com/tobymao/sqlglot/compare/v26.3.9...v26.4.0
[v26.4.1]: https://github.com/tobymao/sqlglot/compare/v26.4.0...v26.4.1 [v26.4.1]: https://github.com/tobymao/sqlglot/compare/v26.4.0...v26.4.1
[v26.5.0]: https://github.com/tobymao/sqlglot/compare/v26.4.1...v26.5.0 [v26.5.0]: https://github.com/tobymao/sqlglot/compare/v26.4.1...v26.5.0
[v26.6.0]: https://github.com/tobymao/sqlglot/compare/v26.5.0...v26.6.0
[v26.7.0]: https://github.com/tobymao/sqlglot/compare/v26.6.0...v26.7.0

File diff suppressed because one or more lines are too long

View file

@ -31,7 +31,10 @@
<h2>API Documentation</h2> <h2>API Documentation</h2>
<ul class="memberlist"> <ul class="memberlist">
<li> <li>
<a class="variable" href="#TYPE_CHECKING">TYPE_CHECKING</a> <a class="variable" href="#__version__">__version__</a>
</li>
<li>
<a class="variable" href="#__version_tuple__">__version_tuple__</a>
</li> </li>
<li> <li>
<a class="variable" href="#version">version</a> <a class="variable" href="#version">version</a>
@ -62,34 +65,51 @@
<label class="view-source-button" for="mod-_version-view-source"><span>View Source</span></label> <label class="view-source-button" for="mod-_version-view-source"><span>View Source</span></label>
<div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos"> 1</span></a><span class="c1"># file generated by setuptools_scm</span> <div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos"> 1</span></a><span class="c1"># file generated by setuptools-scm</span>
</span><span id="L-2"><a href="#L-2"><span class="linenos"> 2</span></a><span class="c1"># don&#39;t change, don&#39;t track in version control</span> </span><span id="L-2"><a href="#L-2"><span class="linenos"> 2</span></a><span class="c1"># don&#39;t change, don&#39;t track in version control</span>
</span><span id="L-3"><a href="#L-3"><span class="linenos"> 3</span></a><span class="n">TYPE_CHECKING</span> <span class="o">=</span> <span class="kc">False</span> </span><span id="L-3"><a href="#L-3"><span class="linenos"> 3</span></a>
</span><span id="L-4"><a href="#L-4"><span class="linenos"> 4</span></a><span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span> </span><span id="L-4"><a href="#L-4"><span class="linenos"> 4</span></a><span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;__version__&quot;</span><span class="p">,</span> <span class="s2">&quot;__version_tuple__&quot;</span><span class="p">,</span> <span class="s2">&quot;version&quot;</span><span class="p">,</span> <span class="s2">&quot;version_tuple&quot;</span><span class="p">]</span>
</span><span id="L-5"><a href="#L-5"><span class="linenos"> 5</span></a> <span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Tuple</span><span class="p">,</span> <span class="n">Union</span> </span><span id="L-5"><a href="#L-5"><span class="linenos"> 5</span></a>
</span><span id="L-6"><a href="#L-6"><span class="linenos"> 6</span></a> <span class="n">VERSION_TUPLE</span> <span class="o">=</span> <span class="n">Tuple</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">],</span> <span class="o">...</span><span class="p">]</span> </span><span id="L-6"><a href="#L-6"><span class="linenos"> 6</span></a><span class="n">TYPE_CHECKING</span> <span class="o">=</span> <span class="kc">False</span>
</span><span id="L-7"><a href="#L-7"><span class="linenos"> 7</span></a><span class="k">else</span><span class="p">:</span> </span><span id="L-7"><a href="#L-7"><span class="linenos"> 7</span></a><span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
</span><span id="L-8"><a href="#L-8"><span class="linenos"> 8</span></a> <span class="n">VERSION_TUPLE</span> <span class="o">=</span> <span class="nb">object</span> </span><span id="L-8"><a href="#L-8"><span class="linenos"> 8</span></a> <span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Tuple</span>
</span><span id="L-9"><a href="#L-9"><span class="linenos"> 9</span></a> </span><span id="L-9"><a href="#L-9"><span class="linenos"> 9</span></a> <span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Union</span>
</span><span id="L-10"><a href="#L-10"><span class="linenos">10</span></a><span class="n">version</span><span class="p">:</span> <span class="nb">str</span> </span><span id="L-10"><a href="#L-10"><span class="linenos">10</span></a>
</span><span id="L-11"><a href="#L-11"><span class="linenos">11</span></a><span class="n">__version__</span><span class="p">:</span> <span class="nb">str</span> </span><span id="L-11"><a href="#L-11"><span class="linenos">11</span></a> <span class="n">VERSION_TUPLE</span> <span class="o">=</span> <span class="n">Tuple</span><span class="p">[</span><span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">],</span> <span class="o">...</span><span class="p">]</span>
</span><span id="L-12"><a href="#L-12"><span class="linenos">12</span></a><span class="n">__version_tuple__</span><span class="p">:</span> <span class="n">VERSION_TUPLE</span> </span><span id="L-12"><a href="#L-12"><span class="linenos">12</span></a><span class="k">else</span><span class="p">:</span>
</span><span id="L-13"><a href="#L-13"><span class="linenos">13</span></a><span class="n">version_tuple</span><span class="p">:</span> <span class="n">VERSION_TUPLE</span> </span><span id="L-13"><a href="#L-13"><span class="linenos">13</span></a> <span class="n">VERSION_TUPLE</span> <span class="o">=</span> <span class="nb">object</span>
</span><span id="L-14"><a href="#L-14"><span class="linenos">14</span></a> </span><span id="L-14"><a href="#L-14"><span class="linenos">14</span></a>
</span><span id="L-15"><a href="#L-15"><span class="linenos">15</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;26.5.0&#39;</span> </span><span id="L-15"><a href="#L-15"><span class="linenos">15</span></a><span class="n">version</span><span class="p">:</span> <span class="nb">str</span>
</span><span id="L-16"><a href="#L-16"><span class="linenos">16</span></a><span class="n">__version_tuple__</span> <span class="o">=</span> <span class="n">version_tuple</span> <span class="o">=</span> <span class="p">(</span><span class="mi">26</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> </span><span id="L-16"><a href="#L-16"><span class="linenos">16</span></a><span class="n">__version__</span><span class="p">:</span> <span class="nb">str</span>
</span><span id="L-17"><a href="#L-17"><span class="linenos">17</span></a><span class="n">__version_tuple__</span><span class="p">:</span> <span class="n">VERSION_TUPLE</span>
</span><span id="L-18"><a href="#L-18"><span class="linenos">18</span></a><span class="n">version_tuple</span><span class="p">:</span> <span class="n">VERSION_TUPLE</span>
</span><span id="L-19"><a href="#L-19"><span class="linenos">19</span></a>
</span><span id="L-20"><a href="#L-20"><span class="linenos">20</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;26.7.0&#39;</span>
</span><span id="L-21"><a href="#L-21"><span class="linenos">21</span></a><span class="n">__version_tuple__</span> <span class="o">=</span> <span class="n">version_tuple</span> <span class="o">=</span> <span class="p">(</span><span class="mi">26</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></pre></div> </span></pre></div>
</section> </section>
<section id="TYPE_CHECKING"> <section id="__version__">
<div class="attr variable"> <div class="attr variable">
<span class="name">TYPE_CHECKING</span> = <span class="name">__version__</span><span class="annotation">: str</span> =
<span class="default_value">False</span> <span class="default_value">&#39;26.7.0&#39;</span>
</div> </div>
<a class="headerlink" href="#TYPE_CHECKING"></a> <a class="headerlink" href="#__version__"></a>
</section>
<section id="__version_tuple__">
<div class="attr variable">
<span class="name">__version_tuple__</span><span class="annotation">: object</span> =
<span class="default_value">(26, 7, 0)</span>
</div>
<a class="headerlink" href="#__version_tuple__"></a>
@ -97,7 +117,7 @@
<section id="version"> <section id="version">
<div class="attr variable"> <div class="attr variable">
<span class="name">version</span><span class="annotation">: str</span> = <span class="name">version</span><span class="annotation">: str</span> =
<span class="default_value">&#39;26.5.0&#39;</span> <span class="default_value">&#39;26.7.0&#39;</span>
</div> </div>
@ -109,7 +129,7 @@
<section id="version_tuple"> <section id="version_tuple">
<div class="attr variable"> <div class="attr variable">
<span class="name">version_tuple</span><span class="annotation">: object</span> = <span class="name">version_tuple</span><span class="annotation">: object</span> =
<span class="default_value">(26, 5, 0)</span> <span class="default_value">(26, 7, 0)</span>
</div> </div>

View file

@ -325,7 +325,7 @@ dialect implementations in order to understand how their various components can
<section id="Athena"> <section id="Athena">
<div class="attr variable"> <div class="attr variable">
<span class="name">Athena</span> = <span class="name">Athena</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990150988080&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462755349024&#39;&gt;</span>
</div> </div>
@ -337,7 +337,7 @@ dialect implementations in order to understand how their various components can
<section id="BigQuery"> <section id="BigQuery">
<div class="attr variable"> <div class="attr variable">
<span class="name">BigQuery</span> = <span class="name">BigQuery</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990155292544&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462741502272&#39;&gt;</span>
</div> </div>
@ -349,7 +349,7 @@ dialect implementations in order to understand how their various components can
<section id="ClickHouse"> <section id="ClickHouse">
<div class="attr variable"> <div class="attr variable">
<span class="name">ClickHouse</span> = <span class="name">ClickHouse</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990146633968&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462754762032&#39;&gt;</span>
</div> </div>
@ -361,7 +361,7 @@ dialect implementations in order to understand how their various components can
<section id="Databricks"> <section id="Databricks">
<div class="attr variable"> <div class="attr variable">
<span class="name">Databricks</span> = <span class="name">Databricks</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990146641264&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462742589632&#39;&gt;</span>
</div> </div>
@ -373,7 +373,7 @@ dialect implementations in order to understand how their various components can
<section id="Doris"> <section id="Doris">
<div class="attr variable"> <div class="attr variable">
<span class="name">Doris</span> = <span class="name">Doris</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990155444768&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462742590208&#39;&gt;</span>
</div> </div>
@ -385,7 +385,7 @@ dialect implementations in order to understand how their various components can
<section id="Drill"> <section id="Drill">
<div class="attr variable"> <div class="attr variable">
<span class="name">Drill</span> = <span class="name">Drill</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990142497552&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462740790416&#39;&gt;</span>
</div> </div>
@ -397,7 +397,7 @@ dialect implementations in order to understand how their various components can
<section id="Druid"> <section id="Druid">
<div class="attr variable"> <div class="attr variable">
<span class="name">Druid</span> = <span class="name">Druid</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990140097664&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462740798336&#39;&gt;</span>
</div> </div>
@ -409,7 +409,7 @@ dialect implementations in order to understand how their various components can
<section id="DuckDB"> <section id="DuckDB">
<div class="attr variable"> <div class="attr variable">
<span class="name">DuckDB</span> = <span class="name">DuckDB</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990145643760&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462741187664&#39;&gt;</span>
</div> </div>
@ -421,7 +421,7 @@ dialect implementations in order to understand how their various components can
<section id="Dune"> <section id="Dune">
<div class="attr variable"> <div class="attr variable">
<span class="name">Dune</span> = <span class="name">Dune</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990155886064&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462745526160&#39;&gt;</span>
</div> </div>
@ -433,7 +433,7 @@ dialect implementations in order to understand how their various components can
<section id="Hive"> <section id="Hive">
<div class="attr variable"> <div class="attr variable">
<span class="name">Hive</span> = <span class="name">Hive</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990155879632&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462750759136&#39;&gt;</span>
</div> </div>
@ -445,7 +445,7 @@ dialect implementations in order to understand how their various components can
<section id="Materialize"> <section id="Materialize">
<div class="attr variable"> <div class="attr variable">
<span class="name">Materialize</span> = <span class="name">Materialize</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990155535520&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462751357952&#39;&gt;</span>
</div> </div>
@ -457,7 +457,7 @@ dialect implementations in order to understand how their various components can
<section id="MySQL"> <section id="MySQL">
<div class="attr variable"> <div class="attr variable">
<span class="name">MySQL</span> = <span class="name">MySQL</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990145679760&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462751363424&#39;&gt;</span>
</div> </div>
@ -469,7 +469,7 @@ dialect implementations in order to understand how their various components can
<section id="Oracle"> <section id="Oracle">
<div class="attr variable"> <div class="attr variable">
<span class="name">Oracle</span> = <span class="name">Oracle</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990144694544&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462755217712&#39;&gt;</span>
</div> </div>
@ -481,7 +481,7 @@ dialect implementations in order to understand how their various components can
<section id="Postgres"> <section id="Postgres">
<div class="attr variable"> <div class="attr variable">
<span class="name">Postgres</span> = <span class="name">Postgres</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990144681200&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462755233024&#39;&gt;</span>
</div> </div>
@ -493,7 +493,7 @@ dialect implementations in order to understand how their various components can
<section id="Presto"> <section id="Presto">
<div class="attr variable"> <div class="attr variable">
<span class="name">Presto</span> = <span class="name">Presto</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990155130576&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462756443568&#39;&gt;</span>
</div> </div>
@ -505,7 +505,7 @@ dialect implementations in order to understand how their various components can
<section id="PRQL"> <section id="PRQL">
<div class="attr variable"> <div class="attr variable">
<span class="name">PRQL</span> = <span class="name">PRQL</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990156080368&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462755122432&#39;&gt;</span>
</div> </div>
@ -517,7 +517,7 @@ dialect implementations in order to understand how their various components can
<section id="Redshift"> <section id="Redshift">
<div class="attr variable"> <div class="attr variable">
<span class="name">Redshift</span> = <span class="name">Redshift</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990156070864&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462755125120&#39;&gt;</span>
</div> </div>
@ -529,7 +529,7 @@ dialect implementations in order to understand how their various components can
<section id="RisingWave"> <section id="RisingWave">
<div class="attr variable"> <div class="attr variable">
<span class="name">RisingWave</span> = <span class="name">RisingWave</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990147260640&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462756817904&#39;&gt;</span>
</div> </div>
@ -541,7 +541,7 @@ dialect implementations in order to understand how their various components can
<section id="Snowflake"> <section id="Snowflake">
<div class="attr variable"> <div class="attr variable">
<span class="name">Snowflake</span> = <span class="name">Snowflake</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990147258336&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462743195648&#39;&gt;</span>
</div> </div>
@ -553,7 +553,7 @@ dialect implementations in order to understand how their various components can
<section id="Spark"> <section id="Spark">
<div class="attr variable"> <div class="attr variable">
<span class="name">Spark</span> = <span class="name">Spark</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990155948672&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462755039024&#39;&gt;</span>
</div> </div>
@ -565,7 +565,7 @@ dialect implementations in order to understand how their various components can
<section id="Spark2"> <section id="Spark2">
<div class="attr variable"> <div class="attr variable">
<span class="name">Spark2</span> = <span class="name">Spark2</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990154264192&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462746722960&#39;&gt;</span>
</div> </div>
@ -577,7 +577,7 @@ dialect implementations in order to understand how their various components can
<section id="SQLite"> <section id="SQLite">
<div class="attr variable"> <div class="attr variable">
<span class="name">SQLite</span> = <span class="name">SQLite</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990145087616&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462742002304&#39;&gt;</span>
</div> </div>
@ -589,7 +589,7 @@ dialect implementations in order to understand how their various components can
<section id="StarRocks"> <section id="StarRocks">
<div class="attr variable"> <div class="attr variable">
<span class="name">StarRocks</span> = <span class="name">StarRocks</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990142730592&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462742011664&#39;&gt;</span>
</div> </div>
@ -601,7 +601,7 @@ dialect implementations in order to understand how their various components can
<section id="Tableau"> <section id="Tableau">
<div class="attr variable"> <div class="attr variable">
<span class="name">Tableau</span> = <span class="name">Tableau</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990155788928&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462741692736&#39;&gt;</span>
</div> </div>
@ -613,7 +613,7 @@ dialect implementations in order to understand how their various components can
<section id="Teradata"> <section id="Teradata">
<div class="attr variable"> <div class="attr variable">
<span class="name">Teradata</span> = <span class="name">Teradata</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990146321568&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462745788496&#39;&gt;</span>
</div> </div>
@ -625,7 +625,7 @@ dialect implementations in order to understand how their various components can
<section id="Trino"> <section id="Trino">
<div class="attr variable"> <div class="attr variable">
<span class="name">Trino</span> = <span class="name">Trino</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990140471472&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462753877488&#39;&gt;</span>
</div> </div>
@ -637,7 +637,7 @@ dialect implementations in order to understand how their various components can
<section id="TSQL"> <section id="TSQL">
<div class="attr variable"> <div class="attr variable">
<span class="name">TSQL</span> = <span class="name">TSQL</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990140479392&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462753885648&#39;&gt;</span>
</div> </div>
@ -649,7 +649,7 @@ dialect implementations in order to understand how their various components can
<section id="Dialect"> <section id="Dialect">
<div class="attr variable"> <div class="attr variable">
<span class="name">Dialect</span> = <span class="name">Dialect</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990140487376&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462739461584&#39;&gt;</span>
</div> </div>
@ -661,7 +661,7 @@ dialect implementations in order to understand how their various components can
<section id="Dialects"> <section id="Dialects">
<div class="attr variable"> <div class="attr variable">
<span class="name">Dialects</span> = <span class="name">Dialects</span> =
<span class="default_value">&lt;MagicMock id=&#39;139990140495296&#39;&gt;</span> <span class="default_value">&lt;MagicMock id=&#39;140462739469504&#39;&gt;</span>
</div> </div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -1920,7 +1920,7 @@ belong to some totally-ordered set.</p>
<section id="DATE_UNITS"> <section id="DATE_UNITS">
<div class="attr variable"> <div class="attr variable">
<span class="name">DATE_UNITS</span> = <span class="name">DATE_UNITS</span> =
<span class="default_value">{&#39;month&#39;, &#39;day&#39;, &#39;week&#39;, &#39;quarter&#39;, &#39;year&#39;, &#39;year_month&#39;}</span> <span class="default_value">{&#39;day&#39;, &#39;year_month&#39;, &#39;week&#39;, &#39;quarter&#39;, &#39;year&#39;, &#39;month&#39;}</span>
</div> </div>

View file

@ -641,7 +641,7 @@
<div class="attr variable"> <div class="attr variable">
<span class="name">ALL_JSON_PATH_PARTS</span> = <span class="name">ALL_JSON_PATH_PARTS</span> =
<input id="ALL_JSON_PATH_PARTS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="ALL_JSON_PATH_PARTS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="ALL_JSON_PATH_PARTS-view-value"></label><span class="default_value">{&lt;class &#39;<a href="expressions.html#JSONPathSelector">sqlglot.expressions.JSONPathSelector</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathSlice">sqlglot.expressions.JSONPathSlice</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathWildcard">sqlglot.expressions.JSONPathWildcard</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathScript">sqlglot.expressions.JSONPathScript</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathRoot">sqlglot.expressions.JSONPathRoot</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathRecursive">sqlglot.expressions.JSONPathRecursive</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathKey">sqlglot.expressions.JSONPathKey</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathUnion">sqlglot.expressions.JSONPathUnion</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathFilter">sqlglot.expressions.JSONPathFilter</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathSubscript">sqlglot.expressions.JSONPathSubscript</a>&#39;&gt;}</span> <label class="view-value-button pdoc-button" for="ALL_JSON_PATH_PARTS-view-value"></label><span class="default_value">{&lt;class &#39;<a href="expressions.html#JSONPathKey">sqlglot.expressions.JSONPathKey</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathWildcard">sqlglot.expressions.JSONPathWildcard</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathFilter">sqlglot.expressions.JSONPathFilter</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathUnion">sqlglot.expressions.JSONPathUnion</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathSubscript">sqlglot.expressions.JSONPathSubscript</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathSelector">sqlglot.expressions.JSONPathSelector</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathSlice">sqlglot.expressions.JSONPathSlice</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathScript">sqlglot.expressions.JSONPathScript</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathRoot">sqlglot.expressions.JSONPathRoot</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathRecursive">sqlglot.expressions.JSONPathRecursive</a>&#39;&gt;}</span>
</div> </div>

File diff suppressed because one or more lines are too long

View file

@ -581,7 +581,7 @@ queries if it would result in multiple table selects in a single query:</p>
<div class="attr variable"> <div class="attr variable">
<span class="name">UNMERGABLE_ARGS</span> = <span class="name">UNMERGABLE_ARGS</span> =
<input id="UNMERGABLE_ARGS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="UNMERGABLE_ARGS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="UNMERGABLE_ARGS-view-value"></label><span class="default_value">{&#39;qualify&#39;, &#39;sample&#39;, &#39;connect&#39;, &#39;limit&#39;, &#39;match&#39;, &#39;prewhere&#39;, &#39;locks&#39;, &#39;pivots&#39;, &#39;group&#39;, &#39;laterals&#39;, &#39;windows&#39;, &#39;operation_modifiers&#39;, &#39;having&#39;, &#39;format&#39;, &#39;settings&#39;, &#39;options&#39;, &#39;cluster&#39;, &#39;kind&#39;, &#39;offset&#39;, &#39;distribute&#39;, &#39;sort&#39;, &#39;distinct&#39;, &#39;with&#39;, &#39;into&#39;}</span> <label class="view-value-button pdoc-button" for="UNMERGABLE_ARGS-view-value"></label><span class="default_value">{&#39;sample&#39;, &#39;match&#39;, &#39;sort&#39;, &#39;locks&#39;, &#39;format&#39;, &#39;into&#39;, &#39;limit&#39;, &#39;offset&#39;, &#39;operation_modifiers&#39;, &#39;distinct&#39;, &#39;windows&#39;, &#39;having&#39;, &#39;laterals&#39;, &#39;settings&#39;, &#39;kind&#39;, &#39;distribute&#39;, &#39;connect&#39;, &#39;pivots&#39;, &#39;group&#39;, &#39;cluster&#39;, &#39;prewhere&#39;, &#39;options&#39;, &#39;qualify&#39;, &#39;with&#39;}</span>
</div> </div>

View file

@ -155,54 +155,58 @@
</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a> <span class="n">source</span><span class="o">.</span><span class="n">alias</span> </span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a> <span class="n">source</span><span class="o">.</span><span class="n">alias</span>
</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a> <span class="p">)</span> </span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a> <span class="p">)</span>
</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a> </span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a>
</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a> <span class="n">_qualify</span><span class="p">(</span><span class="n">source</span><span class="p">)</span> </span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a> <span class="k">if</span> <span class="n">pivots</span><span class="p">:</span>
</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a> </span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">pivots</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">alias</span><span class="p">:</span>
</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a> <span class="k">if</span> <span class="n">pivots</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">pivots</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">alias</span><span class="p">:</span> </span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a> <span class="n">pivot_alias</span> <span class="o">=</span> <span class="n">next_alias_name</span><span class="p">()</span>
</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a> <span class="n">pivots</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">set</span><span class="p">(</span> </span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a> <span class="n">pivots</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;alias&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">TableAlias</span><span class="p">(</span><span class="n">this</span><span class="o">=</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">pivot_alias</span><span class="p">)))</span>
</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a> <span class="s2">&quot;alias&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">TableAlias</span><span class="p">(</span><span class="n">this</span><span class="o">=</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">next_alias_name</span><span class="p">()))</span> </span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a>
</span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a> <span class="p">)</span> </span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a> <span class="c1"># This case corresponds to a pivoted CTE, we don&#39;t want to qualify that</span>
</span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a> </span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">scope</span><span class="o">.</span><span class="n">sources</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">source</span><span class="o">.</span><span class="n">alias_or_name</span><span class="p">),</span> <span class="n">Scope</span><span class="p">):</span>
</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a> <span class="k">if</span> <span class="n">infer_csv_schemas</span> <span class="ow">and</span> <span class="n">schema</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">source</span><span class="o">.</span><span class="n">this</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">ReadCSV</span><span class="p">):</span> </span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a> <span class="k">continue</span>
</span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a> <span class="k">with</span> <span class="n">csv_reader</span><span class="p">(</span><span class="n">source</span><span class="o">.</span><span class="n">this</span><span class="p">)</span> <span class="k">as</span> <span class="n">reader</span><span class="p">:</span> </span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a>
</span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a> <span class="n">header</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span> </span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a> <span class="n">_qualify</span><span class="p">(</span><span class="n">source</span><span class="p">)</span>
</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a> <span class="n">columns</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span> </span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a>
</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a> <span class="n">schema</span><span class="o">.</span><span class="n">add_table</span><span class="p">(</span> </span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a> <span class="k">if</span> <span class="n">infer_csv_schemas</span> <span class="ow">and</span> <span class="n">schema</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">source</span><span class="o">.</span><span class="n">this</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">ReadCSV</span><span class="p">):</span>
</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a> <span class="n">source</span><span class="p">,</span> </span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a> <span class="k">with</span> <span class="n">csv_reader</span><span class="p">(</span><span class="n">source</span><span class="o">.</span><span class="n">this</span><span class="p">)</span> <span class="k">as</span> <span class="n">reader</span><span class="p">:</span>
</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="nb">type</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">columns</span><span class="p">)},</span> </span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a> <span class="n">header</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>
</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a> <span class="n">match_depth</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> </span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a> <span class="n">columns</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>
</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a> <span class="p">)</span> </span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a> <span class="n">schema</span><span class="o">.</span><span class="n">add_table</span><span class="p">(</span>
</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">Scope</span><span class="p">)</span> <span class="ow">and</span> <span class="n">source</span><span class="o">.</span><span class="n">is_udtf</span><span class="p">:</span> </span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a> <span class="n">source</span><span class="p">,</span>
</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a> <span class="n">udtf</span> <span class="o">=</span> <span class="n">source</span><span class="o">.</span><span class="n">expression</span> </span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="nb">type</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">columns</span><span class="p">)},</span>
</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a> <span class="n">table_alias</span> <span class="o">=</span> <span class="n">udtf</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;alias&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">exp</span><span class="o">.</span><span class="n">TableAlias</span><span class="p">(</span> </span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a> <span class="n">match_depth</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a> <span class="n">this</span><span class="o">=</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">next_alias_name</span><span class="p">())</span> </span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a> <span class="p">)</span>
</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a> <span class="p">)</span> </span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">Scope</span><span class="p">)</span> <span class="ow">and</span> <span class="n">source</span><span class="o">.</span><span class="n">is_udtf</span><span class="p">:</span>
</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a> <span class="n">udtf</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;alias&quot;</span><span class="p">,</span> <span class="n">table_alias</span><span class="p">)</span> </span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a> <span class="n">udtf</span> <span class="o">=</span> <span class="n">source</span><span class="o">.</span><span class="n">expression</span>
</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a> </span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a> <span class="n">table_alias</span> <span class="o">=</span> <span class="n">udtf</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;alias&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">exp</span><span class="o">.</span><span class="n">TableAlias</span><span class="p">(</span>
</span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">table_alias</span><span class="o">.</span><span class="n">name</span><span class="p">:</span> </span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a> <span class="n">this</span><span class="o">=</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">next_alias_name</span><span class="p">())</span>
</span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a> <span class="n">table_alias</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;this&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">next_alias_name</span><span class="p">()))</span> </span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a> <span class="p">)</span>
</span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">udtf</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Values</span><span class="p">)</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">table_alias</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span> </span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a> <span class="n">udtf</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;alias&quot;</span><span class="p">,</span> <span class="n">table_alias</span><span class="p">)</span>
</span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">e</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">udtf</span><span class="o">.</span><span class="n">expressions</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">expressions</span><span class="p">):</span> </span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a>
</span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a> <span class="n">table_alias</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;columns&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;_col_</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">))</span> </span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">table_alias</span><span class="o">.</span><span class="n">name</span><span class="p">:</span>
</span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a> <span class="k">else</span><span class="p">:</span> </span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a> <span class="n">table_alias</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;this&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">next_alias_name</span><span class="p">()))</span>
</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">scope</span><span class="o">.</span><span class="n">walk</span><span class="p">():</span> </span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">udtf</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Values</span><span class="p">)</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">table_alias</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span>
</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a> <span class="k">if</span> <span class="p">(</span> </span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">e</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">udtf</span><span class="o">.</span><span class="n">expressions</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">expressions</span><span class="p">):</span>
</span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span><span class="p">)</span> </span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a> <span class="n">table_alias</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;columns&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;_col_</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">))</span>
</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a> <span class="ow">and</span> <span class="ow">not</span> <span class="n">node</span><span class="o">.</span><span class="n">alias</span> </span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">From</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Join</span><span class="p">))</span> </span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">scope</span><span class="o">.</span><span class="n">walk</span><span class="p">():</span>
</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a> <span class="p">):</span> </span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a> <span class="k">if</span> <span class="p">(</span>
</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a> <span class="c1"># Mutates the table by attaching an alias to it</span> </span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span><span class="p">)</span>
</span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a> <span class="n">alias</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">node</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">copy</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">table</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> </span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a> <span class="ow">and</span> <span class="ow">not</span> <span class="n">node</span><span class="o">.</span><span class="n">alias</span>
</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a> </span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">From</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Join</span><span class="p">))</span>
</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">scope</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span> </span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a> <span class="p">):</span>
</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a> <span class="k">if</span> <span class="n">column</span><span class="o">.</span><span class="n">db</span><span class="p">:</span> </span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a> <span class="c1"># Mutates the table by attaching an alias to it</span>
</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a> <span class="n">table_alias</span> <span class="o">=</span> <span class="n">table_aliases</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">name</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">column</span><span class="o">.</span><span class="n">parts</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]))</span> </span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a> <span class="n">alias</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">node</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">copy</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">table</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a> </span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a>
</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a> <span class="k">if</span> <span class="n">table_alias</span><span class="p">:</span> </span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">scope</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span>
</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">exp</span><span class="o">.</span><span class="n">COLUMN_PARTS</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span> </span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a> <span class="k">if</span> <span class="n">column</span><span class="o">.</span><span class="n">db</span><span class="p">:</span>
</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a> <span class="n">column</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span> </span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a> <span class="n">table_alias</span> <span class="o">=</span> <span class="n">table_aliases</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">name</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">column</span><span class="o">.</span><span class="n">parts</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]))</span>
</span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a> <span class="n">column</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;table&quot;</span><span class="p">,</span> <span class="n">table_alias</span><span class="p">)</span> </span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a>
</span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a> </span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a> <span class="k">if</span> <span class="n">table_alias</span><span class="p">:</span>
</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a> <span class="k">return</span> <span class="n">expression</span> </span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">exp</span><span class="o">.</span><span class="n">COLUMN_PARTS</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
</span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a> <span class="n">column</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a> <span class="n">column</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;table&quot;</span><span class="p">,</span> <span class="n">table_alias</span><span class="p">)</span>
</span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a>
</span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a> <span class="k">return</span> <span class="n">expression</span>
</span></pre></div> </span></pre></div>
@ -302,54 +306,58 @@
</span><span id="qualify_tables-98"><a href="#qualify_tables-98"><span class="linenos"> 98</span></a> <span class="n">source</span><span class="o">.</span><span class="n">alias</span> </span><span id="qualify_tables-98"><a href="#qualify_tables-98"><span class="linenos"> 98</span></a> <span class="n">source</span><span class="o">.</span><span class="n">alias</span>
</span><span id="qualify_tables-99"><a href="#qualify_tables-99"><span class="linenos"> 99</span></a> <span class="p">)</span> </span><span id="qualify_tables-99"><a href="#qualify_tables-99"><span class="linenos"> 99</span></a> <span class="p">)</span>
</span><span id="qualify_tables-100"><a href="#qualify_tables-100"><span class="linenos">100</span></a> </span><span id="qualify_tables-100"><a href="#qualify_tables-100"><span class="linenos">100</span></a>
</span><span id="qualify_tables-101"><a href="#qualify_tables-101"><span class="linenos">101</span></a> <span class="n">_qualify</span><span class="p">(</span><span class="n">source</span><span class="p">)</span> </span><span id="qualify_tables-101"><a href="#qualify_tables-101"><span class="linenos">101</span></a> <span class="k">if</span> <span class="n">pivots</span><span class="p">:</span>
</span><span id="qualify_tables-102"><a href="#qualify_tables-102"><span class="linenos">102</span></a> </span><span id="qualify_tables-102"><a href="#qualify_tables-102"><span class="linenos">102</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">pivots</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">alias</span><span class="p">:</span>
</span><span id="qualify_tables-103"><a href="#qualify_tables-103"><span class="linenos">103</span></a> <span class="k">if</span> <span class="n">pivots</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">pivots</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">alias</span><span class="p">:</span> </span><span id="qualify_tables-103"><a href="#qualify_tables-103"><span class="linenos">103</span></a> <span class="n">pivot_alias</span> <span class="o">=</span> <span class="n">next_alias_name</span><span class="p">()</span>
</span><span id="qualify_tables-104"><a href="#qualify_tables-104"><span class="linenos">104</span></a> <span class="n">pivots</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">set</span><span class="p">(</span> </span><span id="qualify_tables-104"><a href="#qualify_tables-104"><span class="linenos">104</span></a> <span class="n">pivots</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;alias&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">TableAlias</span><span class="p">(</span><span class="n">this</span><span class="o">=</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">pivot_alias</span><span class="p">)))</span>
</span><span id="qualify_tables-105"><a href="#qualify_tables-105"><span class="linenos">105</span></a> <span class="s2">&quot;alias&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">TableAlias</span><span class="p">(</span><span class="n">this</span><span class="o">=</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">next_alias_name</span><span class="p">()))</span> </span><span id="qualify_tables-105"><a href="#qualify_tables-105"><span class="linenos">105</span></a>
</span><span id="qualify_tables-106"><a href="#qualify_tables-106"><span class="linenos">106</span></a> <span class="p">)</span> </span><span id="qualify_tables-106"><a href="#qualify_tables-106"><span class="linenos">106</span></a> <span class="c1"># This case corresponds to a pivoted CTE, we don&#39;t want to qualify that</span>
</span><span id="qualify_tables-107"><a href="#qualify_tables-107"><span class="linenos">107</span></a> </span><span id="qualify_tables-107"><a href="#qualify_tables-107"><span class="linenos">107</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">scope</span><span class="o">.</span><span class="n">sources</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">source</span><span class="o">.</span><span class="n">alias_or_name</span><span class="p">),</span> <span class="n">Scope</span><span class="p">):</span>
</span><span id="qualify_tables-108"><a href="#qualify_tables-108"><span class="linenos">108</span></a> <span class="k">if</span> <span class="n">infer_csv_schemas</span> <span class="ow">and</span> <span class="n">schema</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">source</span><span class="o">.</span><span class="n">this</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">ReadCSV</span><span class="p">):</span> </span><span id="qualify_tables-108"><a href="#qualify_tables-108"><span class="linenos">108</span></a> <span class="k">continue</span>
</span><span id="qualify_tables-109"><a href="#qualify_tables-109"><span class="linenos">109</span></a> <span class="k">with</span> <span class="n">csv_reader</span><span class="p">(</span><span class="n">source</span><span class="o">.</span><span class="n">this</span><span class="p">)</span> <span class="k">as</span> <span class="n">reader</span><span class="p">:</span> </span><span id="qualify_tables-109"><a href="#qualify_tables-109"><span class="linenos">109</span></a>
</span><span id="qualify_tables-110"><a href="#qualify_tables-110"><span class="linenos">110</span></a> <span class="n">header</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span> </span><span id="qualify_tables-110"><a href="#qualify_tables-110"><span class="linenos">110</span></a> <span class="n">_qualify</span><span class="p">(</span><span class="n">source</span><span class="p">)</span>
</span><span id="qualify_tables-111"><a href="#qualify_tables-111"><span class="linenos">111</span></a> <span class="n">columns</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span> </span><span id="qualify_tables-111"><a href="#qualify_tables-111"><span class="linenos">111</span></a>
</span><span id="qualify_tables-112"><a href="#qualify_tables-112"><span class="linenos">112</span></a> <span class="n">schema</span><span class="o">.</span><span class="n">add_table</span><span class="p">(</span> </span><span id="qualify_tables-112"><a href="#qualify_tables-112"><span class="linenos">112</span></a> <span class="k">if</span> <span class="n">infer_csv_schemas</span> <span class="ow">and</span> <span class="n">schema</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">source</span><span class="o">.</span><span class="n">this</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">ReadCSV</span><span class="p">):</span>
</span><span id="qualify_tables-113"><a href="#qualify_tables-113"><span class="linenos">113</span></a> <span class="n">source</span><span class="p">,</span> </span><span id="qualify_tables-113"><a href="#qualify_tables-113"><span class="linenos">113</span></a> <span class="k">with</span> <span class="n">csv_reader</span><span class="p">(</span><span class="n">source</span><span class="o">.</span><span class="n">this</span><span class="p">)</span> <span class="k">as</span> <span class="n">reader</span><span class="p">:</span>
</span><span id="qualify_tables-114"><a href="#qualify_tables-114"><span class="linenos">114</span></a> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="nb">type</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">columns</span><span class="p">)},</span> </span><span id="qualify_tables-114"><a href="#qualify_tables-114"><span class="linenos">114</span></a> <span class="n">header</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>
</span><span id="qualify_tables-115"><a href="#qualify_tables-115"><span class="linenos">115</span></a> <span class="n">match_depth</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> </span><span id="qualify_tables-115"><a href="#qualify_tables-115"><span class="linenos">115</span></a> <span class="n">columns</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>
</span><span id="qualify_tables-116"><a href="#qualify_tables-116"><span class="linenos">116</span></a> <span class="p">)</span> </span><span id="qualify_tables-116"><a href="#qualify_tables-116"><span class="linenos">116</span></a> <span class="n">schema</span><span class="o">.</span><span class="n">add_table</span><span class="p">(</span>
</span><span id="qualify_tables-117"><a href="#qualify_tables-117"><span class="linenos">117</span></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">Scope</span><span class="p">)</span> <span class="ow">and</span> <span class="n">source</span><span class="o">.</span><span class="n">is_udtf</span><span class="p">:</span> </span><span id="qualify_tables-117"><a href="#qualify_tables-117"><span class="linenos">117</span></a> <span class="n">source</span><span class="p">,</span>
</span><span id="qualify_tables-118"><a href="#qualify_tables-118"><span class="linenos">118</span></a> <span class="n">udtf</span> <span class="o">=</span> <span class="n">source</span><span class="o">.</span><span class="n">expression</span> </span><span id="qualify_tables-118"><a href="#qualify_tables-118"><span class="linenos">118</span></a> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="nb">type</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">columns</span><span class="p">)},</span>
</span><span id="qualify_tables-119"><a href="#qualify_tables-119"><span class="linenos">119</span></a> <span class="n">table_alias</span> <span class="o">=</span> <span class="n">udtf</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;alias&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">exp</span><span class="o">.</span><span class="n">TableAlias</span><span class="p">(</span> </span><span id="qualify_tables-119"><a href="#qualify_tables-119"><span class="linenos">119</span></a> <span class="n">match_depth</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
</span><span id="qualify_tables-120"><a href="#qualify_tables-120"><span class="linenos">120</span></a> <span class="n">this</span><span class="o">=</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">next_alias_name</span><span class="p">())</span> </span><span id="qualify_tables-120"><a href="#qualify_tables-120"><span class="linenos">120</span></a> <span class="p">)</span>
</span><span id="qualify_tables-121"><a href="#qualify_tables-121"><span class="linenos">121</span></a> <span class="p">)</span> </span><span id="qualify_tables-121"><a href="#qualify_tables-121"><span class="linenos">121</span></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">Scope</span><span class="p">)</span> <span class="ow">and</span> <span class="n">source</span><span class="o">.</span><span class="n">is_udtf</span><span class="p">:</span>
</span><span id="qualify_tables-122"><a href="#qualify_tables-122"><span class="linenos">122</span></a> <span class="n">udtf</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;alias&quot;</span><span class="p">,</span> <span class="n">table_alias</span><span class="p">)</span> </span><span id="qualify_tables-122"><a href="#qualify_tables-122"><span class="linenos">122</span></a> <span class="n">udtf</span> <span class="o">=</span> <span class="n">source</span><span class="o">.</span><span class="n">expression</span>
</span><span id="qualify_tables-123"><a href="#qualify_tables-123"><span class="linenos">123</span></a> </span><span id="qualify_tables-123"><a href="#qualify_tables-123"><span class="linenos">123</span></a> <span class="n">table_alias</span> <span class="o">=</span> <span class="n">udtf</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;alias&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">exp</span><span class="o">.</span><span class="n">TableAlias</span><span class="p">(</span>
</span><span id="qualify_tables-124"><a href="#qualify_tables-124"><span class="linenos">124</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">table_alias</span><span class="o">.</span><span class="n">name</span><span class="p">:</span> </span><span id="qualify_tables-124"><a href="#qualify_tables-124"><span class="linenos">124</span></a> <span class="n">this</span><span class="o">=</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">next_alias_name</span><span class="p">())</span>
</span><span id="qualify_tables-125"><a href="#qualify_tables-125"><span class="linenos">125</span></a> <span class="n">table_alias</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;this&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">next_alias_name</span><span class="p">()))</span> </span><span id="qualify_tables-125"><a href="#qualify_tables-125"><span class="linenos">125</span></a> <span class="p">)</span>
</span><span id="qualify_tables-126"><a href="#qualify_tables-126"><span class="linenos">126</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">udtf</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Values</span><span class="p">)</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">table_alias</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span> </span><span id="qualify_tables-126"><a href="#qualify_tables-126"><span class="linenos">126</span></a> <span class="n">udtf</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;alias&quot;</span><span class="p">,</span> <span class="n">table_alias</span><span class="p">)</span>
</span><span id="qualify_tables-127"><a href="#qualify_tables-127"><span class="linenos">127</span></a> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">e</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">udtf</span><span class="o">.</span><span class="n">expressions</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">expressions</span><span class="p">):</span> </span><span id="qualify_tables-127"><a href="#qualify_tables-127"><span class="linenos">127</span></a>
</span><span id="qualify_tables-128"><a href="#qualify_tables-128"><span class="linenos">128</span></a> <span class="n">table_alias</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;columns&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;_col_</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">))</span> </span><span id="qualify_tables-128"><a href="#qualify_tables-128"><span class="linenos">128</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">table_alias</span><span class="o">.</span><span class="n">name</span><span class="p">:</span>
</span><span id="qualify_tables-129"><a href="#qualify_tables-129"><span class="linenos">129</span></a> <span class="k">else</span><span class="p">:</span> </span><span id="qualify_tables-129"><a href="#qualify_tables-129"><span class="linenos">129</span></a> <span class="n">table_alias</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;this&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">next_alias_name</span><span class="p">()))</span>
</span><span id="qualify_tables-130"><a href="#qualify_tables-130"><span class="linenos">130</span></a> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">scope</span><span class="o">.</span><span class="n">walk</span><span class="p">():</span> </span><span id="qualify_tables-130"><a href="#qualify_tables-130"><span class="linenos">130</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">udtf</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Values</span><span class="p">)</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">table_alias</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span>
</span><span id="qualify_tables-131"><a href="#qualify_tables-131"><span class="linenos">131</span></a> <span class="k">if</span> <span class="p">(</span> </span><span id="qualify_tables-131"><a href="#qualify_tables-131"><span class="linenos">131</span></a> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">e</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">udtf</span><span class="o">.</span><span class="n">expressions</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">expressions</span><span class="p">):</span>
</span><span id="qualify_tables-132"><a href="#qualify_tables-132"><span class="linenos">132</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span><span class="p">)</span> </span><span id="qualify_tables-132"><a href="#qualify_tables-132"><span class="linenos">132</span></a> <span class="n">table_alias</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;columns&quot;</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;_col_</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">))</span>
</span><span id="qualify_tables-133"><a href="#qualify_tables-133"><span class="linenos">133</span></a> <span class="ow">and</span> <span class="ow">not</span> <span class="n">node</span><span class="o">.</span><span class="n">alias</span> </span><span id="qualify_tables-133"><a href="#qualify_tables-133"><span class="linenos">133</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="qualify_tables-134"><a href="#qualify_tables-134"><span class="linenos">134</span></a> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">From</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Join</span><span class="p">))</span> </span><span id="qualify_tables-134"><a href="#qualify_tables-134"><span class="linenos">134</span></a> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">scope</span><span class="o">.</span><span class="n">walk</span><span class="p">():</span>
</span><span id="qualify_tables-135"><a href="#qualify_tables-135"><span class="linenos">135</span></a> <span class="p">):</span> </span><span id="qualify_tables-135"><a href="#qualify_tables-135"><span class="linenos">135</span></a> <span class="k">if</span> <span class="p">(</span>
</span><span id="qualify_tables-136"><a href="#qualify_tables-136"><span class="linenos">136</span></a> <span class="c1"># Mutates the table by attaching an alias to it</span> </span><span id="qualify_tables-136"><a href="#qualify_tables-136"><span class="linenos">136</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span><span class="p">)</span>
</span><span id="qualify_tables-137"><a href="#qualify_tables-137"><span class="linenos">137</span></a> <span class="n">alias</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">node</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">copy</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">table</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> </span><span id="qualify_tables-137"><a href="#qualify_tables-137"><span class="linenos">137</span></a> <span class="ow">and</span> <span class="ow">not</span> <span class="n">node</span><span class="o">.</span><span class="n">alias</span>
</span><span id="qualify_tables-138"><a href="#qualify_tables-138"><span class="linenos">138</span></a> </span><span id="qualify_tables-138"><a href="#qualify_tables-138"><span class="linenos">138</span></a> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">From</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Join</span><span class="p">))</span>
</span><span id="qualify_tables-139"><a href="#qualify_tables-139"><span class="linenos">139</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">scope</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span> </span><span id="qualify_tables-139"><a href="#qualify_tables-139"><span class="linenos">139</span></a> <span class="p">):</span>
</span><span id="qualify_tables-140"><a href="#qualify_tables-140"><span class="linenos">140</span></a> <span class="k">if</span> <span class="n">column</span><span class="o">.</span><span class="n">db</span><span class="p">:</span> </span><span id="qualify_tables-140"><a href="#qualify_tables-140"><span class="linenos">140</span></a> <span class="c1"># Mutates the table by attaching an alias to it</span>
</span><span id="qualify_tables-141"><a href="#qualify_tables-141"><span class="linenos">141</span></a> <span class="n">table_alias</span> <span class="o">=</span> <span class="n">table_aliases</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">name</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">column</span><span class="o">.</span><span class="n">parts</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]))</span> </span><span id="qualify_tables-141"><a href="#qualify_tables-141"><span class="linenos">141</span></a> <span class="n">alias</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">node</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">copy</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">table</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="qualify_tables-142"><a href="#qualify_tables-142"><span class="linenos">142</span></a> </span><span id="qualify_tables-142"><a href="#qualify_tables-142"><span class="linenos">142</span></a>
</span><span id="qualify_tables-143"><a href="#qualify_tables-143"><span class="linenos">143</span></a> <span class="k">if</span> <span class="n">table_alias</span><span class="p">:</span> </span><span id="qualify_tables-143"><a href="#qualify_tables-143"><span class="linenos">143</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">scope</span><span class="o">.</span><span class="n">columns</span><span class="p">:</span>
</span><span id="qualify_tables-144"><a href="#qualify_tables-144"><span class="linenos">144</span></a> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">exp</span><span class="o">.</span><span class="n">COLUMN_PARTS</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span> </span><span id="qualify_tables-144"><a href="#qualify_tables-144"><span class="linenos">144</span></a> <span class="k">if</span> <span class="n">column</span><span class="o">.</span><span class="n">db</span><span class="p">:</span>
</span><span id="qualify_tables-145"><a href="#qualify_tables-145"><span class="linenos">145</span></a> <span class="n">column</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span> </span><span id="qualify_tables-145"><a href="#qualify_tables-145"><span class="linenos">145</span></a> <span class="n">table_alias</span> <span class="o">=</span> <span class="n">table_aliases</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">name</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">column</span><span class="o">.</span><span class="n">parts</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]))</span>
</span><span id="qualify_tables-146"><a href="#qualify_tables-146"><span class="linenos">146</span></a> <span class="n">column</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;table&quot;</span><span class="p">,</span> <span class="n">table_alias</span><span class="p">)</span> </span><span id="qualify_tables-146"><a href="#qualify_tables-146"><span class="linenos">146</span></a>
</span><span id="qualify_tables-147"><a href="#qualify_tables-147"><span class="linenos">147</span></a> </span><span id="qualify_tables-147"><a href="#qualify_tables-147"><span class="linenos">147</span></a> <span class="k">if</span> <span class="n">table_alias</span><span class="p">:</span>
</span><span id="qualify_tables-148"><a href="#qualify_tables-148"><span class="linenos">148</span></a> <span class="k">return</span> <span class="n">expression</span> </span><span id="qualify_tables-148"><a href="#qualify_tables-148"><span class="linenos">148</span></a> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">exp</span><span class="o">.</span><span class="n">COLUMN_PARTS</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
</span><span id="qualify_tables-149"><a href="#qualify_tables-149"><span class="linenos">149</span></a> <span class="n">column</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
</span><span id="qualify_tables-150"><a href="#qualify_tables-150"><span class="linenos">150</span></a> <span class="n">column</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;table&quot;</span><span class="p">,</span> <span class="n">table_alias</span><span class="p">)</span>
</span><span id="qualify_tables-151"><a href="#qualify_tables-151"><span class="linenos">151</span></a>
</span><span id="qualify_tables-152"><a href="#qualify_tables-152"><span class="linenos">152</span></a> <span class="k">return</span> <span class="n">expression</span>
</span></pre></div> </span></pre></div>

View file

@ -542,7 +542,7 @@
</span><span id="L-292"><a href="#L-292"><span class="linenos">292</span></a> <span class="ow">or</span> <span class="p">(</span> </span><span id="L-292"><a href="#L-292"><span class="linenos">292</span></a> <span class="ow">or</span> <span class="p">(</span>
</span><span id="L-293"><a href="#L-293"><span class="linenos">293</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">)</span> </span><span id="L-293"><a href="#L-293"><span class="linenos">293</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">)</span>
</span><span id="L-294"><a href="#L-294"><span class="linenos">294</span></a> <span class="ow">and</span> <span class="p">(</span> </span><span id="L-294"><a href="#L-294"><span class="linenos">294</span></a> <span class="ow">and</span> <span class="p">(</span>
</span><span id="L-295"><a href="#L-295"><span class="linenos">295</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">)</span> </span><span id="L-295"><a href="#L-295"><span class="linenos">295</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">WithinGroup</span><span class="p">))</span>
</span><span id="L-296"><a href="#L-296"><span class="linenos">296</span></a> <span class="ow">or</span> <span class="n">column</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">named_selects</span> </span><span id="L-296"><a href="#L-296"><span class="linenos">296</span></a> <span class="ow">or</span> <span class="n">column</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">named_selects</span>
</span><span id="L-297"><a href="#L-297"><span class="linenos">297</span></a> <span class="p">)</span> </span><span id="L-297"><a href="#L-297"><span class="linenos">297</span></a> <span class="p">)</span>
</span><span id="L-298"><a href="#L-298"><span class="linenos">298</span></a> <span class="p">)</span> </span><span id="L-298"><a href="#L-298"><span class="linenos">298</span></a> <span class="p">)</span>
@ -1548,7 +1548,7 @@
</span><span id="Scope-293"><a href="#Scope-293"><span class="linenos">293</span></a> <span class="ow">or</span> <span class="p">(</span> </span><span id="Scope-293"><a href="#Scope-293"><span class="linenos">293</span></a> <span class="ow">or</span> <span class="p">(</span>
</span><span id="Scope-294"><a href="#Scope-294"><span class="linenos">294</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">)</span> </span><span id="Scope-294"><a href="#Scope-294"><span class="linenos">294</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">)</span>
</span><span id="Scope-295"><a href="#Scope-295"><span class="linenos">295</span></a> <span class="ow">and</span> <span class="p">(</span> </span><span id="Scope-295"><a href="#Scope-295"><span class="linenos">295</span></a> <span class="ow">and</span> <span class="p">(</span>
</span><span id="Scope-296"><a href="#Scope-296"><span class="linenos">296</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">)</span> </span><span id="Scope-296"><a href="#Scope-296"><span class="linenos">296</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">WithinGroup</span><span class="p">))</span>
</span><span id="Scope-297"><a href="#Scope-297"><span class="linenos">297</span></a> <span class="ow">or</span> <span class="n">column</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">named_selects</span> </span><span id="Scope-297"><a href="#Scope-297"><span class="linenos">297</span></a> <span class="ow">or</span> <span class="n">column</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">named_selects</span>
</span><span id="Scope-298"><a href="#Scope-298"><span class="linenos">298</span></a> <span class="p">)</span> </span><span id="Scope-298"><a href="#Scope-298"><span class="linenos">298</span></a> <span class="p">)</span>
</span><span id="Scope-299"><a href="#Scope-299"><span class="linenos">299</span></a> <span class="p">)</span> </span><span id="Scope-299"><a href="#Scope-299"><span class="linenos">299</span></a> <span class="p">)</span>
@ -2415,7 +2415,7 @@ a list of the left and right child scopes.</li>
</span><span id="Scope.columns-293"><a href="#Scope.columns-293"><span class="linenos">293</span></a> <span class="ow">or</span> <span class="p">(</span> </span><span id="Scope.columns-293"><a href="#Scope.columns-293"><span class="linenos">293</span></a> <span class="ow">or</span> <span class="p">(</span>
</span><span id="Scope.columns-294"><a href="#Scope.columns-294"><span class="linenos">294</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">)</span> </span><span id="Scope.columns-294"><a href="#Scope.columns-294"><span class="linenos">294</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">)</span>
</span><span id="Scope.columns-295"><a href="#Scope.columns-295"><span class="linenos">295</span></a> <span class="ow">and</span> <span class="p">(</span> </span><span id="Scope.columns-295"><a href="#Scope.columns-295"><span class="linenos">295</span></a> <span class="ow">and</span> <span class="p">(</span>
</span><span id="Scope.columns-296"><a href="#Scope.columns-296"><span class="linenos">296</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">)</span> </span><span id="Scope.columns-296"><a href="#Scope.columns-296"><span class="linenos">296</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ancestor</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">WithinGroup</span><span class="p">))</span>
</span><span id="Scope.columns-297"><a href="#Scope.columns-297"><span class="linenos">297</span></a> <span class="ow">or</span> <span class="n">column</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">named_selects</span> </span><span id="Scope.columns-297"><a href="#Scope.columns-297"><span class="linenos">297</span></a> <span class="ow">or</span> <span class="n">column</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">named_selects</span>
</span><span id="Scope.columns-298"><a href="#Scope.columns-298"><span class="linenos">298</span></a> <span class="p">)</span> </span><span id="Scope.columns-298"><a href="#Scope.columns-298"><span class="linenos">298</span></a> <span class="p">)</span>
</span><span id="Scope.columns-299"><a href="#Scope.columns-299"><span class="linenos">299</span></a> <span class="p">)</span> </span><span id="Scope.columns-299"><a href="#Scope.columns-299"><span class="linenos">299</span></a> <span class="p">)</span>

View file

@ -3238,7 +3238,7 @@ prefix are statically known.</p>
<div class="attr variable"> <div class="attr variable">
<span class="name">DATETRUNC_COMPARISONS</span> = <span class="name">DATETRUNC_COMPARISONS</span> =
<input id="DATETRUNC_COMPARISONS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="DATETRUNC_COMPARISONS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="DATETRUNC_COMPARISONS-view-value"></label><span class="default_value">{&lt;class &#39;<a href="../expressions.html#LT">sqlglot.expressions.LT</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#NEQ">sqlglot.expressions.NEQ</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#GTE">sqlglot.expressions.GTE</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#EQ">sqlglot.expressions.EQ</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#In">sqlglot.expressions.In</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#LTE">sqlglot.expressions.LTE</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#GT">sqlglot.expressions.GT</a>&#39;&gt;}</span> <label class="view-value-button pdoc-button" for="DATETRUNC_COMPARISONS-view-value"></label><span class="default_value">{&lt;class &#39;<a href="../expressions.html#In">sqlglot.expressions.In</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#LT">sqlglot.expressions.LT</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#NEQ">sqlglot.expressions.NEQ</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#EQ">sqlglot.expressions.EQ</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#GTE">sqlglot.expressions.GTE</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#LTE">sqlglot.expressions.LTE</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#GT">sqlglot.expressions.GT</a>&#39;&gt;}</span>
</div> </div>
@ -3322,7 +3322,7 @@ prefix are statically known.</p>
<section id="JOINS"> <section id="JOINS">
<div class="attr variable"> <div class="attr variable">
<span class="name">JOINS</span> = <span class="name">JOINS</span> =
<span class="default_value">{(&#39;&#39;, &#39;INNER&#39;), (&#39;RIGHT&#39;, &#39;&#39;), (&#39;RIGHT&#39;, &#39;OUTER&#39;), (&#39;&#39;, &#39;&#39;)}</span> <span class="default_value">{(&#39;RIGHT&#39;, &#39;&#39;), (&#39;&#39;, &#39;INNER&#39;), (&#39;RIGHT&#39;, &#39;OUTER&#39;), (&#39;&#39;, &#39;&#39;)}</span>
</div> </div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -391,7 +391,7 @@
</span><span id="L-258"><a href="#L-258"><span class="linenos">258</span></a> <span class="p">}</span> </span><span id="L-258"><a href="#L-258"><span class="linenos">258</span></a> <span class="p">}</span>
</span><span id="L-259"><a href="#L-259"><span class="linenos">259</span></a> </span><span id="L-259"><a href="#L-259"><span class="linenos">259</span></a>
</span><span id="L-260"><a href="#L-260"><span class="linenos">260</span></a> <span class="n">select_candidates</span> <span class="o">=</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span> <span class="k">if</span> <span class="n">expression</span><span class="o">.</span><span class="n">is_star</span> <span class="k">else</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Column</span><span class="p">)</span> </span><span id="L-260"><a href="#L-260"><span class="linenos">260</span></a> <span class="n">select_candidates</span> <span class="o">=</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span> <span class="k">if</span> <span class="n">expression</span><span class="o">.</span><span class="n">is_star</span> <span class="k">else</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Column</span><span class="p">)</span>
</span><span id="L-261"><a href="#L-261"><span class="linenos">261</span></a> <span class="k">for</span> <span class="n">select_candidate</span> <span class="ow">in</span> <span class="n">qualify_filters</span><span class="o">.</span><span class="n">find_all</span><span class="p">(</span><span class="n">select_candidates</span><span class="p">):</span> </span><span id="L-261"><a href="#L-261"><span class="linenos">261</span></a> <span class="k">for</span> <span class="n">select_candidate</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">qualify_filters</span><span class="o">.</span><span class="n">find_all</span><span class="p">(</span><span class="n">select_candidates</span><span class="p">)):</span>
</span><span id="L-262"><a href="#L-262"><span class="linenos">262</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">select_candidate</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">):</span> </span><span id="L-262"><a href="#L-262"><span class="linenos">262</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">select_candidate</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">):</span>
</span><span id="L-263"><a href="#L-263"><span class="linenos">263</span></a> <span class="k">if</span> <span class="n">expression_by_alias</span><span class="p">:</span> </span><span id="L-263"><a href="#L-263"><span class="linenos">263</span></a> <span class="k">if</span> <span class="n">expression_by_alias</span><span class="p">:</span>
</span><span id="L-264"><a href="#L-264"><span class="linenos">264</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">select_candidate</span><span class="o">.</span><span class="n">find_all</span><span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Column</span><span class="p">):</span> </span><span id="L-264"><a href="#L-264"><span class="linenos">264</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">select_candidate</span><span class="o">.</span><span class="n">find_all</span><span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Column</span><span class="p">):</span>
@ -1496,7 +1496,7 @@ or the appropriate <code>Generator.TRANSFORMS</code> function (when applicable -
</span><span id="eliminate_qualify-259"><a href="#eliminate_qualify-259"><span class="linenos">259</span></a> <span class="p">}</span> </span><span id="eliminate_qualify-259"><a href="#eliminate_qualify-259"><span class="linenos">259</span></a> <span class="p">}</span>
</span><span id="eliminate_qualify-260"><a href="#eliminate_qualify-260"><span class="linenos">260</span></a> </span><span id="eliminate_qualify-260"><a href="#eliminate_qualify-260"><span class="linenos">260</span></a>
</span><span id="eliminate_qualify-261"><a href="#eliminate_qualify-261"><span class="linenos">261</span></a> <span class="n">select_candidates</span> <span class="o">=</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span> <span class="k">if</span> <span class="n">expression</span><span class="o">.</span><span class="n">is_star</span> <span class="k">else</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Column</span><span class="p">)</span> </span><span id="eliminate_qualify-261"><a href="#eliminate_qualify-261"><span class="linenos">261</span></a> <span class="n">select_candidates</span> <span class="o">=</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span> <span class="k">if</span> <span class="n">expression</span><span class="o">.</span><span class="n">is_star</span> <span class="k">else</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Column</span><span class="p">)</span>
</span><span id="eliminate_qualify-262"><a href="#eliminate_qualify-262"><span class="linenos">262</span></a> <span class="k">for</span> <span class="n">select_candidate</span> <span class="ow">in</span> <span class="n">qualify_filters</span><span class="o">.</span><span class="n">find_all</span><span class="p">(</span><span class="n">select_candidates</span><span class="p">):</span> </span><span id="eliminate_qualify-262"><a href="#eliminate_qualify-262"><span class="linenos">262</span></a> <span class="k">for</span> <span class="n">select_candidate</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">qualify_filters</span><span class="o">.</span><span class="n">find_all</span><span class="p">(</span><span class="n">select_candidates</span><span class="p">)):</span>
</span><span id="eliminate_qualify-263"><a href="#eliminate_qualify-263"><span class="linenos">263</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">select_candidate</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">):</span> </span><span id="eliminate_qualify-263"><a href="#eliminate_qualify-263"><span class="linenos">263</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">select_candidate</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Window</span><span class="p">):</span>
</span><span id="eliminate_qualify-264"><a href="#eliminate_qualify-264"><span class="linenos">264</span></a> <span class="k">if</span> <span class="n">expression_by_alias</span><span class="p">:</span> </span><span id="eliminate_qualify-264"><a href="#eliminate_qualify-264"><span class="linenos">264</span></a> <span class="k">if</span> <span class="n">expression_by_alias</span><span class="p">:</span>
</span><span id="eliminate_qualify-265"><a href="#eliminate_qualify-265"><span class="linenos">265</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">select_candidate</span><span class="o">.</span><span class="n">find_all</span><span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Column</span><span class="p">):</span> </span><span id="eliminate_qualify-265"><a href="#eliminate_qualify-265"><span class="linenos">265</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">select_candidate</span><span class="o">.</span><span class="n">find_all</span><span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Column</span><span class="p">):</span>

View file

@ -356,6 +356,7 @@ class BigQuery(Dialect):
FORCE_EARLY_ALIAS_REF_EXPANSION = True FORCE_EARLY_ALIAS_REF_EXPANSION = True
EXPAND_ALIAS_REFS_EARLY_ONLY_IN_GROUP_BY = True EXPAND_ALIAS_REFS_EARLY_ONLY_IN_GROUP_BY = True
PRESERVE_ORIGINAL_NAMES = True PRESERVE_ORIGINAL_NAMES = True
HEX_STRING_IS_INTEGER_TYPE = True
# https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#case_sensitivity # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#case_sensitivity
NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
@ -903,6 +904,7 @@ class BigQuery(Dialect):
exp.GenerateSeries: rename_func("GENERATE_ARRAY"), exp.GenerateSeries: rename_func("GENERATE_ARRAY"),
exp.GroupConcat: rename_func("STRING_AGG"), exp.GroupConcat: rename_func("STRING_AGG"),
exp.Hex: lambda self, e: self.func("UPPER", self.func("TO_HEX", self.sql(e, "this"))), exp.Hex: lambda self, e: self.func("UPPER", self.func("TO_HEX", self.sql(e, "this"))),
exp.HexString: lambda self, e: self.hexstring_sql(e, binary_function_repr="FROM_HEX"),
exp.If: if_sql(false_value="NULL"), exp.If: if_sql(false_value="NULL"),
exp.ILike: no_ilike_sql, exp.ILike: no_ilike_sql,
exp.IntDiv: rename_func("DIV"), exp.IntDiv: rename_func("DIV"),

View file

@ -82,7 +82,7 @@ def _build_count_if(args: t.List) -> exp.CountIf | exp.CombinedAggFunc:
if len(args) == 1: if len(args) == 1:
return exp.CountIf(this=seq_get(args, 0)) return exp.CountIf(this=seq_get(args, 0))
return exp.CombinedAggFunc(this="countIf", expressions=args, parts=("count", "If")) return exp.CombinedAggFunc(this="countIf", expressions=args)
def _build_str_to_date(args: t.List) -> exp.Cast | exp.Anonymous: def _build_str_to_date(args: t.List) -> exp.Cast | exp.Anonymous:
@ -190,6 +190,7 @@ class ClickHouse(Dialect):
PRESERVE_ORIGINAL_NAMES = True PRESERVE_ORIGINAL_NAMES = True
NUMBERS_CAN_BE_UNDERSCORE_SEPARATED = True NUMBERS_CAN_BE_UNDERSCORE_SEPARATED = True
IDENTIFIERS_CAN_START_WITH_DIGIT = True IDENTIFIERS_CAN_START_WITH_DIGIT = True
HEX_STRING_IS_INTEGER_TYPE = True
# https://github.com/ClickHouse/ClickHouse/issues/33935#issue-1112165779 # https://github.com/ClickHouse/ClickHouse/issues/33935#issue-1112165779
NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_SENSITIVE NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_SENSITIVE
@ -217,6 +218,7 @@ class ClickHouse(Dialect):
KEYWORDS = { KEYWORDS = {
**tokens.Tokenizer.KEYWORDS, **tokens.Tokenizer.KEYWORDS,
".:": TokenType.DOTCOLON,
"ATTACH": TokenType.COMMAND, "ATTACH": TokenType.COMMAND,
"DATE32": TokenType.DATE32, "DATE32": TokenType.DATE32,
"DATETIME64": TokenType.DATETIME64, "DATETIME64": TokenType.DATETIME64,
@ -438,6 +440,8 @@ class ClickHouse(Dialect):
FUNC_TOKENS = { FUNC_TOKENS = {
*parser.Parser.FUNC_TOKENS, *parser.Parser.FUNC_TOKENS,
TokenType.AND,
TokenType.OR,
TokenType.SET, TokenType.SET,
} }
@ -477,8 +481,7 @@ class ClickHouse(Dialect):
RANGE_PARSERS = { RANGE_PARSERS = {
**parser.Parser.RANGE_PARSERS, **parser.Parser.RANGE_PARSERS,
TokenType.GLOBAL: lambda self, this: self._match(TokenType.IN) TokenType.GLOBAL: lambda self, this: self._parse_global_in(this),
and self._parse_in(this, is_global=True),
} }
# The PLACEHOLDER entry is popped because 1) it doesn't affect Clickhouse (it corresponds to # The PLACEHOLDER entry is popped because 1) it doesn't affect Clickhouse (it corresponds to
@ -632,6 +635,11 @@ class ClickHouse(Dialect):
this.set("is_global", is_global) this.set("is_global", is_global)
return this return this
def _parse_global_in(self, this: t.Optional[exp.Expression]) -> exp.Not | exp.In:
is_negated = self._match(TokenType.NOT)
this = self._match(TokenType.IN) and self._parse_in(this, is_global=True)
return self.expression(exp.Not, this=this) if is_negated else this
def _parse_table( def _parse_table(
self, self,
schema: bool = False, schema: bool = False,
@ -649,6 +657,13 @@ class ClickHouse(Dialect):
is_db_reference=is_db_reference, is_db_reference=is_db_reference,
) )
if isinstance(this, exp.Table):
inner = this.this
alias = this.args.get("alias")
if isinstance(inner, exp.GenerateSeries) and alias and not alias.columns:
alias.set("columns", [exp.to_identifier("generate_series")])
if self._match(TokenType.FINAL): if self._match(TokenType.FINAL):
this = self.expression(exp.Final, this=this) this = self.expression(exp.Final, this=this)
@ -735,7 +750,6 @@ class ClickHouse(Dialect):
"expressions": anon_func.expressions, "expressions": anon_func.expressions,
} }
if parts[1]: if parts[1]:
kwargs["parts"] = parts
exp_class: t.Type[exp.Expression] = ( exp_class: t.Type[exp.Expression] = (
exp.CombinedParameterizedAgg if params else exp.CombinedAggFunc exp.CombinedParameterizedAgg if params else exp.CombinedAggFunc
) )
@ -902,7 +916,6 @@ class ClickHouse(Dialect):
TABLE_HINTS = False TABLE_HINTS = False
GROUPINGS_SEP = "" GROUPINGS_SEP = ""
SET_OP_MODIFIERS = False SET_OP_MODIFIERS = False
SUPPORTS_TABLE_ALIAS_COLUMNS = False
VALUES_AS_TABLE = False VALUES_AS_TABLE = False
ARRAY_SIZE_NAME = "LENGTH" ARRAY_SIZE_NAME = "LENGTH"
@ -982,6 +995,7 @@ class ClickHouse(Dialect):
**generator.Generator.TRANSFORMS, **generator.Generator.TRANSFORMS,
exp.AnyValue: rename_func("any"), exp.AnyValue: rename_func("any"),
exp.ApproxDistinct: rename_func("uniq"), exp.ApproxDistinct: rename_func("uniq"),
exp.ArrayConcat: rename_func("arrayConcat"),
exp.ArrayFilter: lambda self, e: self.func("arrayFilter", e.expression, e.this), exp.ArrayFilter: lambda self, e: self.func("arrayFilter", e.expression, e.this),
exp.ArraySum: rename_func("arraySum"), exp.ArraySum: rename_func("arraySum"),
exp.ArgMax: arg_max_or_min_no_count("argMax"), exp.ArgMax: arg_max_or_min_no_count("argMax"),
@ -1001,6 +1015,7 @@ class ClickHouse(Dialect):
exp.Explode: rename_func("arrayJoin"), exp.Explode: rename_func("arrayJoin"),
exp.Final: lambda self, e: f"{self.sql(e, 'this')} FINAL", exp.Final: lambda self, e: f"{self.sql(e, 'this')} FINAL",
exp.IsNan: rename_func("isNaN"), exp.IsNan: rename_func("isNaN"),
exp.JSONCast: lambda self, e: f"{self.sql(e, 'this')}.:{self.sql(e, 'to')}",
exp.JSONExtract: json_extract_segments("JSONExtractString", quoted_index=False), exp.JSONExtract: json_extract_segments("JSONExtractString", quoted_index=False),
exp.JSONExtractScalar: json_extract_segments("JSONExtractString", quoted_index=False), exp.JSONExtractScalar: json_extract_segments("JSONExtractString", quoted_index=False),
exp.JSONPathKey: json_path_key_only_name, exp.JSONPathKey: json_path_key_only_name,
@ -1036,7 +1051,7 @@ class ClickHouse(Dialect):
exp.SHA2: sha256_sql, exp.SHA2: sha256_sql,
exp.UnixToTime: _unix_to_time_sql, exp.UnixToTime: _unix_to_time_sql,
exp.TimestampTrunc: timestamptrunc_sql(zone=True), exp.TimestampTrunc: timestamptrunc_sql(zone=True),
exp.Trim: trim_sql, exp.Trim: lambda self, e: trim_sql(self, e, default_trim_type="BOTH"),
exp.Variance: rename_func("varSamp"), exp.Variance: rename_func("varSamp"),
exp.SchemaCommentProperty: lambda self, e: self.naked_property(e), exp.SchemaCommentProperty: lambda self, e: self.naked_property(e),
exp.Stddev: rename_func("stddevSamp"), exp.Stddev: rename_func("stddevSamp"),
@ -1092,7 +1107,7 @@ class ClickHouse(Dialect):
if not isinstance(expression.parent, exp.Cast): if not isinstance(expression.parent, exp.Cast):
# StrToDate returns DATEs in other dialects (eg. postgres), so # StrToDate returns DATEs in other dialects (eg. postgres), so
# this branch aims to improve the transpilation to clickhouse # this branch aims to improve the transpilation to clickhouse
return f"CAST({strtodate_sql} AS DATE)" return self.cast_sql(exp.cast(expression, "DATE"))
return strtodate_sql return strtodate_sql
@ -1201,19 +1216,6 @@ class ClickHouse(Dialect):
), ),
] ]
def parameterizedagg_sql(self, expression: exp.ParameterizedAgg) -> str:
params = self.expressions(expression, key="params", flat=True)
return self.func(expression.name, *expression.expressions) + f"({params})"
def anonymousaggfunc_sql(self, expression: exp.AnonymousAggFunc) -> str:
return self.func(expression.name, *expression.expressions)
def combinedaggfunc_sql(self, expression: exp.CombinedAggFunc) -> str:
return self.anonymousaggfunc_sql(expression)
def combinedparameterizedagg_sql(self, expression: exp.CombinedParameterizedAgg) -> str:
return self.parameterizedagg_sql(expression)
def placeholder_sql(self, expression: exp.Placeholder) -> str: def placeholder_sql(self, expression: exp.Placeholder) -> str:
return f"{{{expression.name}: {self.sql(expression, 'kind')}}}" return f"{{{expression.name}: {self.sql(expression, 'kind')}}}"
@ -1294,3 +1296,18 @@ class ClickHouse(Dialect):
is_sql = self.wrap(is_sql) is_sql = self.wrap(is_sql)
return is_sql return is_sql
def in_sql(self, expression: exp.In) -> str:
in_sql = super().in_sql(expression)
if isinstance(expression.parent, exp.Not) and expression.args.get("is_global"):
in_sql = in_sql.replace("GLOBAL IN", "GLOBAL NOT IN", 1)
return in_sql
def not_sql(self, expression: exp.Not) -> str:
if isinstance(expression.this, exp.In) and expression.this.args.get("is_global"):
# let `GLOBAL IN` child interpose `NOT`
return self.sql(expression, "this")
return super().not_sql(expression)

View file

@ -3,6 +3,8 @@ from __future__ import annotations
import importlib import importlib
import logging import logging
import typing as t import typing as t
import sys
from enum import Enum, auto from enum import Enum, auto
from functools import reduce from functools import reduce
@ -103,6 +105,20 @@ class NormalizationStrategy(str, AutoName):
"""Always case-insensitive, regardless of quotes.""" """Always case-insensitive, regardless of quotes."""
class Version(int):
def __new__(cls, version_str: t.Optional[str], *args, **kwargs):
if version_str:
parts = version_str.split(".")
parts.extend(["0"] * (3 - len(parts)))
v = int("".join([p.zfill(3) for p in parts]))
else:
# No version defined means we should support the latest engine semantics, so
# the comparison to any specific version should yield that latest is greater
v = sys.maxsize
return super(Version, cls).__new__(cls, v)
class _Dialect(type): class _Dialect(type):
_classes: t.Dict[str, t.Type[Dialect]] = {} _classes: t.Dict[str, t.Type[Dialect]] = {}
@ -453,6 +469,9 @@ class Dialect(metaclass=_Dialect):
NUMBERS_CAN_BE_UNDERSCORE_SEPARATED = False NUMBERS_CAN_BE_UNDERSCORE_SEPARATED = False
"""Whether number literals can include underscores for better readability""" """Whether number literals can include underscores for better readability"""
HEX_STRING_IS_INTEGER_TYPE: bool = False
"""Whether hex strings such as x'CC' evaluate to integer or binary/blob type"""
REGEXP_EXTRACT_DEFAULT_GROUP = 0 REGEXP_EXTRACT_DEFAULT_GROUP = 0
"""The default value for the capturing group.""" """The default value for the capturing group."""
@ -1002,6 +1021,10 @@ class Dialect(metaclass=_Dialect):
def generator(self, **opts) -> Generator: def generator(self, **opts) -> Generator:
return self.generator_class(dialect=self, **opts) return self.generator_class(dialect=self, **opts)
@property
def version(self) -> Version:
return Version(self.settings.get("version", None))
DialectType = t.Union[str, Dialect, t.Type[Dialect], None] DialectType = t.Union[str, Dialect, t.Type[Dialect], None]
@ -1384,9 +1407,9 @@ def count_if_to_sum(self: Generator, expression: exp.CountIf) -> str:
return self.func("sum", exp.func("if", cond, 1, 0)) return self.func("sum", exp.func("if", cond, 1, 0))
def trim_sql(self: Generator, expression: exp.Trim) -> str: def trim_sql(self: Generator, expression: exp.Trim, default_trim_type: str = "") -> str:
target = self.sql(expression, "this") target = self.sql(expression, "this")
trim_type = self.sql(expression, "position") trim_type = self.sql(expression, "position") or default_trim_type
remove_chars = self.sql(expression, "expression") remove_chars = self.sql(expression, "expression")
collation = self.sql(expression, "collation") collation = self.sql(expression, "collation")

View file

@ -8,11 +8,13 @@ from sqlglot.dialects.dialect import (
Dialect, Dialect,
JSON_EXTRACT_TYPE, JSON_EXTRACT_TYPE,
NormalizationStrategy, NormalizationStrategy,
Version,
approx_count_distinct_sql, approx_count_distinct_sql,
arrow_json_extract_sql, arrow_json_extract_sql,
binary_from_function, binary_from_function,
bool_xor_sql, bool_xor_sql,
build_default_decimal_type, build_default_decimal_type,
count_if_to_sum,
date_trunc_to_time, date_trunc_to_time,
datestrtodate_sql, datestrtodate_sql,
no_datetime_sql, no_datetime_sql,
@ -75,7 +77,10 @@ def _date_delta_sql(self: DuckDB.Generator, expression: DATETIME_DELTA) -> str:
this = exp.cast(this, to_type) if to_type else this this = exp.cast(this, to_type) if to_type else this
return f"{self.sql(this)} {op} {self.sql(exp.Interval(this=expression.expression, unit=unit))}" expr = expression.expression
interval = expr if isinstance(expr, exp.Interval) else exp.Interval(this=expr, unit=unit)
return f"{self.sql(this)} {op} {self.sql(interval)}"
# BigQuery -> DuckDB conversion for the DATE function # BigQuery -> DuckDB conversion for the DATE function
@ -279,6 +284,7 @@ class DuckDB(Dialect):
SUPPORTS_ORDER_BY_ALL = True SUPPORTS_ORDER_BY_ALL = True
SUPPORTS_FIXED_SIZE_ARRAYS = True SUPPORTS_FIXED_SIZE_ARRAYS = True
STRICT_JSON_PATH_SYNTAX = False STRICT_JSON_PATH_SYNTAX = False
NUMBERS_CAN_BE_UNDERSCORE_SEPARATED = True
# https://duckdb.org/docs/sql/introduction.html#creating-a-new-table # https://duckdb.org/docs/sql/introduction.html#creating-a-new-table
NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE
@ -373,6 +379,7 @@ class DuckDB(Dialect):
"DECODE": lambda args: exp.Decode( "DECODE": lambda args: exp.Decode(
this=seq_get(args, 0), charset=exp.Literal.string("utf-8") this=seq_get(args, 0), charset=exp.Literal.string("utf-8")
), ),
"EDITDIST3": exp.Levenshtein.from_arg_list,
"ENCODE": lambda args: exp.Encode( "ENCODE": lambda args: exp.Encode(
this=seq_get(args, 0), charset=exp.Literal.string("utf-8") this=seq_get(args, 0), charset=exp.Literal.string("utf-8")
), ),
@ -380,6 +387,7 @@ class DuckDB(Dialect):
"EPOCH_MS": lambda args: exp.UnixToTime( "EPOCH_MS": lambda args: exp.UnixToTime(
this=seq_get(args, 0), scale=exp.UnixToTime.MILLIS this=seq_get(args, 0), scale=exp.UnixToTime.MILLIS
), ),
"GENERATE_SERIES": _build_generate_series(),
"JSON": exp.ParseJSON.from_arg_list, "JSON": exp.ParseJSON.from_arg_list,
"JSON_EXTRACT_PATH": parser.build_extract_json_with_path(exp.JSONExtract), "JSON_EXTRACT_PATH": parser.build_extract_json_with_path(exp.JSONExtract),
"JSON_EXTRACT_STRING": parser.build_extract_json_with_path(exp.JSONExtractScalar), "JSON_EXTRACT_STRING": parser.build_extract_json_with_path(exp.JSONExtractScalar),
@ -391,6 +399,7 @@ class DuckDB(Dialect):
"MAKE_TIMESTAMP": _build_make_timestamp, "MAKE_TIMESTAMP": _build_make_timestamp,
"QUANTILE_CONT": exp.PercentileCont.from_arg_list, "QUANTILE_CONT": exp.PercentileCont.from_arg_list,
"QUANTILE_DISC": exp.PercentileDisc.from_arg_list, "QUANTILE_DISC": exp.PercentileDisc.from_arg_list,
"RANGE": _build_generate_series(end_exclusive=True),
"REGEXP_EXTRACT": build_regexp_extract(exp.RegexpExtract), "REGEXP_EXTRACT": build_regexp_extract(exp.RegexpExtract),
"REGEXP_EXTRACT_ALL": build_regexp_extract(exp.RegexpExtractAll), "REGEXP_EXTRACT_ALL": build_regexp_extract(exp.RegexpExtractAll),
"REGEXP_MATCHES": exp.RegexpLike.from_arg_list, "REGEXP_MATCHES": exp.RegexpLike.from_arg_list,
@ -400,6 +409,7 @@ class DuckDB(Dialect):
replacement=seq_get(args, 2), replacement=seq_get(args, 2),
modifiers=seq_get(args, 3), modifiers=seq_get(args, 3),
), ),
"SHA256": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(256)),
"STRFTIME": build_formatted_time(exp.TimeToStr, "duckdb"), "STRFTIME": build_formatted_time(exp.TimeToStr, "duckdb"),
"STRING_SPLIT": exp.Split.from_arg_list, "STRING_SPLIT": exp.Split.from_arg_list,
"STRING_SPLIT_REGEX": exp.RegexpSplit.from_arg_list, "STRING_SPLIT_REGEX": exp.RegexpSplit.from_arg_list,
@ -412,9 +422,6 @@ class DuckDB(Dialect):
"TO_TIMESTAMP": exp.UnixToTime.from_arg_list, "TO_TIMESTAMP": exp.UnixToTime.from_arg_list,
"UNNEST": exp.Explode.from_arg_list, "UNNEST": exp.Explode.from_arg_list,
"XOR": binary_from_function(exp.BitwiseXor), "XOR": binary_from_function(exp.BitwiseXor),
"GENERATE_SERIES": _build_generate_series(),
"RANGE": _build_generate_series(end_exclusive=True),
"EDITDIST3": exp.Levenshtein.from_arg_list,
} }
FUNCTIONS.pop("DATE_SUB") FUNCTIONS.pop("DATE_SUB")
@ -470,7 +477,9 @@ class DuckDB(Dialect):
self, this: t.Optional[exp.Expression] = None self, this: t.Optional[exp.Expression] = None
) -> t.Optional[exp.Expression]: ) -> t.Optional[exp.Expression]:
bracket = super()._parse_bracket(this) bracket = super()._parse_bracket(this)
if isinstance(bracket, exp.Bracket):
if self.dialect.version < Version("1.2.0") and isinstance(bracket, exp.Bracket):
# https://duckdb.org/2025/02/05/announcing-duckdb-120.html#breaking-changes
bracket.set("returns_list_for_maps", True) bracket.set("returns_list_for_maps", True)
return bracket return bracket
@ -574,6 +583,7 @@ class DuckDB(Dialect):
exp.Encode: lambda self, e: encode_decode_sql(self, e, "ENCODE", replace=False), exp.Encode: lambda self, e: encode_decode_sql(self, e, "ENCODE", replace=False),
exp.GenerateDateArray: _generate_datetime_array_sql, exp.GenerateDateArray: _generate_datetime_array_sql,
exp.GenerateTimestampArray: _generate_datetime_array_sql, exp.GenerateTimestampArray: _generate_datetime_array_sql,
exp.HexString: lambda self, e: self.hexstring_sql(e, binary_function_repr="FROM_HEX"),
exp.Explode: rename_func("UNNEST"), exp.Explode: rename_func("UNNEST"),
exp.IntDiv: lambda self, e: self.binary(e, "//"), exp.IntDiv: lambda self, e: self.binary(e, "//"),
exp.IsInf: rename_func("ISINF"), exp.IsInf: rename_func("ISINF"),
@ -682,6 +692,7 @@ class DuckDB(Dialect):
exp.DataType.Type.CHAR: "TEXT", exp.DataType.Type.CHAR: "TEXT",
exp.DataType.Type.DATETIME: "TIMESTAMP", exp.DataType.Type.DATETIME: "TIMESTAMP",
exp.DataType.Type.FLOAT: "REAL", exp.DataType.Type.FLOAT: "REAL",
exp.DataType.Type.JSONB: "JSON",
exp.DataType.Type.NCHAR: "TEXT", exp.DataType.Type.NCHAR: "TEXT",
exp.DataType.Type.NVARCHAR: "TEXT", exp.DataType.Type.NVARCHAR: "TEXT",
exp.DataType.Type.UINT: "UINTEGER", exp.DataType.Type.UINT: "UINTEGER",
@ -894,7 +905,18 @@ class DuckDB(Dialect):
return self.function_fallback_sql(expression) return self.function_fallback_sql(expression)
def countif_sql(self, expression: exp.CountIf) -> str:
if self.dialect.version >= Version("1.2"):
return self.function_fallback_sql(expression)
# https://github.com/tobymao/sqlglot/pull/4749
return count_if_to_sum(self, expression)
def bracket_sql(self, expression: exp.Bracket) -> str: def bracket_sql(self, expression: exp.Bracket) -> str:
if self.dialect.version >= Version("1.2"):
return super().bracket_sql(expression)
# https://duckdb.org/2025/02/05/announcing-duckdb-120.html#breaking-changes
this = expression.this this = expression.this
if isinstance(this, exp.Array): if isinstance(this, exp.Array):
this.replace(exp.paren(this)) this.replace(exp.paren(this))

View file

@ -299,6 +299,7 @@ class MySQL(Dialect):
"CONVERT_TZ": lambda args: exp.ConvertTimezone( "CONVERT_TZ": lambda args: exp.ConvertTimezone(
source_tz=seq_get(args, 1), target_tz=seq_get(args, 2), timestamp=seq_get(args, 0) source_tz=seq_get(args, 1), target_tz=seq_get(args, 2), timestamp=seq_get(args, 0)
), ),
"CURDATE": exp.CurrentDate.from_arg_list,
"DATE": lambda args: exp.TsOrDsToDate(this=seq_get(args, 0)), "DATE": lambda args: exp.TsOrDsToDate(this=seq_get(args, 0)),
"DATE_ADD": build_date_delta_with_interval(exp.DateAdd), "DATE_ADD": build_date_delta_with_interval(exp.DateAdd),
"DATE_FORMAT": build_formatted_time(exp.TimeToStr, "mysql"), "DATE_FORMAT": build_formatted_time(exp.TimeToStr, "mysql"),
@ -438,6 +439,11 @@ class MySQL(Dialect):
"MODIFY": lambda self: self._parse_alter_table_alter(), "MODIFY": lambda self: self._parse_alter_table_alter(),
} }
ALTER_ALTER_PARSERS = {
**parser.Parser.ALTER_ALTER_PARSERS,
"INDEX": lambda self: self._parse_alter_table_alter_index(),
}
SCHEMA_UNNAMED_CONSTRAINTS = { SCHEMA_UNNAMED_CONSTRAINTS = {
*parser.Parser.SCHEMA_UNNAMED_CONSTRAINTS, *parser.Parser.SCHEMA_UNNAMED_CONSTRAINTS,
"FULLTEXT", "FULLTEXT",
@ -692,6 +698,18 @@ class MySQL(Dialect):
on_condition=self._parse_on_condition(), on_condition=self._parse_on_condition(),
) )
def _parse_alter_table_alter_index(self) -> exp.AlterIndex:
index = self._parse_field(any_token=True)
if self._match_text_seq("VISIBLE"):
visible = True
elif self._match_text_seq("INVISIBLE"):
visible = False
else:
visible = None
return self.expression(exp.AlterIndex, this=index, visible=visible)
class Generator(generator.Generator): class Generator(generator.Generator):
INTERVAL_ALLOWS_PLURAL_FORM = False INTERVAL_ALLOWS_PLURAL_FORM = False
LOCKING_READS_SUPPORTED = True LOCKING_READS_SUPPORTED = True
@ -792,6 +810,7 @@ class MySQL(Dialect):
exp.DataType.Type.USMALLINT: "SMALLINT", exp.DataType.Type.USMALLINT: "SMALLINT",
exp.DataType.Type.UTINYINT: "TINYINT", exp.DataType.Type.UTINYINT: "TINYINT",
exp.DataType.Type.UDECIMAL: "DECIMAL", exp.DataType.Type.UDECIMAL: "DECIMAL",
exp.DataType.Type.UDOUBLE: "DOUBLE",
} }
TIMESTAMP_TYPE_MAPPING = { TIMESTAMP_TYPE_MAPPING = {

View file

@ -650,7 +650,7 @@ class Postgres(Dialect):
if isinstance(expression.parent, (exp.From, exp.Join)): if isinstance(expression.parent, (exp.From, exp.Join)):
generate_series = ( generate_series = (
exp.select("value::date") exp.select("value::date")
.from_(generate_series.as_("value")) .from_(exp.Table(this=generate_series).as_("_t", table=["value"]))
.subquery(expression.args.get("alias") or "_unnested_generate_series") .subquery(expression.args.get("alias") or "_unnested_generate_series")
) )
return self.sql(generate_series) return self.sql(generate_series)

View file

@ -222,6 +222,7 @@ class Presto(Dialect):
} }
class Tokenizer(tokens.Tokenizer): class Tokenizer(tokens.Tokenizer):
HEX_STRINGS = [("x'", "'"), ("X'", "'")]
UNICODE_STRINGS = [ UNICODE_STRINGS = [
(prefix + q, q) (prefix + q, q)
for q in t.cast(t.List[str], tokens.Tokenizer.QUOTES) for q in t.cast(t.List[str], tokens.Tokenizer.QUOTES)
@ -400,7 +401,6 @@ class Presto(Dialect):
exp.If: if_sql(), exp.If: if_sql(),
exp.ILike: no_ilike_sql, exp.ILike: no_ilike_sql,
exp.Initcap: _initcap_sql, exp.Initcap: _initcap_sql,
exp.JSONExtract: lambda self, e: self.jsonextract_sql(e),
exp.Last: _first_last_sql, exp.Last: _first_last_sql,
exp.LastDay: lambda self, e: self.func("LAST_DAY_OF_MONTH", e.this), exp.LastDay: lambda self, e: self.func("LAST_DAY_OF_MONTH", e.this),
exp.Lateral: explode_to_unnest_sql, exp.Lateral: explode_to_unnest_sql,

View file

@ -176,19 +176,27 @@ def _date_trunc_to_time(args: t.List) -> exp.DateTrunc | exp.TimestampTrunc:
return trunc return trunc
def _unqualify_unpivot_columns(expression: exp.Expression) -> exp.Expression: def _unqualify_pivot_columns(expression: exp.Expression) -> exp.Expression:
""" """
Snowflake doesn't allow columns referenced in UNPIVOT to be qualified, Snowflake doesn't allow columns referenced in UNPIVOT to be qualified,
so we need to unqualify them. so we need to unqualify them. Same goes for ANY ORDER BY <column>.
Example: Example:
>>> from sqlglot import parse_one >>> from sqlglot import parse_one
>>> expr = parse_one("SELECT * FROM m_sales UNPIVOT(sales FOR month IN (m_sales.jan, feb, mar, april))") >>> expr = parse_one("SELECT * FROM m_sales UNPIVOT(sales FOR month IN (m_sales.jan, feb, mar, april))")
>>> print(_unqualify_unpivot_columns(expr).sql(dialect="snowflake")) >>> print(_unqualify_pivot_columns(expr).sql(dialect="snowflake"))
SELECT * FROM m_sales UNPIVOT(sales FOR month IN (jan, feb, mar, april)) SELECT * FROM m_sales UNPIVOT(sales FOR month IN (jan, feb, mar, april))
""" """
if isinstance(expression, exp.Pivot) and expression.unpivot: if isinstance(expression, exp.Pivot):
if expression.unpivot:
expression = transforms.unqualify_columns(expression) expression = transforms.unqualify_columns(expression)
else:
field = expression.args.get("field")
field_expr = seq_get(field.expressions if field else [], 0)
if isinstance(field_expr, exp.PivotAny):
unqualified_field_expr = transforms.unqualify_columns(field_expr)
t.cast(exp.Expression, field).set("expressions", unqualified_field_expr, 0)
return expression return expression
@ -512,6 +520,8 @@ class Snowflake(Dialect):
} }
SHOW_PARSERS = { SHOW_PARSERS = {
"DATABASES": _show_parser("DATABASES"),
"TERSE DATABASES": _show_parser("DATABASES"),
"SCHEMAS": _show_parser("SCHEMAS"), "SCHEMAS": _show_parser("SCHEMAS"),
"TERSE SCHEMAS": _show_parser("SCHEMAS"), "TERSE SCHEMAS": _show_parser("SCHEMAS"),
"OBJECTS": _show_parser("OBJECTS"), "OBJECTS": _show_parser("OBJECTS"),
@ -531,6 +541,9 @@ class Snowflake(Dialect):
"COLUMNS": _show_parser("COLUMNS"), "COLUMNS": _show_parser("COLUMNS"),
"USERS": _show_parser("USERS"), "USERS": _show_parser("USERS"),
"TERSE USERS": _show_parser("USERS"), "TERSE USERS": _show_parser("USERS"),
"FUNCTIONS": _show_parser("FUNCTIONS"),
"PROCEDURES": _show_parser("PROCEDURES"),
"WAREHOUSES": _show_parser("WAREHOUSES"),
} }
CONSTRAINT_PARSERS = { CONSTRAINT_PARSERS = {
@ -565,6 +578,16 @@ class Snowflake(Dialect):
), ),
} }
def _parse_use(self) -> exp.Use:
if self._match_text_seq("SECONDARY", "ROLES"):
this = self._match_texts(("ALL", "NONE")) and exp.var(self._prev.text.upper())
roles = None if this else self._parse_csv(lambda: self._parse_table(schema=False))
return self.expression(
exp.Use, kind="SECONDARY ROLES", this=this, expressions=roles
)
return super()._parse_use()
def _negate_range( def _negate_range(
self, this: t.Optional[exp.Expression] = None self, this: t.Optional[exp.Expression] = None
) -> t.Optional[exp.Expression]: ) -> t.Optional[exp.Expression]:
@ -749,6 +772,14 @@ class Snowflake(Dialect):
if self._match(TokenType.IN): if self._match(TokenType.IN):
if self._match_text_seq("ACCOUNT"): if self._match_text_seq("ACCOUNT"):
scope_kind = "ACCOUNT" scope_kind = "ACCOUNT"
elif self._match_text_seq("CLASS"):
scope_kind = "CLASS"
scope = self._parse_table_parts()
elif self._match_text_seq("APPLICATION"):
scope_kind = "APPLICATION"
if self._match_text_seq("PACKAGE"):
scope_kind += " PACKAGE"
scope = self._parse_table_parts()
elif self._match_set(self.DB_CREATABLES): elif self._match_set(self.DB_CREATABLES):
scope_kind = self._prev.text.upper() scope_kind = self._prev.text.upper()
if self._curr: if self._curr:
@ -769,6 +800,8 @@ class Snowflake(Dialect):
"starts_with": self._match_text_seq("STARTS", "WITH") and self._parse_string(), "starts_with": self._match_text_seq("STARTS", "WITH") and self._parse_string(),
"limit": self._parse_limit(), "limit": self._parse_limit(),
"from": self._parse_string() if self._match(TokenType.FROM) else None, "from": self._parse_string() if self._match(TokenType.FROM) else None,
"privileges": self._match_text_seq("WITH", "PRIVILEGES")
and self._parse_csv(lambda: self._parse_var(any_token=True, upper=True)),
}, },
) )
@ -942,7 +975,7 @@ class Snowflake(Dialect):
exp.PercentileDisc: transforms.preprocess( exp.PercentileDisc: transforms.preprocess(
[transforms.add_within_group_for_percentiles] [transforms.add_within_group_for_percentiles]
), ),
exp.Pivot: transforms.preprocess([_unqualify_unpivot_columns]), exp.Pivot: transforms.preprocess([_unqualify_pivot_columns]),
exp.RegexpExtract: _regexpextract_sql, exp.RegexpExtract: _regexpextract_sql,
exp.RegexpExtractAll: _regexpextract_sql, exp.RegexpExtractAll: _regexpextract_sql,
exp.RegexpILike: _regexpilike_sql, exp.RegexpILike: _regexpilike_sql,
@ -1139,7 +1172,10 @@ class Snowflake(Dialect):
if from_: if from_:
from_ = f" FROM {from_}" from_ = f" FROM {from_}"
return f"SHOW {terse}{expression.name}{history}{like}{scope_kind}{scope}{starts_with}{limit}{from_}" privileges = self.expressions(expression, key="privileges", flat=True)
privileges = f" WITH PRIVILEGES {privileges}" if privileges else ""
return f"SHOW {terse}{expression.name}{history}{like}{scope_kind}{scope}{starts_with}{limit}{from_}{privileges}"
def describe_sql(self, expression: exp.Describe) -> str: def describe_sql(self, expression: exp.Describe) -> str:
# Default to table if kind is unknown # Default to table if kind is unknown

View file

@ -140,6 +140,7 @@ class SQLite(Dialect):
SUPPORTS_TO_NUMBER = False SUPPORTS_TO_NUMBER = False
EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False
SUPPORTS_MEDIAN = False SUPPORTS_MEDIAN = False
JSON_KEY_VALUE_PAIR_SEP = ","
SUPPORTED_JSON_PATH_PARTS = { SUPPORTED_JSON_PATH_PARTS = {
exp.JSONPathKey, exp.JSONPathKey,

View file

@ -11,9 +11,6 @@ class Trino(Presto):
SUPPORTS_USER_DEFINED_TYPES = False SUPPORTS_USER_DEFINED_TYPES = False
LOG_BASE_FIRST = True LOG_BASE_FIRST = True
class Tokenizer(Presto.Tokenizer):
HEX_STRINGS = [("X'", "'")]
class Parser(Presto.Parser): class Parser(Presto.Parser):
FUNCTION_PARSERS = { FUNCTION_PARSERS = {
**Presto.Parser.FUNCTION_PARSERS, **Presto.Parser.FUNCTION_PARSERS,
@ -56,6 +53,7 @@ class Trino(Presto):
option=self._parse_var_from_options(self.JSON_QUERY_OPTIONS, raise_unmatched=False), option=self._parse_var_from_options(self.JSON_QUERY_OPTIONS, raise_unmatched=False),
json_query=True, json_query=True,
quote=self._parse_json_query_quote(), quote=self._parse_json_query_quote(),
on_condition=self._parse_on_condition(),
) )
class Generator(Presto.Generator): class Generator(Presto.Generator):
@ -73,7 +71,6 @@ class Trino(Presto):
exp.Merge: merge_without_target_sql, exp.Merge: merge_without_target_sql,
exp.TimeStrToTime: lambda self, e: timestrtotime_sql(self, e, include_precision=True), exp.TimeStrToTime: lambda self, e: timestrtotime_sql(self, e, include_precision=True),
exp.Trim: trim_sql, exp.Trim: trim_sql,
exp.JSONExtract: lambda self, e: self.jsonextract_sql(e),
} }
SUPPORTED_JSON_PATH_PARTS = { SUPPORTED_JSON_PATH_PARTS = {
@ -93,7 +90,14 @@ class Trino(Presto):
quote = self.sql(expression, "quote") quote = self.sql(expression, "quote")
quote = f" {quote}" if quote else "" quote = f" {quote}" if quote else ""
return self.func("JSON_QUERY", expression.this, json_path + option + quote) on_condition = self.sql(expression, "on_condition")
on_condition = f" {on_condition}" if on_condition else ""
return self.func(
"JSON_QUERY",
expression.this,
json_path + option + quote + on_condition,
)
def groupconcat_sql(self, expression: exp.GroupConcat) -> str: def groupconcat_sql(self, expression: exp.GroupConcat) -> str:
this = expression.this this = expression.this

View file

@ -1282,20 +1282,6 @@ class TSQL(Dialect):
expression.this.set("catalog", None) expression.this.set("catalog", None)
return super().drop_sql(expression) return super().drop_sql(expression)
def declare_sql(self, expression: exp.Declare) -> str:
return f"DECLARE {self.expressions(expression, flat=True)}"
def declareitem_sql(self, expression: exp.DeclareItem) -> str:
variable = self.sql(expression, "this")
default = self.sql(expression, "default")
default = f" = {default}" if default else ""
kind = self.sql(expression, "kind")
if isinstance(expression.args.get("kind"), exp.Schema):
kind = f"TABLE {kind}"
return f"{variable} AS {kind}{default}"
def options_modifier(self, expression: exp.Expression) -> str: def options_modifier(self, expression: exp.Expression) -> str:
options = self.expressions(expression, key="options") options = self.expressions(expression, key="options")
return f" OPTION{self.wrap(options)}" if options else "" return f" OPTION{self.wrap(options)}" if options else ""

View file

@ -68,7 +68,6 @@ def diff(
target: exp.Expression, target: exp.Expression,
matchings: t.List[t.Tuple[exp.Expression, exp.Expression]] | None = None, matchings: t.List[t.Tuple[exp.Expression, exp.Expression]] | None = None,
delta_only: bool = False, delta_only: bool = False,
copy: bool = True,
**kwargs: t.Any, **kwargs: t.Any,
) -> t.List[Edit]: ) -> t.List[Edit]:
""" """
@ -97,9 +96,6 @@ def diff(
Note: expression references in this list must refer to the same node objects that are Note: expression references in this list must refer to the same node objects that are
referenced in the source / target trees. referenced in the source / target trees.
delta_only: excludes all `Keep` nodes from the diff. delta_only: excludes all `Keep` nodes from the diff.
copy: whether to copy the input expressions.
Note: if this is set to false, the caller must ensure that there are no shared references
in the two trees, otherwise the diffing algorithm may produce unexpected behavior.
kwargs: additional arguments to pass to the ChangeDistiller instance. kwargs: additional arguments to pass to the ChangeDistiller instance.
Returns: Returns:
@ -108,43 +104,53 @@ def diff(
expression tree into the target one. expression tree into the target one.
""" """
matchings = matchings or [] matchings = matchings or []
matching_ids = {id(n) for pair in matchings for n in pair}
def compute_node_mappings( def compute_node_mappings(
original: exp.Expression, copy: exp.Expression old_nodes: tuple[exp.Expression, ...], new_nodes: tuple[exp.Expression, ...]
) -> t.Dict[int, exp.Expression]: ) -> t.Dict[int, exp.Expression]:
node_mapping = {} node_mapping = {}
for old_node, new_node in zip( for old_node, new_node in zip(reversed(old_nodes), reversed(new_nodes)):
reversed(tuple(original.walk())), reversed(tuple(copy.walk()))
):
# We cache the hash of each new node here to speed up equality comparisons. If the input
# trees aren't copied, these hashes will be evicted before returning the edit script.
new_node._hash = hash(new_node) new_node._hash = hash(new_node)
node_mapping[id(old_node)] = new_node
old_node_id = id(old_node)
if old_node_id in matching_ids:
node_mapping[old_node_id] = new_node
return node_mapping return node_mapping
# if the source and target have any shared objects, that means there's an issue with the ast
# the algorithm won't work because the parent / hierarchies will be inaccurate
source_nodes = tuple(source.walk())
target_nodes = tuple(target.walk())
source_ids = {id(n) for n in source_nodes}
target_ids = {id(n) for n in target_nodes}
copy = (
len(source_nodes) != len(source_ids)
or len(target_nodes) != len(target_ids)
or source_ids & target_ids
)
source_copy = source.copy() if copy else source source_copy = source.copy() if copy else source
target_copy = target.copy() if copy else target target_copy = target.copy() if copy else target
node_mappings = { try:
**compute_node_mappings(source, source_copy), # We cache the hash of each new node here to speed up equality comparisons. If the input
**compute_node_mappings(target, target_copy), # trees aren't copied, these hashes will be evicted before returning the edit script.
} if copy and matchings:
matchings_copy = [(node_mappings[id(s)], node_mappings[id(t)]) for s, t in matchings] source_mapping = compute_node_mappings(source_nodes, tuple(source_copy.walk()))
target_mapping = compute_node_mappings(target_nodes, tuple(target_copy.walk()))
matchings = [(source_mapping[id(s)], target_mapping[id(t)]) for s, t in matchings]
else:
for node in chain(reversed(source_nodes), reversed(target_nodes)):
node._hash = hash(node)
edit_script = ChangeDistiller(**kwargs).diff( edit_script = ChangeDistiller(**kwargs).diff(
source_copy, source_copy,
target_copy, target_copy,
matchings=matchings_copy, matchings=matchings,
delta_only=delta_only, delta_only=delta_only,
) )
finally:
if not copy: if not copy:
for node in chain(source.walk(), target.walk()): for node in chain(source_nodes, target_nodes):
node._hash = None node._hash = None
return edit_script return edit_script
@ -186,8 +192,6 @@ class ChangeDistiller:
) -> t.List[Edit]: ) -> t.List[Edit]:
matchings = matchings or [] matchings = matchings or []
pre_matched_nodes = {id(s): id(t) for s, t in matchings} pre_matched_nodes = {id(s): id(t) for s, t in matchings}
if len({n for pair in pre_matched_nodes.items() for n in pair}) != 2 * len(matchings):
raise ValueError("Each node can be referenced at most once in the list of matchings")
self._source = source self._source = source
self._target = target self._target = target

View file

@ -1557,6 +1557,7 @@ class Show(Expression):
"log": False, "log": False,
"position": False, "position": False,
"types": False, "types": False,
"privileges": False,
} }
@ -1568,8 +1569,12 @@ class CharacterSet(Expression):
arg_types = {"this": True, "default": False} arg_types = {"this": True, "default": False}
class RecursiveWithSearch(Expression):
arg_types = {"kind": True, "this": True, "expression": True, "using": False}
class With(Expression): class With(Expression):
arg_types = {"expressions": True, "recursive": False} arg_types = {"expressions": True, "recursive": False, "search": False}
@property @property
def recursive(self) -> bool: def recursive(self) -> bool:
@ -1608,7 +1613,7 @@ class BitString(Condition):
class HexString(Condition): class HexString(Condition):
pass arg_types = {"this": True, "is_integer": False}
class ByteString(Condition): class ByteString(Condition):
@ -1698,9 +1703,15 @@ class AlterColumn(Expression):
"drop": False, "drop": False,
"comment": False, "comment": False,
"allow_null": False, "allow_null": False,
"visible": False,
} }
# https://dev.mysql.com/doc/refman/8.0/en/invisible-indexes.html
class AlterIndex(Expression):
arg_types = {"this": True, "visible": True}
# https://docs.aws.amazon.com/redshift/latest/dg/r_ALTER_TABLE.html # https://docs.aws.amazon.com/redshift/latest/dg/r_ALTER_TABLE.html
class AlterDistStyle(Expression): class AlterDistStyle(Expression):
pass pass
@ -2352,8 +2363,7 @@ class Fetch(Expression):
arg_types = { arg_types = {
"direction": False, "direction": False,
"count": False, "count": False,
"percent": False, "limit_options": False,
"with_ties": False,
} }
@ -2395,7 +2405,21 @@ class Lambda(Expression):
class Limit(Expression): class Limit(Expression):
arg_types = {"this": False, "expression": True, "offset": False, "expressions": False} arg_types = {
"this": False,
"expression": True,
"offset": False,
"limit_options": False,
"expressions": False,
}
class LimitOptions(Expression):
arg_types = {
"percent": False,
"rows": False,
"with_ties": False,
}
class Literal(Condition): class Literal(Condition):
@ -4475,6 +4499,7 @@ class DataType(Expression):
UINT256 = auto() UINT256 = auto()
UMEDIUMINT = auto() UMEDIUMINT = auto()
UDECIMAL = auto() UDECIMAL = auto()
UDOUBLE = auto()
UNION = auto() UNION = auto()
UNKNOWN = auto() # Sentinel value, useful for type annotation UNKNOWN = auto() # Sentinel value, useful for type annotation
USERDEFINED = "USER-DEFINED" USERDEFINED = "USER-DEFINED"
@ -4558,6 +4583,7 @@ class DataType(Expression):
Type.MONEY, Type.MONEY,
Type.SMALLMONEY, Type.SMALLMONEY,
Type.UDECIMAL, Type.UDECIMAL,
Type.UDOUBLE,
} }
NUMERIC_TYPES = { NUMERIC_TYPES = {
@ -4827,14 +4853,6 @@ class Connector(Binary):
pass pass
class And(Connector):
pass
class Or(Connector):
pass
class BitwiseAnd(Binary): class BitwiseAnd(Binary):
pass pass
@ -5288,11 +5306,11 @@ class AnonymousAggFunc(AggFunc):
# https://clickhouse.com/docs/en/sql-reference/aggregate-functions/combinators # https://clickhouse.com/docs/en/sql-reference/aggregate-functions/combinators
class CombinedAggFunc(AnonymousAggFunc): class CombinedAggFunc(AnonymousAggFunc):
arg_types = {"this": True, "expressions": False, "parts": True} arg_types = {"this": True, "expressions": False}
class CombinedParameterizedAgg(ParameterizedAgg): class CombinedParameterizedAgg(ParameterizedAgg):
arg_types = {"this": True, "expressions": True, "params": True, "parts": True} arg_types = {"this": True, "expressions": True, "params": True}
# https://docs.snowflake.com/en/sql-reference/functions/hll # https://docs.snowflake.com/en/sql-reference/functions/hll
@ -5558,6 +5576,11 @@ class TryCast(Cast):
pass pass
# https://clickhouse.com/docs/sql-reference/data-types/newjson#reading-json-paths-as-sub-columns
class JSONCast(Cast):
pass
class Try(Func): class Try(Func):
pass pass
@ -5959,6 +5982,14 @@ class LowerHex(Hex):
pass pass
class And(Connector, Func):
pass
class Or(Connector, Func):
pass
class Xor(Connector, Func): class Xor(Connector, Func):
arg_types = {"this": False, "expression": False, "expressions": False} arg_types = {"this": False, "expression": False, "expressions": False}
@ -6181,6 +6212,7 @@ class JSONExtract(Binary, Func):
"json_query": False, "json_query": False,
"option": False, "option": False,
"quote": False, "quote": False,
"on_condition": False,
} }
_sql_names = ["JSON_EXTRACT"] _sql_names = ["JSON_EXTRACT"]
is_var_len_args = True is_var_len_args = True
@ -6820,7 +6852,7 @@ class Year(Func):
class Use(Expression): class Use(Expression):
arg_types = {"this": True, "kind": False} arg_types = {"this": False, "expressions": False, "kind": False}
class Merge(DML): class Merge(DML):

View file

@ -1238,8 +1238,10 @@ class Generator(metaclass=_Generator):
if self.CTE_RECURSIVE_KEYWORD_REQUIRED and expression.args.get("recursive") if self.CTE_RECURSIVE_KEYWORD_REQUIRED and expression.args.get("recursive")
else "" else ""
) )
search = self.sql(expression, "search")
search = f" {search}" if search else ""
return f"WITH {recursive}{sql}" return f"WITH {recursive}{sql}{search}"
def cte_sql(self, expression: exp.CTE) -> str: def cte_sql(self, expression: exp.CTE) -> str:
alias = expression.args.get("alias") alias = expression.args.get("alias")
@ -1276,12 +1278,31 @@ class Generator(metaclass=_Generator):
return f"{self.dialect.BIT_START}{this}{self.dialect.BIT_END}" return f"{self.dialect.BIT_START}{this}{self.dialect.BIT_END}"
return f"{int(this, 2)}" return f"{int(this, 2)}"
def hexstring_sql(self, expression: exp.HexString) -> str: def hexstring_sql(
self, expression: exp.HexString, binary_function_repr: t.Optional[str] = None
) -> str:
this = self.sql(expression, "this") this = self.sql(expression, "this")
if self.dialect.HEX_START: is_integer_type = expression.args.get("is_integer")
return f"{self.dialect.HEX_START}{this}{self.dialect.HEX_END}"
if (is_integer_type and not self.dialect.HEX_STRING_IS_INTEGER_TYPE) or (
not self.dialect.HEX_START and not binary_function_repr
):
# Integer representation will be returned if:
# - The read dialect treats the hex value as integer literal but not the write
# - The transpilation is not supported (write dialect hasn't set HEX_START or the param flag)
return f"{int(this, 16)}" return f"{int(this, 16)}"
if not is_integer_type:
# Read dialect treats the hex value as BINARY/BLOB
if binary_function_repr:
# The write dialect supports the transpilation to its equivalent BINARY/BLOB
return self.func(binary_function_repr, exp.Literal.string(this))
if self.dialect.HEX_STRING_IS_INTEGER_TYPE:
# The write dialect does not support the transpilation, it'll treat the hex value as INTEGER
self.unsupported("Unsupported transpilation from BINARY/BLOB hex string")
return f"{self.dialect.HEX_START}{this}{self.dialect.HEX_END}"
def bytestring_sql(self, expression: exp.ByteString) -> str: def bytestring_sql(self, expression: exp.ByteString) -> str:
this = self.sql(expression, "this") this = self.sql(expression, "this")
if self.dialect.BYTE_START: if self.dialect.BYTE_START:
@ -1467,10 +1488,17 @@ class Generator(metaclass=_Generator):
direction = f" {direction}" if direction else "" direction = f" {direction}" if direction else ""
count = self.sql(expression, "count") count = self.sql(expression, "count")
count = f" {count}" if count else "" count = f" {count}" if count else ""
if expression.args.get("percent"): limit_options = self.sql(expression, "limit_options")
count = f"{count} PERCENT" limit_options = f"{limit_options}" if limit_options else " ROWS ONLY"
with_ties_or_only = "WITH TIES" if expression.args.get("with_ties") else "ONLY" return f"{self.seg('FETCH')}{direction}{count}{limit_options}"
return f"{self.seg('FETCH')}{direction}{count} ROWS {with_ties_or_only}"
def limitoptions_sql(self, expression: exp.LimitOptions) -> str:
percent = " PERCENT" if expression.args.get("percent") else ""
rows = " ROWS" if expression.args.get("rows") else ""
with_ties = " WITH TIES" if expression.args.get("with_ties") else ""
if not with_ties and rows:
with_ties = " ONLY"
return f"{percent}{rows}{with_ties}"
def filter_sql(self, expression: exp.Filter) -> str: def filter_sql(self, expression: exp.Filter) -> str:
if self.AGGREGATE_FILTER_SUPPORTED: if self.AGGREGATE_FILTER_SUPPORTED:
@ -2261,9 +2289,10 @@ class Generator(metaclass=_Generator):
args_sql = ", ".join(self.sql(e) for e in args) args_sql = ", ".join(self.sql(e) for e in args)
args_sql = f"({args_sql})" if top and any(not e.is_number for e in args) else args_sql args_sql = f"({args_sql})" if top and any(not e.is_number for e in args) else args_sql
expressions = self.expressions(expression, flat=True) expressions = self.expressions(expression, flat=True)
limit_options = self.sql(expression, "limit_options")
expressions = f" BY {expressions}" if expressions else "" expressions = f" BY {expressions}" if expressions else ""
return f"{this}{self.seg('TOP' if top else 'LIMIT')} {args_sql}{expressions}" return f"{this}{self.seg('TOP' if top else 'LIMIT')} {args_sql}{limit_options}{expressions}"
def offset_sql(self, expression: exp.Offset) -> str: def offset_sql(self, expression: exp.Offset) -> str:
this = self.sql(expression, "this") this = self.sql(expression, "this")
@ -2284,9 +2313,7 @@ class Generator(metaclass=_Generator):
return f"{global_}{kind}{this}{expressions}{collate}" return f"{global_}{kind}{this}{expressions}{collate}"
def set_sql(self, expression: exp.Set) -> str: def set_sql(self, expression: exp.Set) -> str:
expressions = ( expressions = f" {self.expressions(expression, flat=True)}"
f" {self.expressions(expression, flat=True)}" if expression.expressions else ""
)
tag = " TAG" if expression.args.get("tag") else "" tag = " TAG" if expression.args.get("tag") else ""
return f"{'UNSET' if expression.args.get('unset') else 'SET'}{tag}{expressions}" return f"{'UNSET' if expression.args.get('unset') else 'SET'}{tag}{expressions}"
@ -3265,6 +3292,10 @@ class Generator(metaclass=_Generator):
if comment: if comment:
return f"ALTER COLUMN {this} COMMENT {comment}" return f"ALTER COLUMN {this} COMMENT {comment}"
visible = expression.args.get("visible")
if visible:
return f"ALTER COLUMN {this} SET {visible}"
allow_null = expression.args.get("allow_null") allow_null = expression.args.get("allow_null")
drop = expression.args.get("drop") drop = expression.args.get("drop")
@ -3277,6 +3308,14 @@ class Generator(metaclass=_Generator):
return f"ALTER COLUMN {this} DROP DEFAULT" return f"ALTER COLUMN {this} DROP DEFAULT"
def alterindex_sql(self, expression: exp.AlterIndex) -> str:
this = self.sql(expression, "this")
visible = expression.args.get("visible")
visible_sql = "VISIBLE" if visible else "INVISIBLE"
return f"ALTER INDEX {this} {visible_sql}"
def alterdiststyle_sql(self, expression: exp.AlterDistStyle) -> str: def alterdiststyle_sql(self, expression: exp.AlterDistStyle) -> str:
this = self.sql(expression, "this") this = self.sql(expression, "this")
if not isinstance(expression.this, exp.Var): if not isinstance(expression.this, exp.Var):
@ -3499,6 +3538,9 @@ class Generator(metaclass=_Generator):
def trycast_sql(self, expression: exp.TryCast) -> str: def trycast_sql(self, expression: exp.TryCast) -> str:
return self.cast_sql(expression, safe_prefix="TRY_") return self.cast_sql(expression, safe_prefix="TRY_")
def jsoncast_sql(self, expression: exp.JSONCast) -> str:
return self.cast_sql(expression)
def try_sql(self, expression: exp.Try) -> str: def try_sql(self, expression: exp.Try) -> str:
if not self.TRY_SUPPORTED: if not self.TRY_SUPPORTED:
self.unsupported("Unsupported TRY function") self.unsupported("Unsupported TRY function")
@ -3523,7 +3565,7 @@ class Generator(metaclass=_Generator):
def use_sql(self, expression: exp.Use) -> str: def use_sql(self, expression: exp.Use) -> str:
kind = self.sql(expression, "kind") kind = self.sql(expression, "kind")
kind = f" {kind}" if kind else "" kind = f" {kind}" if kind else ""
this = self.sql(expression, "this") this = self.sql(expression, "this") or self.expressions(expression, flat=True)
this = f" {this}" if this else "" this = f" {this}" if this else ""
return f"USE{kind}{this}" return f"USE{kind}{this}"
@ -4762,3 +4804,45 @@ class Generator(metaclass=_Generator):
connection = f"WITH CONNECTION {connection} " if connection else "" connection = f"WITH CONNECTION {connection} " if connection else ""
options = self.sql(expression, "options") options = self.sql(expression, "options")
return f"EXPORT DATA {connection}{options} AS {this}" return f"EXPORT DATA {connection}{options} AS {this}"
def declare_sql(self, expression: exp.Declare) -> str:
return f"DECLARE {self.expressions(expression, flat=True)}"
def declareitem_sql(self, expression: exp.DeclareItem) -> str:
variable = self.sql(expression, "this")
default = self.sql(expression, "default")
default = f" = {default}" if default else ""
kind = self.sql(expression, "kind")
if isinstance(expression.args.get("kind"), exp.Schema):
kind = f"TABLE {kind}"
return f"{variable} AS {kind}{default}"
def recursivewithsearch_sql(self, expression: exp.RecursiveWithSearch) -> str:
kind = self.sql(expression, "kind")
this = self.sql(expression, "this")
set = self.sql(expression, "expression")
using = self.sql(expression, "using")
using = f" USING {using}" if using else ""
kind_sql = kind if kind == "CYCLE" else f"SEARCH {kind} FIRST BY"
return f"{kind_sql} {this} SET {set}{using}"
def parameterizedagg_sql(self, expression: exp.ParameterizedAgg) -> str:
params = self.expressions(expression, key="params", flat=True)
return self.func(expression.name, *expression.expressions) + f"({params})"
def anonymousaggfunc_sql(self, expression: exp.AnonymousAggFunc) -> str:
return self.func(expression.name, *expression.expressions)
def combinedaggfunc_sql(self, expression: exp.CombinedAggFunc) -> str:
return self.anonymousaggfunc_sql(expression)
def combinedparameterizedagg_sql(self, expression: exp.CombinedParameterizedAgg) -> str:
return self.parameterizedagg_sql(expression)
def show_sql(self, expression: exp.Show) -> str:
self.unsupported("Unsupported SHOW statement")
return ""

View file

@ -195,7 +195,7 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
# Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the
# exp.SetOperation is the expression of a scope source, as selecting from it multiple times # exp.SetOperation is the expression of a scope source, as selecting from it multiple times
# would reprocess the entire subtree to coerce the types of its operands' projections # would reprocess the entire subtree to coerce the types of its operands' projections
self._setop_column_types: t.Dict[int, t.Dict[str, exp.DataType.Type]] = {} self._setop_column_types: t.Dict[int, t.Dict[str, exp.DataType | exp.DataType.Type]] = {}
def _set_type( def _set_type(
self, expression: exp.Expression, target_type: t.Optional[exp.DataType | exp.DataType.Type] self, expression: exp.Expression, target_type: t.Optional[exp.DataType | exp.DataType.Type]
@ -312,18 +312,32 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
def _maybe_coerce( def _maybe_coerce(
self, type1: exp.DataType | exp.DataType.Type, type2: exp.DataType | exp.DataType.Type self, type1: exp.DataType | exp.DataType.Type, type2: exp.DataType | exp.DataType.Type
) -> exp.DataType.Type: ) -> exp.DataType | exp.DataType.Type:
type1_value = type1.this if isinstance(type1, exp.DataType) else type1 """
type2_value = type2.this if isinstance(type2, exp.DataType) else type2 Returns type2 if type1 can be coerced into it, otherwise type1.
If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters),
we assume type1 does not coerce into type2, so we also return it in this case.
"""
if isinstance(type1, exp.DataType):
if type1.expressions:
return type1
type1_value = type1.this
else:
type1_value = type1
if isinstance(type2, exp.DataType):
if type2.expressions:
return type1
type2_value = type2.this
else:
type2_value = type2
# We propagate the UNKNOWN type upwards if found # We propagate the UNKNOWN type upwards if found
if exp.DataType.Type.UNKNOWN in (type1_value, type2_value): if exp.DataType.Type.UNKNOWN in (type1_value, type2_value):
return exp.DataType.Type.UNKNOWN return exp.DataType.Type.UNKNOWN
return t.cast( return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value
exp.DataType.Type,
type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value,
)
def _annotate_binary(self, expression: B) -> B: def _annotate_binary(self, expression: B) -> B:
self._annotate_args(expression) self._annotate_args(expression)

View file

@ -102,7 +102,10 @@ def qualify_columns(
qualify_outputs(scope) qualify_outputs(scope)
_expand_group_by(scope, dialect) _expand_group_by(scope, dialect)
_expand_order_by(scope, resolver)
# DISTINCT ON and ORDER BY follow the same rules (tested in DuckDB, Postgres, ClickHouse)
# https://www.postgresql.org/docs/current/sql-select.html#SQL-DISTINCT
_expand_order_by_and_distinct_on(scope, resolver)
if dialect == "bigquery": if dialect == "bigquery":
annotator.annotate_scope(scope) annotator.annotate_scope(scope)
@ -359,35 +362,40 @@ def _expand_group_by(scope: Scope, dialect: DialectType) -> None:
expression.set("group", group) expression.set("group", group)
def _expand_order_by(scope: Scope, resolver: Resolver) -> None: def _expand_order_by_and_distinct_on(scope: Scope, resolver: Resolver) -> None:
order = scope.expression.args.get("order") for modifier_key in ("order", "distinct"):
if not order: modifier = scope.expression.args.get(modifier_key)
return if isinstance(modifier, exp.Distinct):
modifier = modifier.args.get("on")
ordereds = order.expressions if not isinstance(modifier, exp.Expression):
for ordered, new_expression in zip( continue
ordereds,
modifier_expressions = modifier.expressions
if modifier_key == "order":
modifier_expressions = [ordered.this for ordered in modifier_expressions]
for original, expanded in zip(
modifier_expressions,
_expand_positional_references( _expand_positional_references(
scope, (o.this for o in ordereds), resolver.schema.dialect, alias=True scope, modifier_expressions, resolver.schema.dialect, alias=True
), ),
): ):
for agg in ordered.find_all(exp.AggFunc): for agg in original.find_all(exp.AggFunc):
for col in agg.find_all(exp.Column): for col in agg.find_all(exp.Column):
if not col.table: if not col.table:
col.set("table", resolver.get_table(col.name)) col.set("table", resolver.get_table(col.name))
ordered.set("this", new_expression) original.replace(expanded)
if scope.expression.args.get("group"): if scope.expression.args.get("group"):
selects = {s.this: exp.column(s.alias_or_name) for s in scope.expression.selects} selects = {s.this: exp.column(s.alias_or_name) for s in scope.expression.selects}
for ordered in ordereds: for expression in modifier_expressions:
ordered = ordered.this expression.replace(
exp.to_identifier(_select_by_pos(scope, expression).alias)
ordered.replace( if expression.is_int
exp.to_identifier(_select_by_pos(scope, ordered).alias) else selects.get(expression, expression)
if ordered.is_int
else selects.get(ordered, ordered)
) )

View file

@ -97,12 +97,16 @@ def qualify_tables(
source.alias source.alias
) )
_qualify(source) if pivots:
if not pivots[0].alias:
pivot_alias = next_alias_name()
pivots[0].set("alias", exp.TableAlias(this=exp.to_identifier(pivot_alias)))
if pivots and not pivots[0].alias: # This case corresponds to a pivoted CTE, we don't want to qualify that
pivots[0].set( if isinstance(scope.sources.get(source.alias_or_name), Scope):
"alias", exp.TableAlias(this=exp.to_identifier(next_alias_name())) continue
)
_qualify(source)
if infer_csv_schemas and schema and isinstance(source.this, exp.ReadCSV): if infer_csv_schemas and schema and isinstance(source.this, exp.ReadCSV):
with csv_reader(source.this) as reader: with csv_reader(source.this) as reader:

View file

@ -282,7 +282,14 @@ class Scope:
self._columns = [] self._columns = []
for column in columns + external_columns: for column in columns + external_columns:
ancestor = column.find_ancestor( ancestor = column.find_ancestor(
exp.Select, exp.Qualify, exp.Order, exp.Having, exp.Hint, exp.Table, exp.Star exp.Select,
exp.Qualify,
exp.Order,
exp.Having,
exp.Hint,
exp.Table,
exp.Star,
exp.Distinct,
) )
if ( if (
not ancestor not ancestor
@ -290,9 +297,9 @@ class Scope:
or isinstance(ancestor, exp.Select) or isinstance(ancestor, exp.Select)
or (isinstance(ancestor, exp.Table) and not isinstance(ancestor.this, exp.Func)) or (isinstance(ancestor, exp.Table) and not isinstance(ancestor.this, exp.Func))
or ( or (
isinstance(ancestor, exp.Order) isinstance(ancestor, (exp.Order, exp.Distinct))
and ( and (
isinstance(ancestor.parent, exp.Window) isinstance(ancestor.parent, (exp.Window, exp.WithinGroup))
or column.name not in named_selects or column.name not in named_selects
) )
) )

View file

@ -318,6 +318,7 @@ class Parser(metaclass=_Parser):
TokenType.FIXEDSTRING, TokenType.FIXEDSTRING,
TokenType.FLOAT, TokenType.FLOAT,
TokenType.DOUBLE, TokenType.DOUBLE,
TokenType.UDOUBLE,
TokenType.CHAR, TokenType.CHAR,
TokenType.NCHAR, TokenType.NCHAR,
TokenType.VARCHAR, TokenType.VARCHAR,
@ -418,6 +419,7 @@ class Parser(metaclass=_Parser):
TokenType.SMALLINT: TokenType.USMALLINT, TokenType.SMALLINT: TokenType.USMALLINT,
TokenType.TINYINT: TokenType.UTINYINT, TokenType.TINYINT: TokenType.UTINYINT,
TokenType.DECIMAL: TokenType.UDECIMAL, TokenType.DECIMAL: TokenType.UDECIMAL,
TokenType.DOUBLE: TokenType.UDOUBLE,
} }
SUBQUERY_PREDICATES = { SUBQUERY_PREDICATES = {
@ -733,6 +735,11 @@ class Parser(metaclass=_Parser):
COLUMN_OPERATORS = { COLUMN_OPERATORS = {
TokenType.DOT: None, TokenType.DOT: None,
TokenType.DOTCOLON: lambda self, this, to: self.expression(
exp.JSONCast,
this=this,
to=to,
),
TokenType.DCOLON: lambda self, this, to: self.expression( TokenType.DCOLON: lambda self, this, to: self.expression(
exp.Cast if self.STRICT_CAST else exp.TryCast, exp.Cast if self.STRICT_CAST else exp.TryCast,
this=this, this=this,
@ -827,11 +834,7 @@ class Parser(metaclass=_Parser):
TokenType.UNCACHE: lambda self: self._parse_uncache(), TokenType.UNCACHE: lambda self: self._parse_uncache(),
TokenType.UNPIVOT: lambda self: self._parse_simplified_pivot(is_unpivot=True), TokenType.UNPIVOT: lambda self: self._parse_simplified_pivot(is_unpivot=True),
TokenType.UPDATE: lambda self: self._parse_update(), TokenType.UPDATE: lambda self: self._parse_update(),
TokenType.USE: lambda self: self.expression( TokenType.USE: lambda self: self._parse_use(),
exp.Use,
kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
this=self._parse_table(schema=False),
),
TokenType.SEMICOLON: lambda self: exp.Semicolon(), TokenType.SEMICOLON: lambda self: exp.Semicolon(),
} }
@ -865,7 +868,11 @@ class Parser(metaclass=_Parser):
NUMERIC_PARSERS = { NUMERIC_PARSERS = {
TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text), TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text), TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text), TokenType.HEX_STRING: lambda self, token: self.expression(
exp.HexString,
this=token.text,
is_integer=self.dialect.HEX_STRING_IS_INTEGER_TYPE or None,
),
TokenType.NUMBER: lambda self, token: self.expression( TokenType.NUMBER: lambda self, token: self.expression(
exp.Literal, this=token.text, is_string=False exp.Literal, this=token.text, is_string=False
), ),
@ -1371,6 +1378,8 @@ class Parser(metaclass=_Parser):
OPERATION_MODIFIERS: t.Set[str] = set() OPERATION_MODIFIERS: t.Set[str] = set()
RECURSIVE_CTE_SEARCH_KIND = {"BREADTH", "DEPTH", "CYCLE"}
STRICT_CAST = True STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False PREFIXED_PIVOT_COLUMNS = False
@ -2967,6 +2976,13 @@ class Parser(metaclass=_Parser):
}, },
) )
def _parse_use(self) -> exp.Use:
return self.expression(
exp.Use,
kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
this=self._parse_table(schema=False),
)
def _parse_uncache(self) -> exp.Uncache: def _parse_uncache(self) -> exp.Uncache:
if not self._match(TokenType.TABLE): if not self._match(TokenType.TABLE):
self.raise_error("Expecting TABLE after UNCACHE") self.raise_error("Expecting TABLE after UNCACHE")
@ -3165,6 +3181,24 @@ class Parser(metaclass=_Parser):
return self._parse_set_operations(this) if parse_set_operation else this return self._parse_set_operations(this) if parse_set_operation else this
def _parse_recursive_with_search(self) -> t.Optional[exp.RecursiveWithSearch]:
self._match_text_seq("SEARCH")
kind = self._match_texts(self.RECURSIVE_CTE_SEARCH_KIND) and self._prev.text.upper()
if not kind:
return None
self._match_text_seq("FIRST", "BY")
return self.expression(
exp.RecursiveWithSearch,
kind=kind,
this=self._parse_id_var(),
expression=self._match_text_seq("SET") and self._parse_id_var(),
using=self._match_text_seq("USING") and self._parse_id_var(),
)
def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]: def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
if not skip_with_token and not self._match(TokenType.WITH): if not skip_with_token and not self._match(TokenType.WITH):
return None return None
@ -3189,7 +3223,11 @@ class Parser(metaclass=_Parser):
last_comments = self._prev_comments last_comments = self._prev_comments
return self.expression( return self.expression(
exp.With, comments=comments, expressions=expressions, recursive=recursive exp.With,
comments=comments,
expressions=expressions,
recursive=recursive,
search=self._parse_recursive_with_search(),
) )
def _parse_cte(self) -> t.Optional[exp.CTE]: def _parse_cte(self) -> t.Optional[exp.CTE]:
@ -4205,7 +4243,11 @@ class Parser(metaclass=_Parser):
names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions)) names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
columns: t.List[exp.Expression] = [] columns: t.List[exp.Expression] = []
for fld in pivot.args["field"].expressions: pivot_field_expressions = pivot.args["field"].expressions
# The `PivotAny` expression corresponds to `ANY ORDER BY <column>`; we can't infer in this case.
if not isinstance(seq_get(pivot_field_expressions, 0), exp.PivotAny):
for fld in pivot_field_expressions:
field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
for name in names: for name in names:
if self.PREFIXED_PIVOT_COLUMNS: if self.PREFIXED_PIVOT_COLUMNS:
@ -4413,6 +4455,13 @@ class Parser(metaclass=_Parser):
exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
) )
def _parse_limit_options(self) -> exp.LimitOptions:
percent = self._match(TokenType.PERCENT)
rows = self._match_set((TokenType.ROW, TokenType.ROWS))
self._match_text_seq("ONLY")
with_ties = self._match_text_seq("WITH", "TIES")
return self.expression(exp.LimitOptions, percent=percent, rows=rows, with_ties=with_ties)
def _parse_limit( def _parse_limit(
self, self,
this: t.Optional[exp.Expression] = None, this: t.Optional[exp.Expression] = None,
@ -4427,7 +4476,10 @@ class Parser(metaclass=_Parser):
if limit_paren: if limit_paren:
self._match_r_paren() self._match_r_paren()
limit_options = self._parse_limit_options()
else: else:
limit_options = None
expression = self._parse_term() expression = self._parse_term()
if self._match(TokenType.COMMA): if self._match(TokenType.COMMA):
@ -4442,6 +4494,7 @@ class Parser(metaclass=_Parser):
expression=expression, expression=expression,
offset=offset, offset=offset,
comments=comments, comments=comments,
limit_options=limit_options,
expressions=self._parse_limit_by(), expressions=self._parse_limit_by(),
) )
@ -4452,22 +4505,12 @@ class Parser(metaclass=_Parser):
direction = self._prev.text.upper() if direction else "FIRST" direction = self._prev.text.upper() if direction else "FIRST"
count = self._parse_field(tokens=self.FETCH_TOKENS) count = self._parse_field(tokens=self.FETCH_TOKENS)
percent = self._match(TokenType.PERCENT)
self._match_set((TokenType.ROW, TokenType.ROWS))
only = self._match_text_seq("ONLY")
with_ties = self._match_text_seq("WITH", "TIES")
if only and with_ties:
self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
return self.expression( return self.expression(
exp.Fetch, exp.Fetch,
direction=direction, direction=direction,
count=count, count=count,
percent=percent, limit_options=self._parse_limit_options(),
with_ties=with_ties,
) )
return this return this
@ -5003,16 +5046,21 @@ class Parser(metaclass=_Parser):
expressions = self._parse_csv(self._parse_equality) expressions = self._parse_csv(self._parse_equality)
elif is_aggregate: elif is_aggregate:
func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var( func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
any_token=False, tokens=(TokenType.VAR,) any_token=False, tokens=(TokenType.VAR, TokenType.ANY)
) )
if not func_or_ident or not self._match(TokenType.COMMA): if not func_or_ident:
return None return None
expressions = self._parse_csv( expressions = [func_or_ident]
if self._match(TokenType.COMMA):
expressions.extend(
self._parse_csv(
lambda: self._parse_types( lambda: self._parse_types(
check_func=check_func, schema=schema, allow_identifiers=allow_identifiers check_func=check_func,
schema=schema,
allow_identifiers=allow_identifiers,
)
) )
) )
expressions.insert(0, func_or_ident)
else: else:
expressions = self._parse_csv(self._parse_type_size) expressions = self._parse_csv(self._parse_type_size)
@ -5281,7 +5329,7 @@ class Parser(metaclass=_Parser):
op_token = self._prev.token_type op_token = self._prev.token_type
op = self.COLUMN_OPERATORS.get(op_token) op = self.COLUMN_OPERATORS.get(op_token)
if op_token == TokenType.DCOLON: if op_token in (TokenType.DCOLON, TokenType.DOTCOLON):
field = self._parse_dcolon() field = self._parse_dcolon()
if not field: if not field:
self.raise_error("Expected type") self.raise_error("Expected type")
@ -7071,6 +7119,12 @@ class Parser(metaclass=_Parser):
this=column, this=column,
allow_null=False, allow_null=False,
) )
if self._match_text_seq("SET", "VISIBLE"):
return self.expression(exp.AlterColumn, this=column, visible="VISIBLE")
if self._match_text_seq("SET", "INVISIBLE"):
return self.expression(exp.AlterColumn, this=column, visible="INVISIBLE")
self._match_text_seq("SET", "DATA") self._match_text_seq("SET", "DATA")
self._match_text_seq("TYPE") self._match_text_seq("TYPE")
return self.expression( return self.expression(

View file

@ -37,6 +37,7 @@ class TokenType(AutoName):
DASH = auto() DASH = auto()
PLUS = auto() PLUS = auto()
COLON = auto() COLON = auto()
DOTCOLON = auto()
DCOLON = auto() DCOLON = auto()
DQMARK = auto() DQMARK = auto()
SEMICOLON = auto() SEMICOLON = auto()
@ -123,6 +124,7 @@ class TokenType(AutoName):
UINT256 = auto() UINT256 = auto()
FLOAT = auto() FLOAT = auto()
DOUBLE = auto() DOUBLE = auto()
UDOUBLE = auto()
DECIMAL = auto() DECIMAL = auto()
DECIMAL32 = auto() DECIMAL32 = auto()
DECIMAL64 = auto() DECIMAL64 = auto()

View file

@ -258,7 +258,7 @@ def eliminate_qualify(expression: exp.Expression) -> exp.Expression:
} }
select_candidates = exp.Window if expression.is_star else (exp.Window, exp.Column) select_candidates = exp.Window if expression.is_star else (exp.Window, exp.Column)
for select_candidate in qualify_filters.find_all(select_candidates): for select_candidate in list(qualify_filters.find_all(select_candidates)):
if isinstance(select_candidate, exp.Window): if isinstance(select_candidate, exp.Window):
if expression_by_alias: if expression_by_alias:
for column in select_candidate.find_all(exp.Column): for column in select_candidate.find_all(exp.Column):
@ -907,16 +907,15 @@ def eliminate_join_marks(expression: exp.Expression) -> exp.Expression:
len(marked_column_tables) == 1 len(marked_column_tables) == 1
), "Columns of only a single table can be marked with (+) in a given binary predicate" ), "Columns of only a single table can be marked with (+) in a given binary predicate"
# Add predicate if join already copied, or add join if it is new
join_this = old_joins.get(col.table, query_from).this join_this = old_joins.get(col.table, query_from).this
new_join = exp.Join(this=join_this, on=join_predicate, kind="LEFT") existing_join = new_joins.get(join_this.alias_or_name)
# Upsert new_join into new_joins dictionary
new_join_alias_or_name = new_join.alias_or_name
existing_join = new_joins.get(new_join_alias_or_name)
if existing_join: if existing_join:
existing_join.set("on", exp.and_(existing_join.args.get("on"), new_join.args["on"])) existing_join.set("on", exp.and_(existing_join.args["on"], join_predicate))
else: else:
new_joins[new_join_alias_or_name] = new_join new_joins[join_this.alias_or_name] = exp.Join(
this=join_this.copy(), on=join_predicate.copy(), kind="LEFT"
)
# If the parent of the target predicate is a binary node, then it now has only one child # If the parent of the target predicate is a binary node, then it now has only one child
if isinstance(predicate_parent, exp.Binary): if isinstance(predicate_parent, exp.Binary):

2
sqlglotrs/Cargo.lock generated
View file

@ -503,7 +503,7 @@ dependencies = [
[[package]] [[package]]
name = "sqlglotrs" name = "sqlglotrs"
version = "0.3.14" version = "0.4.0"
dependencies = [ dependencies = [
"criterion", "criterion",
"pyo3", "pyo3",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "sqlglotrs" name = "sqlglotrs"
version = "0.3.14" version = "0.4.0"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"

View file

@ -142,7 +142,7 @@ impl<'a> TokenizerState<'a> {
break; break;
} }
if !self.settings.white_space.contains_key(&self.current_char) { if !self.current_char.is_whitespace() {
if self.current_char.is_ascii_digit() { if self.current_char.is_ascii_digit() {
self.scan_number()?; self.scan_number()?;
} else if let Some(identifier_end) = } else if let Some(identifier_end) =
@ -575,9 +575,12 @@ impl<'a> TokenizerState<'a> {
) -> Result<(), TokenizerError> { ) -> Result<(), TokenizerError> {
self.advance(1)?; self.advance(1)?;
let value = self.extract_value()?[2..].to_string(); let value = self.extract_value()?[2..].to_string();
match u64::from_str_radix(&value, radix) {
Ok(_) => self.add(radix_token_type, Some(value)), // Validate if the string consists only of valid hex digits
Err(_) => self.add(self.token_types.identifier, None), if value.chars().all(|c| c.is_digit(radix)) {
self.add(radix_token_type, Some(value))
} else {
self.add(self.token_types.identifier, None)
} }
} }

View file

@ -865,6 +865,7 @@ LANGUAGE js AS
"presto": "SHA256(x)", "presto": "SHA256(x)",
"trino": "SHA256(x)", "trino": "SHA256(x)",
"postgres": "SHA256(x)", "postgres": "SHA256(x)",
"duckdb": "SHA256(x)",
}, },
write={ write={
"bigquery": "SHA256(x)", "bigquery": "SHA256(x)",
@ -875,6 +876,7 @@ LANGUAGE js AS
"redshift": "SHA2(x, 256)", "redshift": "SHA2(x, 256)",
"trino": "SHA256(x)", "trino": "SHA256(x)",
"duckdb": "SHA256(x)", "duckdb": "SHA256(x)",
"snowflake": "SHA2(x, 256)",
}, },
) )
self.validate_all( self.validate_all(

View file

@ -29,6 +29,10 @@ class TestClickhouse(Validator):
self.assertEqual(expr.sql(dialect="clickhouse"), "COUNT(x)") self.assertEqual(expr.sql(dialect="clickhouse"), "COUNT(x)")
self.assertIsNone(expr._meta) self.assertIsNone(expr._meta)
self.validate_identity("SELECT 1 OR (1 = 2)")
self.validate_identity("SELECT 1 AND (1 = 2)")
self.validate_identity("SELECT json.a.:Int64")
self.validate_identity("SELECT json.a.:JSON.b.:Int64")
self.validate_identity("WITH arrayJoin([(1, [2, 3])]) AS arr SELECT arr") self.validate_identity("WITH arrayJoin([(1, [2, 3])]) AS arr SELECT arr")
self.validate_identity("CAST(1 AS Bool)") self.validate_identity("CAST(1 AS Bool)")
self.validate_identity("SELECT toString(CHAR(104.1, 101, 108.9, 108.9, 111, 32))") self.validate_identity("SELECT toString(CHAR(104.1, 101, 108.9, 108.9, 111, 32))")
@ -85,6 +89,7 @@ class TestClickhouse(Validator):
self.validate_identity("SELECT exponentialTimeDecayedAvg(60)(a, b)") self.validate_identity("SELECT exponentialTimeDecayedAvg(60)(a, b)")
self.validate_identity("levenshteinDistance(col1, col2)", "editDistance(col1, col2)") self.validate_identity("levenshteinDistance(col1, col2)", "editDistance(col1, col2)")
self.validate_identity("SELECT * FROM foo WHERE x GLOBAL IN (SELECT * FROM bar)") self.validate_identity("SELECT * FROM foo WHERE x GLOBAL IN (SELECT * FROM bar)")
self.validate_identity("SELECT * FROM foo WHERE x GLOBAL NOT IN (SELECT * FROM bar)")
self.validate_identity("POSITION(haystack, needle)") self.validate_identity("POSITION(haystack, needle)")
self.validate_identity("POSITION(haystack, needle, position)") self.validate_identity("POSITION(haystack, needle, position)")
self.validate_identity("CAST(x AS DATETIME)", "CAST(x AS DateTime)") self.validate_identity("CAST(x AS DATETIME)", "CAST(x AS DateTime)")
@ -158,6 +163,21 @@ class TestClickhouse(Validator):
self.validate_identity( self.validate_identity(
"CREATE TABLE t (foo String CODEC(LZ4HC(9), ZSTD, DELTA), size String ALIAS formatReadableSize(size_bytes), INDEX idx1 a TYPE bloom_filter(0.001) GRANULARITY 1, INDEX idx2 a TYPE set(100) GRANULARITY 2, INDEX idx3 a TYPE minmax GRANULARITY 3)" "CREATE TABLE t (foo String CODEC(LZ4HC(9), ZSTD, DELTA), size String ALIAS formatReadableSize(size_bytes), INDEX idx1 a TYPE bloom_filter(0.001) GRANULARITY 1, INDEX idx2 a TYPE set(100) GRANULARITY 2, INDEX idx3 a TYPE minmax GRANULARITY 3)"
) )
self.validate_identity(
"SELECT generate_series FROM generate_series(0, 10) AS g(x)",
)
self.validate_identity(
"SELECT and(1, 2)",
"SELECT 1 AND 2",
)
self.validate_identity(
"SELECT or(1, 2)",
"SELECT 1 OR 2",
)
self.validate_identity(
"SELECT generate_series FROM generate_series(0, 10) AS g",
"SELECT generate_series FROM generate_series(0, 10) AS g(generate_series)",
)
self.validate_identity( self.validate_identity(
"INSERT INTO tab VALUES ({'key1': 1, 'key2': 10}), ({'key1': 2, 'key2': 20}), ({'key1': 3, 'key2': 30})", "INSERT INTO tab VALUES ({'key1': 1, 'key2': 10}), ({'key1': 2, 'key2': 20}), ({'key1': 3, 'key2': 30})",
"INSERT INTO tab VALUES (map('key1', 1, 'key2', 10)), (map('key1', 2, 'key2', 20)), (map('key1', 3, 'key2', 30))", "INSERT INTO tab VALUES (map('key1', 1, 'key2', 10)), (map('key1', 2, 'key2', 20)), (map('key1', 3, 'key2', 30))",
@ -179,6 +199,13 @@ class TestClickhouse(Validator):
"SELECT SUM(1) AS impressions FROM (SELECT ['Istanbul', 'Berlin', 'Bobruisk'] AS cities) WHERE arrayJoin(cities) IN ('Istanbul', 'Berlin')", "SELECT SUM(1) AS impressions FROM (SELECT ['Istanbul', 'Berlin', 'Bobruisk'] AS cities) WHERE arrayJoin(cities) IN ('Istanbul', 'Berlin')",
) )
self.validate_all(
"SELECT CAST(STR_TO_DATE(SUBSTRING(a.eta, 1, 10), '%Y-%m-%d') AS Nullable(DATE))",
read={
"clickhouse": "SELECT CAST(STR_TO_DATE(SUBSTRING(a.eta, 1, 10), '%Y-%m-%d') AS Nullable(DATE))",
"oracle": "SELECT to_date(substr(a.eta, 1,10), 'YYYY-MM-DD')",
},
)
self.validate_all( self.validate_all(
"CHAR(67) || CHAR(65) || CHAR(84)", "CHAR(67) || CHAR(65) || CHAR(84)",
read={ read={
@ -201,13 +228,13 @@ class TestClickhouse(Validator):
}, },
) )
self.validate_all( self.validate_all(
"SELECT CAST(STR_TO_DATE('05 12 2000', '%d %m %Y') AS DATE)", "SELECT CAST(STR_TO_DATE('05 12 2000', '%d %m %Y') AS Nullable(DATE))",
read={ read={
"clickhouse": "SELECT CAST(STR_TO_DATE('05 12 2000', '%d %m %Y') AS DATE)", "clickhouse": "SELECT CAST(STR_TO_DATE('05 12 2000', '%d %m %Y') AS Nullable(DATE))",
"postgres": "SELECT TO_DATE('05 12 2000', 'DD MM YYYY')", "postgres": "SELECT TO_DATE('05 12 2000', 'DD MM YYYY')",
}, },
write={ write={
"clickhouse": "SELECT CAST(STR_TO_DATE('05 12 2000', '%d %m %Y') AS DATE)", "clickhouse": "SELECT CAST(STR_TO_DATE('05 12 2000', '%d %m %Y') AS Nullable(DATE))",
"postgres": "SELECT CAST(CAST(TO_DATE('05 12 2000', 'DD MM YYYY') AS TIMESTAMP) AS DATE)", "postgres": "SELECT CAST(CAST(TO_DATE('05 12 2000', 'DD MM YYYY') AS TIMESTAMP) AS DATE)",
}, },
) )
@ -226,9 +253,9 @@ class TestClickhouse(Validator):
}, },
) )
self.validate_all( self.validate_all(
"SELECT a, b FROM (SELECT * FROM x) AS t", "SELECT a, b FROM (SELECT * FROM x) AS t(a, b)",
read={ read={
"clickhouse": "SELECT a, b FROM (SELECT * FROM x) AS t", "clickhouse": "SELECT a, b FROM (SELECT * FROM x) AS t(a, b)",
"duckdb": "SELECT a, b FROM (SELECT * FROM x) AS t(a, b)", "duckdb": "SELECT a, b FROM (SELECT * FROM x) AS t(a, b)",
}, },
) )
@ -557,6 +584,7 @@ class TestClickhouse(Validator):
self.validate_identity( self.validate_identity(
"SELECT COUNT(1) FROM table SETTINGS additional_table_filters = {'a': 'b', 'c': 'd'}" "SELECT COUNT(1) FROM table SETTINGS additional_table_filters = {'a': 'b', 'c': 'd'}"
) )
self.validate_identity("SELECT arrayConcat([1, 2], [3, 4])")
def test_clickhouse_values(self): def test_clickhouse_values(self):
values = exp.select("*").from_( values = exp.select("*").from_(
@ -682,6 +710,33 @@ class TestClickhouse(Validator):
with self.subTest(f"Casting to ClickHouse {data_type}"): with self.subTest(f"Casting to ClickHouse {data_type}"):
self.validate_identity(f"SELECT CAST(val AS {data_type})") self.validate_identity(f"SELECT CAST(val AS {data_type})")
def test_aggregate_function_column_with_any_keyword(self):
# Regression test for https://github.com/tobymao/sqlglot/issues/4723
self.validate_all(
"""
CREATE TABLE my_db.my_table
(
someId UUID,
aggregatedColumn AggregateFunction(any, String),
aggregatedColumnWithParams AggregateFunction(any(somecolumn), String),
)
ENGINE = AggregatingMergeTree()
ORDER BY (someId)
""",
write={
"clickhouse": """CREATE TABLE my_db.my_table (
someId UUID,
aggregatedColumn AggregateFunction(any, String),
aggregatedColumnWithParams AggregateFunction(any(somecolumn), String)
)
ENGINE=AggregatingMergeTree()
ORDER BY (
someId
)""",
},
pretty=True,
)
def test_ddl(self): def test_ddl(self):
db_table_expr = exp.Table(this=None, db=exp.to_identifier("foo"), catalog=None) db_table_expr = exp.Table(this=None, db=exp.to_identifier("foo"), catalog=None)
create_with_cluster = exp.Create( create_with_cluster = exp.Create(
@ -1061,13 +1116,15 @@ LIFETIME(MIN 0 MAX 0)""",
CREATE TABLE t ( CREATE TABLE t (
a AggregateFunction(quantiles(0.5, 0.9), UInt64), a AggregateFunction(quantiles(0.5, 0.9), UInt64),
b AggregateFunction(quantiles, UInt64), b AggregateFunction(quantiles, UInt64),
c SimpleAggregateFunction(sum, Float64) c SimpleAggregateFunction(sum, Float64),
d AggregateFunction(count)
)""", )""",
write={ write={
"clickhouse": """CREATE TABLE t ( "clickhouse": """CREATE TABLE t (
a AggregateFunction(quantiles(0.5, 0.9), UInt64), a AggregateFunction(quantiles(0.5, 0.9), UInt64),
b AggregateFunction(quantiles, UInt64), b AggregateFunction(quantiles, UInt64),
c SimpleAggregateFunction(sum, Float64) c SimpleAggregateFunction(sum, Float64),
d AggregateFunction(count)
)""" )"""
}, },
pretty=True, pretty=True,

View file

@ -168,6 +168,18 @@ class TestDialect(Validator):
self.assertFalse(snowflake_class in {"bigquery", "redshift"}) self.assertFalse(snowflake_class in {"bigquery", "redshift"})
self.assertFalse(snowflake_object in {"bigquery", "redshift"}) self.assertFalse(snowflake_object in {"bigquery", "redshift"})
def test_compare_dialect_versions(self):
ddb_v1 = Dialect.get_or_raise("duckdb, version=1.0")
ddb_v1_2 = Dialect.get_or_raise("duckdb, foo=bar, version=1.0")
ddb_v2 = Dialect.get_or_raise("duckdb, version=2.2.4")
ddb_latest = Dialect.get_or_raise("duckdb")
self.assertTrue(ddb_latest.version > ddb_v2.version)
self.assertTrue(ddb_v1.version < ddb_v2.version)
self.assertTrue(ddb_v1.version == ddb_v1_2.version)
self.assertTrue(ddb_latest.version == Dialect.get_or_raise("duckdb").version)
def test_cast(self): def test_cast(self):
self.validate_all( self.validate_all(
"CAST(a AS TEXT)", "CAST(a AS TEXT)",
@ -3015,7 +3027,7 @@ FROM subquery2""",
"databricks": "SELECT * FROM EXPLODE(SEQUENCE(CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE), INTERVAL '1' WEEK))", "databricks": "SELECT * FROM EXPLODE(SEQUENCE(CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE), INTERVAL '1' WEEK))",
"duckdb": "SELECT * FROM UNNEST(CAST(GENERATE_SERIES(CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE), (7 * INTERVAL '1' DAY)) AS DATE[]))", "duckdb": "SELECT * FROM UNNEST(CAST(GENERATE_SERIES(CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE), (7 * INTERVAL '1' DAY)) AS DATE[]))",
"mysql": "WITH RECURSIVE _generated_dates(date_value) AS (SELECT CAST('2020-01-01' AS DATE) AS date_value UNION ALL SELECT CAST(DATE_ADD(date_value, INTERVAL 1 WEEK) AS DATE) FROM _generated_dates WHERE CAST(DATE_ADD(date_value, INTERVAL 1 WEEK) AS DATE) <= CAST('2020-02-01' AS DATE)) SELECT * FROM (SELECT date_value FROM _generated_dates) AS _generated_dates", "mysql": "WITH RECURSIVE _generated_dates(date_value) AS (SELECT CAST('2020-01-01' AS DATE) AS date_value UNION ALL SELECT CAST(DATE_ADD(date_value, INTERVAL 1 WEEK) AS DATE) FROM _generated_dates WHERE CAST(DATE_ADD(date_value, INTERVAL 1 WEEK) AS DATE) <= CAST('2020-02-01' AS DATE)) SELECT * FROM (SELECT date_value FROM _generated_dates) AS _generated_dates",
"postgres": "SELECT * FROM (SELECT CAST(value AS DATE) FROM GENERATE_SERIES(CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE), INTERVAL '1 WEEK') AS value) AS _unnested_generate_series", "postgres": "SELECT * FROM (SELECT CAST(value AS DATE) FROM GENERATE_SERIES(CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE), INTERVAL '1 WEEK') AS _t(value)) AS _unnested_generate_series",
"presto": "SELECT * FROM UNNEST(SEQUENCE(CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE), (1 * INTERVAL '7' DAY)))", "presto": "SELECT * FROM UNNEST(SEQUENCE(CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE), (1 * INTERVAL '7' DAY)))",
"redshift": "WITH RECURSIVE _generated_dates(date_value) AS (SELECT CAST('2020-01-01' AS DATE) AS date_value UNION ALL SELECT CAST(DATEADD(WEEK, 1, date_value) AS DATE) FROM _generated_dates WHERE CAST(DATEADD(WEEK, 1, date_value) AS DATE) <= CAST('2020-02-01' AS DATE)) SELECT * FROM (SELECT date_value FROM _generated_dates) AS _generated_dates", "redshift": "WITH RECURSIVE _generated_dates(date_value) AS (SELECT CAST('2020-01-01' AS DATE) AS date_value UNION ALL SELECT CAST(DATEADD(WEEK, 1, date_value) AS DATE) FROM _generated_dates WHERE CAST(DATEADD(WEEK, 1, date_value) AS DATE) <= CAST('2020-02-01' AS DATE)) SELECT * FROM (SELECT date_value FROM _generated_dates) AS _generated_dates",
"snowflake": "SELECT * FROM (SELECT DATEADD(WEEK, CAST(value AS INT), CAST('2020-01-01' AS DATE)) AS value FROM TABLE(FLATTEN(INPUT => ARRAY_GENERATE_RANGE(0, (DATEDIFF(WEEK, CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE)) + 1 - 1) + 1))) AS _u(seq, key, path, index, value, this))", "snowflake": "SELECT * FROM (SELECT DATEADD(WEEK, CAST(value AS INT), CAST('2020-01-01' AS DATE)) AS value FROM TABLE(FLATTEN(INPUT => ARRAY_GENERATE_RANGE(0, (DATEDIFF(WEEK, CAST('2020-01-01' AS DATE), CAST('2020-02-01' AS DATE)) + 1 - 1) + 1))) AS _u(seq, key, path, index, value, this))",
@ -3335,3 +3347,26 @@ FROM subquery2""",
"tsql": "SCHEMA_NAME()", "tsql": "SCHEMA_NAME()",
}, },
) )
def test_integer_hex_strings(self):
# Hex strings such as 0xCC represent INTEGER values in the read dialects
integer_dialects = ("bigquery", "clickhouse")
for read_dialect in integer_dialects:
for write_dialect in (
"",
"duckdb",
"databricks",
"snowflake",
"spark",
"redshift",
):
with self.subTest(f"Testing hex string -> INTEGER evaluation for {read_dialect}"):
self.assertEqual(
parse_one("SELECT 0xCC", read=read_dialect).sql(write_dialect), "SELECT 204"
)
for other_integer_dialects in integer_dialects:
self.assertEqual(
parse_one("SELECT 0xCC", read=read_dialect).sql(other_integer_dialects),
"SELECT 0xCC",
)

View file

@ -314,6 +314,10 @@ class TestDuckDB(Validator):
self.validate_identity( self.validate_identity(
"""SELECT '{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }' ->> ['$.family', '$.species']""", """SELECT '{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }' ->> ['$.family', '$.species']""",
) )
self.validate_identity(
"SELECT 20_000 AS literal",
"SELECT 20000 AS literal",
)
self.validate_identity( self.validate_identity(
"""SELECT JSON_EXTRACT_STRING('{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }', ['$.family', '$.species'])""", """SELECT JSON_EXTRACT_STRING('{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }', ['$.family', '$.species'])""",
"""SELECT '{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }' ->> ['$.family', '$.species']""", """SELECT '{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }' ->> ['$.family', '$.species']""",
@ -403,6 +407,14 @@ class TestDuckDB(Validator):
self.validate_all("0x1010", write={"": "0 AS x1010"}) self.validate_all("0x1010", write={"": "0 AS x1010"})
self.validate_all("x ~ y", write={"duckdb": "REGEXP_MATCHES(x, y)"}) self.validate_all("x ~ y", write={"duckdb": "REGEXP_MATCHES(x, y)"})
self.validate_all("SELECT * FROM 'x.y'", write={"duckdb": 'SELECT * FROM "x.y"'}) self.validate_all("SELECT * FROM 'x.y'", write={"duckdb": 'SELECT * FROM "x.y"'})
self.validate_all(
"COUNT_IF(x)",
write={
"duckdb": "COUNT_IF(x)",
"duckdb, version=1.0": "SUM(CASE WHEN x THEN 1 ELSE 0 END)",
"duckdb, version=1.2": "COUNT_IF(x)",
},
)
self.validate_all( self.validate_all(
"SELECT STRFTIME(CAST('2020-01-01' AS TIMESTAMP), CONCAT('%Y', '%m'))", "SELECT STRFTIME(CAST('2020-01-01' AS TIMESTAMP), CONCAT('%Y', '%m'))",
write={ write={
@ -410,6 +422,13 @@ class TestDuckDB(Validator):
"tsql": "SELECT FORMAT(CAST('2020-01-01' AS DATETIME2), CONCAT('yyyy', 'MM'))", "tsql": "SELECT FORMAT(CAST('2020-01-01' AS DATETIME2), CONCAT('yyyy', 'MM'))",
}, },
) )
self.validate_all(
"""SELECT CAST('{"x": 1}' AS JSON)""",
read={
"duckdb": """SELECT '{"x": 1}'::JSON""",
"postgres": """SELECT '{"x": 1}'::JSONB""",
},
)
self.validate_all( self.validate_all(
"SELECT * FROM produce PIVOT(SUM(sales) FOR quarter IN ('Q1', 'Q2'))", "SELECT * FROM produce PIVOT(SUM(sales) FOR quarter IN ('Q1', 'Q2'))",
read={ read={
@ -910,6 +929,10 @@ class TestDuckDB(Validator):
"postgres": "SELECT 'ThOmAs' ~* 'thomas'", "postgres": "SELECT 'ThOmAs' ~* 'thomas'",
}, },
) )
self.validate_identity(
"SELECT DATE_ADD(CAST('2020-01-01' AS DATE), INTERVAL 1 DAY)",
"SELECT CAST('2020-01-01' AS DATE) + INTERVAL '1' DAY",
)
def test_array_index(self): def test_array_index(self):
with self.assertLogs(helper_logger) as cm: with self.assertLogs(helper_logger) as cm:
@ -929,15 +952,15 @@ class TestDuckDB(Validator):
) )
self.validate_identity( self.validate_identity(
"""SELECT LIST_VALUE(1)[i]""", """SELECT LIST_VALUE(1)[i]""",
"""SELECT ([1])[i]""", """SELECT [1][i]""",
) )
self.validate_identity( self.validate_identity(
"""{'x': LIST_VALUE(1)[i]}""", """{'x': LIST_VALUE(1)[i]}""",
"""{'x': ([1])[i]}""", """{'x': [1][i]}""",
) )
self.validate_identity( self.validate_identity(
"""SELECT LIST_APPLY(RANGE(1, 4), i -> {'f1': LIST_VALUE(1, 2, 3)[i], 'f2': LIST_VALUE(1, 2, 3)[i]})""", """SELECT LIST_APPLY(RANGE(1, 4), i -> {'f1': LIST_VALUE(1, 2, 3)[i], 'f2': LIST_VALUE(1, 2, 3)[i]})""",
"""SELECT LIST_APPLY(RANGE(1, 4), i -> {'f1': ([1, 2, 3])[i], 'f2': ([1, 2, 3])[i]})""", """SELECT LIST_APPLY(RANGE(1, 4), i -> {'f1': [1, 2, 3][i], 'f2': [1, 2, 3][i]})""",
) )
self.assertEqual( self.assertEqual(

View file

@ -1,3 +1,4 @@
from sqlglot import exp
from tests.dialects.test_dialect import Validator from tests.dialects.test_dialect import Validator
@ -8,16 +9,28 @@ class TestDune(Validator):
self.validate_identity("CAST(x AS INT256)") self.validate_identity("CAST(x AS INT256)")
self.validate_identity("CAST(x AS UINT256)") self.validate_identity("CAST(x AS UINT256)")
for hex_literal in (
"deadbeef",
"deadbeefdead",
"deadbeefdeadbeef",
"deadbeefdeadbeefde",
"deadbeefdeadbeefdead",
"deadbeefdeadbeefdeadbeef",
"deadbeefdeadbeefdeadbeefdeadbeef",
):
with self.subTest(f"Transpiling hex literal {hex_literal}"):
self.parse_one(f"0x{hex_literal}").assert_is(exp.HexString)
self.validate_all( self.validate_all(
"SELECT 0xdeadbeef", f"SELECT 0x{hex_literal}",
read={ read={
"dune": "SELECT X'deadbeef'", "dune": f"SELECT X'{hex_literal}'",
"postgres": "SELECT x'deadbeef'", "postgres": f"SELECT x'{hex_literal}'",
"trino": "SELECT X'deadbeef'", "trino": f"SELECT X'{hex_literal}'",
}, },
write={ write={
"dune": "SELECT 0xdeadbeef", "dune": f"SELECT 0x{hex_literal}",
"postgres": "SELECT x'deadbeef'", "postgres": f"SELECT x'{hex_literal}'",
"trino": "SELECT X'deadbeef'", "trino": f"SELECT x'{hex_literal}'",
}, },
) )

View file

@ -14,6 +14,7 @@ class TestMySQL(Validator):
self.validate_identity(f"CREATE TABLE t (id {t} UNSIGNED)") self.validate_identity(f"CREATE TABLE t (id {t} UNSIGNED)")
self.validate_identity(f"CREATE TABLE t (id {t}(10) UNSIGNED)") self.validate_identity(f"CREATE TABLE t (id {t}(10) UNSIGNED)")
self.validate_identity("CREATE TABLE bar (abacate DOUBLE(10, 2) UNSIGNED)")
self.validate_identity("CREATE TABLE t (id DECIMAL(20, 4) UNSIGNED)") self.validate_identity("CREATE TABLE t (id DECIMAL(20, 4) UNSIGNED)")
self.validate_identity("CREATE TABLE foo (a BIGINT, UNIQUE (b) USING BTREE)") self.validate_identity("CREATE TABLE foo (a BIGINT, UNIQUE (b) USING BTREE)")
self.validate_identity("CREATE TABLE foo (id BIGINT)") self.validate_identity("CREATE TABLE foo (id BIGINT)")
@ -149,6 +150,10 @@ class TestMySQL(Validator):
"sqlite": "CREATE TABLE x (id INTEGER NOT NULL AUTOINCREMENT PRIMARY KEY)", "sqlite": "CREATE TABLE x (id INTEGER NOT NULL AUTOINCREMENT PRIMARY KEY)",
}, },
) )
self.validate_identity("ALTER TABLE t ALTER INDEX i INVISIBLE")
self.validate_identity("ALTER TABLE t ALTER INDEX i VISIBLE")
self.validate_identity("ALTER TABLE t ALTER COLUMN c SET INVISIBLE")
self.validate_identity("ALTER TABLE t ALTER COLUMN c SET VISIBLE")
def test_identity(self): def test_identity(self):
self.validate_identity("SELECT HIGH_PRIORITY STRAIGHT_JOIN SQL_CALC_FOUND_ROWS * FROM t") self.validate_identity("SELECT HIGH_PRIORITY STRAIGHT_JOIN SQL_CALC_FOUND_ROWS * FROM t")
@ -385,16 +390,16 @@ class TestMySQL(Validator):
def test_hexadecimal_literal(self): def test_hexadecimal_literal(self):
write_CC = { write_CC = {
"bigquery": "SELECT 0xCC", "bigquery": "SELECT FROM_HEX('CC')",
"clickhouse": "SELECT 0xCC", "clickhouse": UnsupportedError,
"databricks": "SELECT X'CC'", "databricks": "SELECT X'CC'",
"drill": "SELECT 204", "drill": "SELECT 204",
"duckdb": "SELECT 204", "duckdb": "SELECT FROM_HEX('CC')",
"hive": "SELECT 204", "hive": "SELECT 204",
"mysql": "SELECT x'CC'", "mysql": "SELECT x'CC'",
"oracle": "SELECT 204", "oracle": "SELECT 204",
"postgres": "SELECT x'CC'", "postgres": "SELECT x'CC'",
"presto": "SELECT 204", "presto": "SELECT x'CC'",
"redshift": "SELECT 204", "redshift": "SELECT 204",
"snowflake": "SELECT x'CC'", "snowflake": "SELECT x'CC'",
"spark": "SELECT X'CC'", "spark": "SELECT X'CC'",
@ -402,20 +407,20 @@ class TestMySQL(Validator):
"starrocks": "SELECT x'CC'", "starrocks": "SELECT x'CC'",
"tableau": "SELECT 204", "tableau": "SELECT 204",
"teradata": "SELECT X'CC'", "teradata": "SELECT X'CC'",
"trino": "SELECT X'CC'", "trino": "SELECT x'CC'",
"tsql": "SELECT 0xCC", "tsql": "SELECT 0xCC",
} }
write_CC_with_leading_zeros = { write_CC_with_leading_zeros = {
"bigquery": "SELECT 0x0000CC", "bigquery": "SELECT FROM_HEX('0000CC')",
"clickhouse": "SELECT 0x0000CC", "clickhouse": UnsupportedError,
"databricks": "SELECT X'0000CC'", "databricks": "SELECT X'0000CC'",
"drill": "SELECT 204", "drill": "SELECT 204",
"duckdb": "SELECT 204", "duckdb": "SELECT FROM_HEX('0000CC')",
"hive": "SELECT 204", "hive": "SELECT 204",
"mysql": "SELECT x'0000CC'", "mysql": "SELECT x'0000CC'",
"oracle": "SELECT 204", "oracle": "SELECT 204",
"postgres": "SELECT x'0000CC'", "postgres": "SELECT x'0000CC'",
"presto": "SELECT 204", "presto": "SELECT x'0000CC'",
"redshift": "SELECT 204", "redshift": "SELECT 204",
"snowflake": "SELECT x'0000CC'", "snowflake": "SELECT x'0000CC'",
"spark": "SELECT X'0000CC'", "spark": "SELECT X'0000CC'",
@ -423,7 +428,7 @@ class TestMySQL(Validator):
"starrocks": "SELECT x'0000CC'", "starrocks": "SELECT x'0000CC'",
"tableau": "SELECT 204", "tableau": "SELECT 204",
"teradata": "SELECT X'0000CC'", "teradata": "SELECT X'0000CC'",
"trino": "SELECT X'0000CC'", "trino": "SELECT x'0000CC'",
"tsql": "SELECT 0x0000CC", "tsql": "SELECT 0x0000CC",
} }
@ -728,6 +733,13 @@ class TestMySQL(Validator):
}, },
) )
self.validate_all(
"CURDATE()",
write={
"mysql": "CURRENT_DATE",
"postgres": "CURRENT_DATE",
},
)
self.validate_all( self.validate_all(
"SELECT CONCAT('11', '22')", "SELECT CONCAT('11', '22')",
read={ read={

View file

@ -117,6 +117,13 @@ class TestOracle(Validator):
"SELECT * FROM t START WITH col CONNECT BY NOCYCLE PRIOR col1 = col2" "SELECT * FROM t START WITH col CONNECT BY NOCYCLE PRIOR col1 = col2"
) )
self.validate_all(
"SELECT TRIM('|' FROM '||Hello ||| world||')",
write={
"clickhouse": "SELECT TRIM(BOTH '|' FROM '||Hello ||| world||')",
"oracle": "SELECT TRIM('|' FROM '||Hello ||| world||')",
},
)
self.validate_all( self.validate_all(
"SELECT department_id, department_name INTO v_department_id, v_department_name FROM departments FETCH FIRST 1 ROWS ONLY", "SELECT department_id, department_name INTO v_department_id, v_department_name FROM departments FETCH FIRST 1 ROWS ONLY",
write={ write={

View file

@ -1358,3 +1358,13 @@ CROSS JOIN JSON_ARRAY_ELEMENTS(CAST(JSON_EXTRACT_PATH(tbox, 'boxes') AS JSON)) A
self.validate_identity("ANALYZE TBL(col1, col2)") self.validate_identity("ANALYZE TBL(col1, col2)")
self.validate_identity("ANALYZE VERBOSE SKIP_LOCKED TBL(col1, col2)") self.validate_identity("ANALYZE VERBOSE SKIP_LOCKED TBL(col1, col2)")
self.validate_identity("ANALYZE BUFFER_USAGE_LIMIT 1337 TBL") self.validate_identity("ANALYZE BUFFER_USAGE_LIMIT 1337 TBL")
def test_recursive_cte(self):
for kind in ("BREADTH", "DEPTH"):
self.validate_identity(
f"WITH RECURSIVE search_tree(id, link, data) AS (SELECT t.id, t.link, t.data FROM tree AS t UNION ALL SELECT t.id, t.link, t.data FROM tree AS t, search_tree AS st WHERE t.id = st.link) SEARCH {kind} FIRST BY id SET ordercol SELECT * FROM search_tree ORDER BY ordercol"
)
self.validate_identity(
"WITH RECURSIVE search_graph(id, link, data, depth) AS (SELECT g.id, g.link, g.data, 1 FROM graph AS g UNION ALL SELECT g.id, g.link, g.data, sg.depth + 1 FROM graph AS g, search_graph AS sg WHERE g.id = sg.link) CYCLE id SET is_cycle USING path SELECT * FROM search_graph"
)

View file

@ -1427,18 +1427,10 @@ class TestSnowflake(Validator):
"CREATE TABLE t (id INT TAG (key1='value_1', key2='value_2'))", "CREATE TABLE t (id INT TAG (key1='value_1', key2='value_2'))",
) )
self.validate_identity("USE SECONDARY ROLES ALL")
self.validate_identity("USE SECONDARY ROLES NONE")
self.validate_identity("USE SECONDARY ROLES a, b, c")
self.validate_identity("CREATE SECURE VIEW table1 AS (SELECT a FROM table2)") self.validate_identity("CREATE SECURE VIEW table1 AS (SELECT a FROM table2)")
self.validate_identity(
"""create external table et2(
col1 date as (parse_json(metadata$external_table_partition):COL1::date),
col2 varchar as (parse_json(metadata$external_table_partition):COL2::varchar),
col3 number as (parse_json(metadata$external_table_partition):COL3::number))
partition by (col1,col2,col3)
location=@s2/logs/
partition_type = user_specified
file_format = (type = parquet)""",
"CREATE EXTERNAL TABLE et2 (col1 DATE AS (CAST(GET_PATH(PARSE_JSON(metadata$external_table_partition), 'COL1') AS DATE)), col2 VARCHAR AS (CAST(GET_PATH(PARSE_JSON(metadata$external_table_partition), 'COL2') AS VARCHAR)), col3 DECIMAL(38, 0) AS (CAST(GET_PATH(PARSE_JSON(metadata$external_table_partition), 'COL3') AS DECIMAL(38, 0)))) LOCATION @s2/logs/ PARTITION BY (col1, col2, col3) partition_type=user_specified file_format=(type = parquet)",
)
self.validate_identity("CREATE OR REPLACE VIEW foo (uid) COPY GRANTS AS (SELECT 1)") self.validate_identity("CREATE OR REPLACE VIEW foo (uid) COPY GRANTS AS (SELECT 1)")
self.validate_identity("CREATE TABLE geospatial_table (id INT, g GEOGRAPHY)") self.validate_identity("CREATE TABLE geospatial_table (id INT, g GEOGRAPHY)")
self.validate_identity("CREATE MATERIALIZED VIEW a COMMENT='...' AS SELECT 1 FROM x") self.validate_identity("CREATE MATERIALIZED VIEW a COMMENT='...' AS SELECT 1 FROM x")
@ -1504,6 +1496,17 @@ class TestSnowflake(Validator):
"CREATE SEQUENCE seq1 WITH START=1 INCREMENT=1 ORDER", "CREATE SEQUENCE seq1 WITH START=1 INCREMENT=1 ORDER",
"CREATE SEQUENCE seq1 START=1 INCREMENT=1 ORDER", "CREATE SEQUENCE seq1 START=1 INCREMENT=1 ORDER",
) )
self.validate_identity(
"""create external table et2(
col1 date as (parse_json(metadata$external_table_partition):COL1::date),
col2 varchar as (parse_json(metadata$external_table_partition):COL2::varchar),
col3 number as (parse_json(metadata$external_table_partition):COL3::number))
partition by (col1,col2,col3)
location=@s2/logs/
partition_type = user_specified
file_format = (type = parquet)""",
"CREATE EXTERNAL TABLE et2 (col1 DATE AS (CAST(GET_PATH(PARSE_JSON(metadata$external_table_partition), 'COL1') AS DATE)), col2 VARCHAR AS (CAST(GET_PATH(PARSE_JSON(metadata$external_table_partition), 'COL2') AS VARCHAR)), col3 DECIMAL(38, 0) AS (CAST(GET_PATH(PARSE_JSON(metadata$external_table_partition), 'COL3') AS DECIMAL(38, 0)))) LOCATION @s2/logs/ PARTITION BY (col1, col2, col3) partition_type=user_specified file_format=(type = parquet)",
)
self.validate_all( self.validate_all(
"CREATE TABLE orders_clone CLONE orders", "CREATE TABLE orders_clone CLONE orders",
@ -2062,6 +2065,40 @@ MATCH_RECOGNIZE (
self.validate_identity("SHOW TERSE USERS") self.validate_identity("SHOW TERSE USERS")
self.validate_identity("SHOW USERS LIKE '_foo%' STARTS WITH 'bar' LIMIT 5 FROM 'baz'") self.validate_identity("SHOW USERS LIKE '_foo%' STARTS WITH 'bar' LIMIT 5 FROM 'baz'")
def test_show_databases(self):
self.validate_identity("SHOW TERSE DATABASES")
self.validate_identity(
"SHOW TERSE DATABASES HISTORY LIKE 'foo' STARTS WITH 'bla' LIMIT 5 FROM 'bob' WITH PRIVILEGES USAGE, MODIFY"
)
ast = parse_one("SHOW DATABASES IN ACCOUNT", read="snowflake")
self.assertEqual(ast.this, "DATABASES")
self.assertEqual(ast.args.get("scope_kind"), "ACCOUNT")
def test_show_functions(self):
self.validate_identity("SHOW FUNCTIONS")
self.validate_identity("SHOW FUNCTIONS LIKE 'foo' IN CLASS bla")
ast = parse_one("SHOW FUNCTIONS IN ACCOUNT", read="snowflake")
self.assertEqual(ast.this, "FUNCTIONS")
self.assertEqual(ast.args.get("scope_kind"), "ACCOUNT")
def test_show_procedures(self):
self.validate_identity("SHOW PROCEDURES")
self.validate_identity("SHOW PROCEDURES LIKE 'foo' IN APPLICATION app")
self.validate_identity("SHOW PROCEDURES LIKE 'foo' IN APPLICATION PACKAGE pkg")
ast = parse_one("SHOW PROCEDURES IN ACCOUNT", read="snowflake")
self.assertEqual(ast.this, "PROCEDURES")
self.assertEqual(ast.args.get("scope_kind"), "ACCOUNT")
def test_show_warehouses(self):
self.validate_identity("SHOW WAREHOUSES")
self.validate_identity("SHOW WAREHOUSES LIKE 'foo' WITH PRIVILEGES USAGE, MODIFY")
ast = parse_one("SHOW WAREHOUSES", read="snowflake")
self.assertEqual(ast.this, "WAREHOUSES")
def test_show_schemas(self): def test_show_schemas(self):
self.validate_identity( self.validate_identity(
"show terse schemas in database db1 starts with 'a' limit 10 from 'b'", "show terse schemas in database db1 starts with 'a' limit 10 from 'b'",

View file

@ -316,7 +316,8 @@ TBLPROPERTIES (
write={ write={
"databricks": "SELECT TRY_ELEMENT_AT(ARRAY(1, 2, 3), 2)", "databricks": "SELECT TRY_ELEMENT_AT(ARRAY(1, 2, 3), 2)",
"spark": "SELECT TRY_ELEMENT_AT(ARRAY(1, 2, 3), 2)", "spark": "SELECT TRY_ELEMENT_AT(ARRAY(1, 2, 3), 2)",
"duckdb": "SELECT ([1, 2, 3])[2]", "duckdb": "SELECT [1, 2, 3][2]",
"duckdb, version=1.1.0": "SELECT ([1, 2, 3])[2]",
"presto": "SELECT ELEMENT_AT(ARRAY[1, 2, 3], 2)", "presto": "SELECT ELEMENT_AT(ARRAY[1, 2, 3], 2)",
}, },
) )
@ -356,7 +357,8 @@ TBLPROPERTIES (
}, },
write={ write={
"databricks": "SELECT TRY_ELEMENT_AT(MAP(1, 'a', 2, 'b'), 2)", "databricks": "SELECT TRY_ELEMENT_AT(MAP(1, 'a', 2, 'b'), 2)",
"duckdb": "SELECT (MAP([1, 2], ['a', 'b'])[2])[1]", "duckdb": "SELECT MAP([1, 2], ['a', 'b'])[2]",
"duckdb, version=1.1.0": "SELECT (MAP([1, 2], ['a', 'b'])[2])[1]",
"spark": "SELECT TRY_ELEMENT_AT(MAP(1, 'a', 2, 'b'), 2)", "spark": "SELECT TRY_ELEMENT_AT(MAP(1, 'a', 2, 'b'), 2)",
}, },
) )

View file

@ -108,6 +108,7 @@ class TestSQLite(Validator):
"SELECT * FROM station WHERE city IS NOT ''", "SELECT * FROM station WHERE city IS NOT ''",
"SELECT * FROM station WHERE NOT city IS ''", "SELECT * FROM station WHERE NOT city IS ''",
) )
self.validate_identity("SELECT JSON_OBJECT('col1', 1, 'col2', '1')")
def test_strftime(self): def test_strftime(self):
self.validate_identity("SELECT STRFTIME('%Y/%m/%d', 'now')") self.validate_identity("SELECT STRFTIME('%Y/%m/%d', 'now')")

View file

@ -5,6 +5,7 @@ class TestTrino(Validator):
dialect = "trino" dialect = "trino"
def test_trino(self): def test_trino(self):
self.validate_identity("JSON_QUERY(m.properties, 'lax $.area' OMIT QUOTES NULL ON ERROR)")
self.validate_identity("JSON_EXTRACT(content, json_path)") self.validate_identity("JSON_EXTRACT(content, json_path)")
self.validate_identity("JSON_QUERY(content, 'lax $.HY.*')") self.validate_identity("JSON_QUERY(content, 'lax $.HY.*')")
self.validate_identity("JSON_QUERY(content, 'strict $.HY.*' WITH WRAPPER)") self.validate_identity("JSON_QUERY(content, 'strict $.HY.*' WITH WRAPPER)")

View file

@ -1705,6 +1705,8 @@ WHERE
"spark": "SELECT * FROM A LIMIT 3", "spark": "SELECT * FROM A LIMIT 3",
}, },
) )
self.validate_identity("SELECT TOP 10 PERCENT")
self.validate_identity("SELECT TOP 10 PERCENT WITH TIES")
def test_format(self): def test_format(self):
self.validate_identity("SELECT FORMAT(foo, 'dddd', 'de-CH')") self.validate_identity("SELECT FORMAT(foo, 'dddd', 'de-CH')")

View file

@ -315,3 +315,10 @@ STRING;
# dialect: bigquery # dialect: bigquery
STRING(timestamp_expr, timezone); STRING(timestamp_expr, timezone);
STRING; STRING;
--------------------------------------
-- Snowflake
--------------------------------------
LEAST(x::DECIMAL(18, 2));
DECIMAL(18, 2);

View file

@ -259,6 +259,20 @@ WITH T1 AS (SELECT 1 AS C1, 1 AS C2, 'Y' AS TOP_PARENT_INDICATOR, 1 AS ID FROM D
SELECT * FROM ROWS FROM (GENERATE_SERIES(1, 3), GENERATE_SERIES(10, 12)) AS t(a, b); SELECT * FROM ROWS FROM (GENERATE_SERIES(1, 3), GENERATE_SERIES(10, 12)) AS t(a, b);
SELECT t.a AS a, t.b AS b FROM ROWS FROM (GENERATE_SERIES(1, 3), GENERATE_SERIES(10, 12)) AS t(a, b); SELECT t.a AS a, t.b AS b FROM ROWS FROM (GENERATE_SERIES(1, 3), GENERATE_SERIES(10, 12)) AS t(a, b);
# execute: false
# dialect: clickhouse
SELECT generate_series FROM generate_series(0, 10) AS g;
SELECT g.generate_series AS generate_series FROM generate_series(0, 10) AS g(generate_series);
# execute: false
# dialect: snowflake
SELECT * FROM quarterly_sales PIVOT(SUM(amount) FOR quarter IN (ANY ORDER BY quarter)) ORDER BY empid;
SELECT * FROM QUARTERLY_SALES AS QUARTERLY_SALES PIVOT(SUM(QUARTERLY_SALES.AMOUNT) FOR QUARTERLY_SALES.QUARTER IN (ANY ORDER BY QUARTER)) AS _Q_0 ORDER BY _Q_0.EMPID;
# execute: false
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY x) AS x FROM t;
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY t.x) AS x FROM t AS t;
-------------------------------------- --------------------------------------
-- Derived tables -- Derived tables
-------------------------------------- --------------------------------------
@ -752,6 +766,10 @@ WITH RECURSIVE t(c) AS (SELECT 1 AS c UNION ALL SELECT t.c + 1 AS c FROM t AS t
WITH RECURSIVE t AS (SELECT 1 AS c UNION ALL SELECT c + 1 AS c FROM t WHERE c <= 10) SELECT c FROM t; WITH RECURSIVE t AS (SELECT 1 AS c UNION ALL SELECT c + 1 AS c FROM t WHERE c <= 10) SELECT c FROM t;
WITH RECURSIVE t AS (SELECT 1 AS c UNION ALL SELECT t.c + 1 AS c FROM t AS t WHERE t.c <= 10) SELECT t.c AS c FROM t AS t; WITH RECURSIVE t AS (SELECT 1 AS c UNION ALL SELECT t.c + 1 AS c FROM t AS t WHERE t.c <= 10) SELECT t.c AS c FROM t AS t;
# title: expand DISTINCT ON ordinals / projection names
SELECT DISTINCT ON (new_col, b + 1, 1) t1.a AS new_col FROM x AS t1 ORDER BY new_col;
SELECT DISTINCT ON (new_col, t1.b + 1, new_col) t1.a AS new_col FROM x AS t1 ORDER BY new_col;
-------------------------------------- --------------------------------------
-- Wrapped tables / join constructs -- Wrapped tables / join constructs
-------------------------------------- --------------------------------------

View file

@ -240,9 +240,26 @@ class TestDiff(unittest.TestCase):
], ],
) )
with self.assertRaises(ValueError): self._validate_delta_only(
diff_delta_only( diff_delta_only(
expr_src, expr_tgt, matchings=[(expr_src, expr_tgt), (expr_src, expr_tgt)] expr_src, expr_tgt, matchings=[(expr_src, expr_tgt), (expr_src, expr_tgt)]
),
[
Insert(expression=exp.Literal.number(2)),
Insert(expression=exp.Literal.number(3)),
Insert(expression=exp.Literal.number(4)),
],
)
expr_tgt.selects[0].replace(expr_src.selects[0])
self._validate_delta_only(
diff_delta_only(expr_src, expr_tgt, matchings=[(expr_src, expr_tgt)]),
[
Insert(expression=exp.Literal.number(2)),
Insert(expression=exp.Literal.number(3)),
Insert(expression=exp.Literal.number(4)),
],
) )
def test_identifier(self): def test_identifier(self):

View file

@ -216,6 +216,28 @@ class TestOptimizer(unittest.TestCase):
) )
def test_qualify_tables(self): def test_qualify_tables(self):
self.assertEqual(
optimizer.qualify_tables.qualify_tables(
parse_one(
"WITH cte AS (SELECT * FROM t) SELECT * FROM cte PIVOT(SUM(c) FOR v IN ('x', 'y'))"
),
db="db",
catalog="catalog",
).sql(),
"WITH cte AS (SELECT * FROM catalog.db.t AS t) SELECT * FROM cte AS cte PIVOT(SUM(c) FOR v IN ('x', 'y')) AS _q_0",
)
self.assertEqual(
optimizer.qualify_tables.qualify_tables(
parse_one(
"WITH cte AS (SELECT * FROM t) SELECT * FROM cte PIVOT(SUM(c) FOR v IN ('x', 'y')) AS pivot_alias"
),
db="db",
catalog="catalog",
).sql(),
"WITH cte AS (SELECT * FROM catalog.db.t AS t) SELECT * FROM cte AS cte PIVOT(SUM(c) FOR v IN ('x', 'y')) AS pivot_alias",
)
self.assertEqual( self.assertEqual(
optimizer.qualify_tables.qualify_tables( optimizer.qualify_tables.qualify_tables(
parse_one("select a from b"), catalog="catalog" parse_one("select a from b"), catalog="catalog"

View file

@ -1,6 +1,6 @@
import unittest import unittest
from sqlglot import parse_one from sqlglot import parse_one, expressions as exp
from sqlglot.transforms import ( from sqlglot.transforms import (
eliminate_distinct_on, eliminate_distinct_on,
eliminate_join_marks, eliminate_join_marks,
@ -147,7 +147,7 @@ class TestTransforms(unittest.TestCase):
self.validate( self.validate(
eliminate_qualify, eliminate_qualify,
"SELECT x AS z FROM y QUALIFY ROW_NUMBER() OVER (PARTITION BY z)", "SELECT x AS z FROM y QUALIFY ROW_NUMBER() OVER (PARTITION BY z)",
"SELECT z FROM (SELECT x AS z, ROW_NUMBER() OVER (PARTITION BY x) AS _w, x FROM y) AS _t WHERE _w", "SELECT z FROM (SELECT x AS z, ROW_NUMBER() OVER (PARTITION BY x) AS _w FROM y) AS _t WHERE _w",
) )
self.validate( self.validate(
eliminate_qualify, eliminate_qualify,
@ -162,7 +162,12 @@ class TestTransforms(unittest.TestCase):
self.validate( self.validate(
eliminate_qualify, eliminate_qualify,
"SELECT y.x AS x, y.t AS z FROM y QUALIFY ROW_NUMBER() OVER (PARTITION BY x ORDER BY x DESC, z)", "SELECT y.x AS x, y.t AS z FROM y QUALIFY ROW_NUMBER() OVER (PARTITION BY x ORDER BY x DESC, z)",
"SELECT x, z FROM (SELECT y.x AS x, y.t AS z, ROW_NUMBER() OVER (PARTITION BY y.x ORDER BY y.x DESC, y.t) AS _w, y.t FROM y) AS _t WHERE _w", "SELECT x, z FROM (SELECT y.x AS x, y.t AS z, ROW_NUMBER() OVER (PARTITION BY y.x ORDER BY y.x DESC, y.t) AS _w FROM y) AS _t WHERE _w",
)
self.validate(
eliminate_qualify,
"select max(col) over (partition by col_id) as col, from some_table qualify row_number() over (partition by col_id order by col asc)=1",
"SELECT col FROM (SELECT MAX(col) OVER (PARTITION BY col_id) AS col, ROW_NUMBER() OVER (PARTITION BY col_id ORDER BY MAX(col) OVER (PARTITION BY col_id) ASC) AS _w, col_id FROM some_table) AS _t WHERE _w = 1",
) )
def test_remove_precision_parameterized_types(self): def test_remove_precision_parameterized_types(self):
@ -251,3 +256,12 @@ class TestTransforms(unittest.TestCase):
f"SELECT table1.id, table2.cloumn1, table3.id FROM table1 LEFT JOIN table2 ON table1.id = table2.id LEFT JOIN (SELECT tableInner1.id FROM tableInner1 LEFT JOIN tableInner2 ON tableInner1.id = tableInner2.id) {alias}table3 ON table1.id = table3.id", f"SELECT table1.id, table2.cloumn1, table3.id FROM table1 LEFT JOIN table2 ON table1.id = table2.id LEFT JOIN (SELECT tableInner1.id FROM tableInner1 LEFT JOIN tableInner2 ON tableInner1.id = tableInner2.id) {alias}table3 ON table1.id = table3.id",
dialect, dialect,
) )
# if multiple conditions, we check that after transformations the tree remains consistent
s = "select a.id from a, b where a.id = b.id (+) AND b.d (+) = const"
tree = eliminate_join_marks(parse_one(s, dialect=dialect))
assert all(type(t.parent_select) is exp.Select for t in tree.find_all(exp.Table))
assert (
tree.sql(dialect=dialect)
== "SELECT a.id FROM a LEFT JOIN b ON a.id = b.id AND b.d = const"
)

View file

@ -23,6 +23,11 @@ class TestTranspile(unittest.TestCase):
def test_weird_chars(self): def test_weird_chars(self):
self.assertEqual(transpile("0Êß")[0], "0 AS Êß") self.assertEqual(transpile("0Êß")[0], "0 AS Êß")
self.assertEqual(
# Ideographic space after SELECT (\u3000)
transpile("SELECT * FROM t WHERE c = 1")[0],
"SELECT * FROM t WHERE c = 1",
)
def test_alias(self): def test_alias(self):
self.assertEqual(transpile("SELECT SUM(y) KEEP")[0], "SELECT SUM(y) AS KEEP") self.assertEqual(transpile("SELECT SUM(y) KEEP")[0], "SELECT SUM(y) AS KEEP")