1
0
Fork 0

Adding upstream version 25.24.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-13 21:55:04 +01:00
parent cfe8a51f10
commit a0663ae805
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
75 changed files with 43236 additions and 41203 deletions

View file

@ -15,10 +15,13 @@ jobs:
deploy: ${{ steps.check_deploy.outputs.deploy }} deploy: ${{ steps.check_deploy.outputs.deploy }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with:
fetch-depth: 0
- id: check_deploy - id: check_deploy
run: | run: |
bash ./.github/workflows/should_deploy_sqlglotrs.sh bash ./.github/workflows/should_deploy_sqlglotrs.sh \
if [ $? -eq 0 ]; then echo "deploy=true" >> $GITHUB_OUTPUT; fi && echo "deploy=true" >> $GITHUB_OUTPUT \
|| echo "deploy=false" >> $GITHUB_OUTPUT
build-rs: build-rs:
needs: should-deploy-rs needs: should-deploy-rs

View file

@ -1,6 +1,128 @@
Changelog Changelog
========= =========
## [v25.23.2] - 2024-09-25
### :wrench: Chores
- [`eca05d3`](https://github.com/tobymao/sqlglot/commit/eca05d3b08645d7a984ee65b438282b35cb41960) - tweak should_deploy_rs script to avoid marking CI as failed *(commit by [@georgesittas](https://github.com/georgesittas))*
## [v25.23.1] - 2024-09-25
### :wrench: Chores
- [`349b8f8`](https://github.com/tobymao/sqlglot/commit/349b8f81ed69a3708e1afd15816b3b58e2bf8b3f) - fetch all history to allow workflow script to skip sqlglotrs deployments *(PR [#4162](https://github.com/tobymao/sqlglot/pull/4162) by [@georgesittas](https://github.com/georgesittas))*
## [v25.23.0] - 2024-09-25
### :boom: BREAKING CHANGES
- due to [`da51ea5`](https://github.com/tobymao/sqlglot/commit/da51ea5c8f405859d877a25176e8e48ef8b4b112) - refactor exp.Chr *(PR [#4081](https://github.com/tobymao/sqlglot/pull/4081) by [@georgesittas](https://github.com/georgesittas))*:
refactor exp.Chr (#4081)
- due to [`9c527b5`](https://github.com/tobymao/sqlglot/commit/9c527b549cc56db9d8f44579397d9f9fe1440573) - treat Nullable as an arg instead of a DataType.TYPE *(PR [#4094](https://github.com/tobymao/sqlglot/pull/4094) by [@georgesittas](https://github.com/georgesittas))*:
treat Nullable as an arg instead of a DataType.TYPE (#4094)
- due to [`ba015dc`](https://github.com/tobymao/sqlglot/commit/ba015dc1102a4fe0c35cbfe6e3d23dc24263c20f) - add `returning` to merge expression builder *(PR [#4125](https://github.com/tobymao/sqlglot/pull/4125) by [@max-muoto](https://github.com/max-muoto))*:
add `returning` to merge expression builder (#4125)
- due to [`77a514d`](https://github.com/tobymao/sqlglot/commit/77a514dd7cfa9feb847c429411809092e5578bad) - Parse VALUES & query modifiers in wrapped FROM clause *(PR [#4135](https://github.com/tobymao/sqlglot/pull/4135) by [@VaggelisD](https://github.com/VaggelisD))*:
Parse VALUES & query modifiers in wrapped FROM clause (#4135)
### :sparkles: New Features
- [`5771d8d`](https://github.com/tobymao/sqlglot/commit/5771d8da94aff104206f93482e7b248d725f1843) - add merge expression builder *(PR [#4084](https://github.com/tobymao/sqlglot/pull/4084) by [@max-muoto](https://github.com/max-muoto))*
- [`1d52709`](https://github.com/tobymao/sqlglot/commit/1d5270915d14f3f92341d5057b88b58fff6c0d97) - **postgres**: Parse DO NOTHING and RETURNING in MERGE statement *(PR [#4087](https://github.com/tobymao/sqlglot/pull/4087) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *addresses issue [#4083](https://github.com/tobymao/sqlglot/issues/4083) opened by [@max-muoto](https://github.com/max-muoto)*
- [`1615bad`](https://github.com/tobymao/sqlglot/commit/1615bad98eeddc8e67e8002c3b1fe93bd7c3b690) - Add support for UUID function *(PR [#4089](https://github.com/tobymao/sqlglot/pull/4089) by [@VaggelisD](https://github.com/VaggelisD))*
- [`5733600`](https://github.com/tobymao/sqlglot/commit/57336006795d32e9253a9df4813d3029d1d32ef1) - **bigquery**: transpile UUID type to STRING *(PR [#4093](https://github.com/tobymao/sqlglot/pull/4093) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *addresses issue [#4091](https://github.com/tobymao/sqlglot/issues/4091) opened by [@gigatexal](https://github.com/gigatexal)*
- [`75230f5`](https://github.com/tobymao/sqlglot/commit/75230f5970c240add1cff7349fc65fb67541fa34) - **bigquery**: add support for the MERGE ... THEN INSERT ROW syntax *(PR [#4096](https://github.com/tobymao/sqlglot/pull/4096) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *addresses issue [#4095](https://github.com/tobymao/sqlglot/issues/4095) opened by [@ericist](https://github.com/ericist)*
- [`f8d4dc4`](https://github.com/tobymao/sqlglot/commit/f8d4dc4bab90cd369eef090c23b81160a7ae78fc) - **parser**: add support for ALTER INDEX closes [#4105](https://github.com/tobymao/sqlglot/pull/4105) *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`28c6f27`](https://github.com/tobymao/sqlglot/commit/28c6f27291d57d85917c62b387b86a598ee3c1d6) - **duckdb**: Support *COLUMNS() function *(PR [#4106](https://github.com/tobymao/sqlglot/pull/4106) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *addresses issue [#4101](https://github.com/tobymao/sqlglot/issues/4101) opened by [@aersam](https://github.com/aersam)*
- [`3cb0041`](https://github.com/tobymao/sqlglot/commit/3cb00417f45624f012e5ce8ababfe3250e813b80) - **snowflake**: Fix exp.Pivot FOR IN clause *(PR [#4109](https://github.com/tobymao/sqlglot/pull/4109) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *addresses issue [#4108](https://github.com/tobymao/sqlglot/issues/4108) opened by [@kharigardner](https://github.com/kharigardner)*
- [`7ac21a0`](https://github.com/tobymao/sqlglot/commit/7ac21a07c73cdf156ae4dc6a848b9f781b265d16) - **athena**: Improve DDL query support *(PR [#4099](https://github.com/tobymao/sqlglot/pull/4099) by [@erindru](https://github.com/erindru))*
- [`a34f8b6`](https://github.com/tobymao/sqlglot/commit/a34f8b6ff9b0aa8595214da75fe7cbfbc8285476) - **oracle**: support TRUNC without fmt argument fixes [#4116](https://github.com/tobymao/sqlglot/pull/4116) *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`bd8e050`](https://github.com/tobymao/sqlglot/commit/bd8e050e7df905082fd32e26c4ee0c6e2d36c897) - **clickhouse**: support ON CLUSTER clause in DELETE *(PR [#4119](https://github.com/tobymao/sqlglot/pull/4119) by [@treysp](https://github.com/treysp))*
- [`1fac6a9`](https://github.com/tobymao/sqlglot/commit/1fac6a9f46e147a5583042d6f82deffd04cd58c9) - expose sqlglot.expressions.delete as a sqlglot module function *(PR [#4126](https://github.com/tobymao/sqlglot/pull/4126) by [@max-muoto](https://github.com/max-muoto))*
- [`4506b3b`](https://github.com/tobymao/sqlglot/commit/4506b3b58fde8e8fe711df8fd0c9c245a98ca86b) - **duckdb**: add support for the UNION type *(PR [#4128](https://github.com/tobymao/sqlglot/pull/4128) by [@georgesittas](https://github.com/georgesittas))*
- [`ba015dc`](https://github.com/tobymao/sqlglot/commit/ba015dc1102a4fe0c35cbfe6e3d23dc24263c20f) - add `returning` to merge expression builder *(PR [#4125](https://github.com/tobymao/sqlglot/pull/4125) by [@max-muoto](https://github.com/max-muoto))*
- [`3ec96ab`](https://github.com/tobymao/sqlglot/commit/3ec96ab7318dc5fc07802d31c825a95db7f5b303) - **clickhouse**: Add support for APPLY query modifier *(PR [#4141](https://github.com/tobymao/sqlglot/pull/4141) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *addresses issue [#4139](https://github.com/tobymao/sqlglot/issues/4139) opened by [@elchyn-cheliabiyeu](https://github.com/elchyn-cheliabiyeu)*
- [`04ddc54`](https://github.com/tobymao/sqlglot/commit/04ddc543159bc55e2cf8098cd96b2a5c881ebbc6) - **bigquery**: Support RANGE<T> type *(PR [#4148](https://github.com/tobymao/sqlglot/pull/4148) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *addresses issue [#4146](https://github.com/tobymao/sqlglot/issues/4146) opened by [@plaflamme](https://github.com/plaflamme)*
- [`17533ee`](https://github.com/tobymao/sqlglot/commit/17533ee6361c30731a9a14666ac952b44982b69d) - Add support for GRANT DDL *(PR [#4138](https://github.com/tobymao/sqlglot/pull/4138) by [@VaggelisD](https://github.com/VaggelisD))*
- [`1a240ec`](https://github.com/tobymao/sqlglot/commit/1a240ec1cbdaf15abab8df642e189b89de239e84) - Add SUBSTR Support *(PR [#4153](https://github.com/tobymao/sqlglot/pull/4153) by [@mwc360](https://github.com/mwc360))*
### :bug: Bug Fixes
- [`da51ea5`](https://github.com/tobymao/sqlglot/commit/da51ea5c8f405859d877a25176e8e48ef8b4b112) - **parser**: refactor exp.Chr *(PR [#4081](https://github.com/tobymao/sqlglot/pull/4081) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#4080](https://github.com/tobymao/sqlglot/issues/4080) opened by [@EugeneTorap](https://github.com/EugeneTorap)*
- [`6294f9e`](https://github.com/tobymao/sqlglot/commit/6294f9e6d08111c6088f5ed9846e7a64f7724801) - **starrocks**: generate ARRAY_FILTER for exp.ArrayFilter *(PR [#4088](https://github.com/tobymao/sqlglot/pull/4088) by [@gauravsagar483](https://github.com/gauravsagar483))*
- [`1e02c02`](https://github.com/tobymao/sqlglot/commit/1e02c0221ea8445ccb5537b0a77e120c0b2c108c) - **mysql**: convert VARCHAR without size to TEXT for DDLs *(PR [#4092](https://github.com/tobymao/sqlglot/pull/4092) by [@georgesittas](https://github.com/georgesittas))*
- [`cb5bcff`](https://github.com/tobymao/sqlglot/commit/cb5bcfff1f96972e75681bb2411bca8b60a4bff1) - **clickhouse**: generate formatDateTime instead of DATE_FORMAT fixes [#4098](https://github.com/tobymao/sqlglot/pull/4098) *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`b10255e`](https://github.com/tobymao/sqlglot/commit/b10255eb8b6b73bf5084fdf6bffd5a7fa351b1ec) - **snowflake**: Manually escape single quotes in colon operator *(PR [#4104](https://github.com/tobymao/sqlglot/pull/4104) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4090](https://github.com/tobymao/sqlglot/issues/4090) opened by [@jussihe-rec](https://github.com/jussihe-rec)*
- [`67a9ad8`](https://github.com/tobymao/sqlglot/commit/67a9ad89abfce84f78dd1a34caa9dc8143233609) - Move JSON path escape to generation *(PR [#4110](https://github.com/tobymao/sqlglot/pull/4110) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4090](https://github.com/tobymao/sqlglot/issues/4090) opened by [@jussihe-rec](https://github.com/jussihe-rec)*
- [`06c76f7`](https://github.com/tobymao/sqlglot/commit/06c76f7471cdb679a7a7a35064204d94841fd929) - calling interval without unit *(commit by [@tobymao](https://github.com/tobymao))*
- [`66c3295`](https://github.com/tobymao/sqlglot/commit/66c32958a9e46642077813adf90079098e41c87e) - **optimizer**: Enable USING expansion with multiple joins *(PR [#4113](https://github.com/tobymao/sqlglot/pull/4113) by [@dg-hellotwin](https://github.com/dg-hellotwin))*
- :arrow_lower_right: *fixes issue [#4112](https://github.com/tobymao/sqlglot/issues/4112) opened by [@dg-hellotwin](https://github.com/dg-hellotwin)*
- [`21f5bcd`](https://github.com/tobymao/sqlglot/commit/21f5bcd13eb9c567c711cec5879c4d08a052b91c) - parse struct(...)[] type properly *(PR [#4123](https://github.com/tobymao/sqlglot/pull/4123) by [@georgesittas](https://github.com/georgesittas))*
- [`22c456d`](https://github.com/tobymao/sqlglot/commit/22c456d032b457244b397598d4480ae22ad316bd) - Do not generate DISTINCT keyword in FILTER *(PR [#4130](https://github.com/tobymao/sqlglot/pull/4130) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4129](https://github.com/tobymao/sqlglot/issues/4129) opened by [@tekumara](https://github.com/tekumara)*
- [`089b77e`](https://github.com/tobymao/sqlglot/commit/089b77ec7efcd6decbf9a7be500e73dc88ba4dec) - **athena**: DDL fixes *(PR [#4132](https://github.com/tobymao/sqlglot/pull/4132) by [@erindru](https://github.com/erindru))*
- [`e6c9902`](https://github.com/tobymao/sqlglot/commit/e6c990225e2685c617dfd1594c83778036405f6b) - invalid regex *(commit by [@tobymao](https://github.com/tobymao))*
- [`77a514d`](https://github.com/tobymao/sqlglot/commit/77a514dd7cfa9feb847c429411809092e5578bad) - **parser**: Parse VALUES & query modifiers in wrapped FROM clause *(PR [#4135](https://github.com/tobymao/sqlglot/pull/4135) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4133](https://github.com/tobymao/sqlglot/issues/4133) opened by [@danxmoran](https://github.com/danxmoran)*
- [`8822d6c`](https://github.com/tobymao/sqlglot/commit/8822d6c1b3b62cfd76fd481db473bf8ea1c12b1a) - **parser**: handle brackets in column op json extract arrow parser *(PR [#4140](https://github.com/tobymao/sqlglot/pull/4140) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#3151](https://github.com/TobikoData/sqlmesh/issues/3151) opened by [@markgraphene](https://github.com/markgraphene)*
- [`be0a4a8`](https://github.com/tobymao/sqlglot/commit/be0a4a85d41bfb617360bd9a59aa9e631e4d6d6c) - **bigquery**: Consume dashed identifiers only if they're connected *(PR [#4144](https://github.com/tobymao/sqlglot/pull/4144) by [@VaggelisD](https://github.com/VaggelisD))*
- [`0444819`](https://github.com/tobymao/sqlglot/commit/044481926d4b008027a2c7fb20501514ef507811) - **optimizer**: don't reorder subquery predicates in simplify *(PR [#4147](https://github.com/tobymao/sqlglot/pull/4147) by [@georgesittas](https://github.com/georgesittas))*
- [`89519bb`](https://github.com/tobymao/sqlglot/commit/89519bba99fc11f17e8e00bf8e3f6dde213e99be) - **clickhouse**: make ToTableProperty appear right after the DDL name *(PR [#4151](https://github.com/tobymao/sqlglot/pull/4151) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#4150](https://github.com/tobymao/sqlglot/issues/4150) opened by [@tzinyama](https://github.com/tzinyama)*
### :recycle: Refactors
- [`9c527b5`](https://github.com/tobymao/sqlglot/commit/9c527b549cc56db9d8f44579397d9f9fe1440573) - treat Nullable as an arg instead of a DataType.TYPE *(PR [#4094](https://github.com/tobymao/sqlglot/pull/4094) by [@georgesittas](https://github.com/georgesittas))*
- [`2961049`](https://github.com/tobymao/sqlglot/commit/296104950f2e679aea37810a48eb490e170518d3) - implement decorator to easily mark args as unsupported *(PR [#4111](https://github.com/tobymao/sqlglot/pull/4111) by [@georgesittas](https://github.com/georgesittas))*
- [`7cf1d70`](https://github.com/tobymao/sqlglot/commit/7cf1d70e909ae319ff659e1455e6fcad1e8cf905) - **optimizer**: Optimize USING expansion *(PR [#4115](https://github.com/tobymao/sqlglot/pull/4115) by [@VaggelisD](https://github.com/VaggelisD))*
### :wrench: Chores
- [`75e6406`](https://github.com/tobymao/sqlglot/commit/75e640672eef0ddf752ee36dbc6f904f8e06510f) - **prql**: rewrite tests to use `validate_all()` *(PR [#4097](https://github.com/tobymao/sqlglot/pull/4097) by [@JJHCool](https://github.com/JJHCool))*
- [`e1f6ae3`](https://github.com/tobymao/sqlglot/commit/e1f6ae393fa2857dbbb9a14b03cbe39910207233) - **prql**: use validate_all instead of validate_identity *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`2dc0b86`](https://github.com/tobymao/sqlglot/commit/2dc0b8620e16b3cdf85f6bb6bea10c2527497933) - **optimizer**: rename helper function in expand_using *(PR [#4117](https://github.com/tobymao/sqlglot/pull/4117) by [@georgesittas](https://github.com/georgesittas))*
- [`fd8b8ba`](https://github.com/tobymao/sqlglot/commit/fd8b8ba7dedaee5d237b080db5c4f7e83ba079e9) - create ARRAY_TYPES set under DataType *(commit by [@georgesittas](https://github.com/georgesittas))*
## [v25.22.0] - 2024-09-19
### :boom: BREAKING CHANGES
- due to [`ba015dc`](https://github.com/tobymao/sqlglot/commit/ba015dc1102a4fe0c35cbfe6e3d23dc24263c20f) - add `returning` to merge expression builder *(PR [#4125](https://github.com/tobymao/sqlglot/pull/4125) by [@max-muoto](https://github.com/max-muoto))*:
add `returning` to merge expression builder (#4125)
### :sparkles: New Features
- [`1fac6a9`](https://github.com/tobymao/sqlglot/commit/1fac6a9f46e147a5583042d6f82deffd04cd58c9) - expose sqlglot.expressions.delete as a sqlglot module function *(PR [#4126](https://github.com/tobymao/sqlglot/pull/4126) by [@max-muoto](https://github.com/max-muoto))*
- [`4506b3b`](https://github.com/tobymao/sqlglot/commit/4506b3b58fde8e8fe711df8fd0c9c245a98ca86b) - **duckdb**: add support for the UNION type *(PR [#4128](https://github.com/tobymao/sqlglot/pull/4128) by [@georgesittas](https://github.com/georgesittas))*
- [`ba015dc`](https://github.com/tobymao/sqlglot/commit/ba015dc1102a4fe0c35cbfe6e3d23dc24263c20f) - add `returning` to merge expression builder *(PR [#4125](https://github.com/tobymao/sqlglot/pull/4125) by [@max-muoto](https://github.com/max-muoto))*
### :bug: Bug Fixes
- [`22c456d`](https://github.com/tobymao/sqlglot/commit/22c456d032b457244b397598d4480ae22ad316bd) - Do not generate DISTINCT keyword in FILTER *(PR [#4130](https://github.com/tobymao/sqlglot/pull/4130) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4129](https://github.com/tobymao/sqlglot/issues/4129) opened by [@tekumara](https://github.com/tekumara)*
- [`089b77e`](https://github.com/tobymao/sqlglot/commit/089b77ec7efcd6decbf9a7be500e73dc88ba4dec) - **athena**: DDL fixes *(PR [#4132](https://github.com/tobymao/sqlglot/pull/4132) by [@erindru](https://github.com/erindru))*
- [`e6c9902`](https://github.com/tobymao/sqlglot/commit/e6c990225e2685c617dfd1594c83778036405f6b) - invalid regex *(commit by [@tobymao](https://github.com/tobymao))*
## [v25.21.3] - 2024-09-14
### :sparkles: New Features
- [`bd8e050`](https://github.com/tobymao/sqlglot/commit/bd8e050e7df905082fd32e26c4ee0c6e2d36c897) - **clickhouse**: support ON CLUSTER clause in DELETE *(PR [#4119](https://github.com/tobymao/sqlglot/pull/4119) by [@treysp](https://github.com/treysp))*
### :bug: Bug Fixes
- [`21f5bcd`](https://github.com/tobymao/sqlglot/commit/21f5bcd13eb9c567c711cec5879c4d08a052b91c) - parse struct(...)[] type properly *(PR [#4123](https://github.com/tobymao/sqlglot/pull/4123) by [@georgesittas](https://github.com/georgesittas))*
## [v25.21.2] - 2024-09-13 ## [v25.21.2] - 2024-09-13
### :sparkles: New Features ### :sparkles: New Features
- [`a34f8b6`](https://github.com/tobymao/sqlglot/commit/a34f8b6ff9b0aa8595214da75fe7cbfbc8285476) - **oracle**: support TRUNC without fmt argument fixes [#4116](https://github.com/tobymao/sqlglot/pull/4116) *(commit by [@georgesittas](https://github.com/georgesittas))* - [`a34f8b6`](https://github.com/tobymao/sqlglot/commit/a34f8b6ff9b0aa8595214da75fe7cbfbc8285476) - **oracle**: support TRUNC without fmt argument fixes [#4116](https://github.com/tobymao/sqlglot/pull/4116) *(commit by [@georgesittas](https://github.com/georgesittas))*
@ -4754,3 +4876,8 @@ Changelog
[v25.21.0]: https://github.com/tobymao/sqlglot/compare/v25.20.1...v25.21.0 [v25.21.0]: https://github.com/tobymao/sqlglot/compare/v25.20.1...v25.21.0
[v25.21.1]: https://github.com/tobymao/sqlglot/compare/v25.21.0...v25.21.1 [v25.21.1]: https://github.com/tobymao/sqlglot/compare/v25.21.0...v25.21.1
[v25.21.2]: https://github.com/tobymao/sqlglot/compare/v25.21.1...v25.21.2 [v25.21.2]: https://github.com/tobymao/sqlglot/compare/v25.21.1...v25.21.2
[v25.21.3]: https://github.com/tobymao/sqlglot/compare/v25.21.2...v25.21.3
[v25.22.0]: https://github.com/tobymao/sqlglot/compare/v25.21.3...v25.22.0
[v25.23.0]: https://github.com/tobymao/sqlglot/compare/v25.20.2...v25.23.0
[v25.23.1]: https://github.com/tobymao/sqlglot/compare/v25.23.0...v25.23.1
[v25.23.2]: https://github.com/tobymao/sqlglot/compare/v25.23.1...v25.23.2

View file

@ -1,6 +1,6 @@
![SQLGlot logo](sqlglot.png) ![SQLGlot logo](sqlglot.png)
SQLGlot is a no-dependency SQL parser, transpiler, optimizer, and engine. It can be used to format SQL or translate between [21 different dialects](https://github.com/tobymao/sqlglot/blob/main/sqlglot/dialects/__init__.py) like [DuckDB](https://duckdb.org/), [Presto](https://prestodb.io/) / [Trino](https://trino.io/), [Spark](https://spark.apache.org/) / [Databricks](https://www.databricks.com/), [Snowflake](https://www.snowflake.com/en/), and [BigQuery](https://cloud.google.com/bigquery/). It aims to read a wide variety of SQL inputs and output syntactically and semantically correct SQL in the targeted dialects. SQLGlot is a no-dependency SQL parser, transpiler, optimizer, and engine. It can be used to format SQL or translate between [23 different dialects](https://github.com/tobymao/sqlglot/blob/main/sqlglot/dialects/__init__.py) like [DuckDB](https://duckdb.org/), [Presto](https://prestodb.io/) / [Trino](https://trino.io/), [Spark](https://spark.apache.org/) / [Databricks](https://www.databricks.com/), [Snowflake](https://www.snowflake.com/en/), and [BigQuery](https://cloud.google.com/bigquery/). It aims to read a wide variety of SQL inputs and output syntactically and semantically correct SQL in the targeted dialects.
It is a very comprehensive generic SQL parser with a robust [test suite](https://github.com/tobymao/sqlglot/blob/main/tests/). It is also quite [performant](#benchmarks), while being written purely in Python. It is a very comprehensive generic SQL parser with a robust [test suite](https://github.com/tobymao/sqlglot/blob/main/tests/). It is also quite [performant](#benchmarks), while being written purely in Python.

File diff suppressed because one or more lines are too long

View file

@ -768,154 +768,155 @@ make check # Full test suite &amp; linter checks
</span><span id="L-27"><a href="#L-27"><span class="linenos"> 27</span></a> <span class="n">cast</span> <span class="k">as</span> <span class="n">cast</span><span class="p">,</span> </span><span id="L-27"><a href="#L-27"><span class="linenos"> 27</span></a> <span class="n">cast</span> <span class="k">as</span> <span class="n">cast</span><span class="p">,</span>
</span><span id="L-28"><a href="#L-28"><span class="linenos"> 28</span></a> <span class="n">column</span> <span class="k">as</span> <span class="n">column</span><span class="p">,</span> </span><span id="L-28"><a href="#L-28"><span class="linenos"> 28</span></a> <span class="n">column</span> <span class="k">as</span> <span class="n">column</span><span class="p">,</span>
</span><span id="L-29"><a href="#L-29"><span class="linenos"> 29</span></a> <span class="n">condition</span> <span class="k">as</span> <span class="n">condition</span><span class="p">,</span> </span><span id="L-29"><a href="#L-29"><span class="linenos"> 29</span></a> <span class="n">condition</span> <span class="k">as</span> <span class="n">condition</span><span class="p">,</span>
</span><span id="L-30"><a href="#L-30"><span class="linenos"> 30</span></a> <span class="n">except_</span> <span class="k">as</span> <span class="n">except_</span><span class="p">,</span> </span><span id="L-30"><a href="#L-30"><span class="linenos"> 30</span></a> <span class="n">delete</span> <span class="k">as</span> <span class="n">delete</span><span class="p">,</span>
</span><span id="L-31"><a href="#L-31"><span class="linenos"> 31</span></a> <span class="n">from_</span> <span class="k">as</span> <span class="n">from_</span><span class="p">,</span> </span><span id="L-31"><a href="#L-31"><span class="linenos"> 31</span></a> <span class="n">except_</span> <span class="k">as</span> <span class="n">except_</span><span class="p">,</span>
</span><span id="L-32"><a href="#L-32"><span class="linenos"> 32</span></a> <span class="n">func</span> <span class="k">as</span> <span class="n">func</span><span class="p">,</span> </span><span id="L-32"><a href="#L-32"><span class="linenos"> 32</span></a> <span class="n">from_</span> <span class="k">as</span> <span class="n">from_</span><span class="p">,</span>
</span><span id="L-33"><a href="#L-33"><span class="linenos"> 33</span></a> <span class="n">insert</span> <span class="k">as</span> <span class="n">insert</span><span class="p">,</span> </span><span id="L-33"><a href="#L-33"><span class="linenos"> 33</span></a> <span class="n">func</span> <span class="k">as</span> <span class="n">func</span><span class="p">,</span>
</span><span id="L-34"><a href="#L-34"><span class="linenos"> 34</span></a> <span class="n">intersect</span> <span class="k">as</span> <span class="n">intersect</span><span class="p">,</span> </span><span id="L-34"><a href="#L-34"><span class="linenos"> 34</span></a> <span class="n">insert</span> <span class="k">as</span> <span class="n">insert</span><span class="p">,</span>
</span><span id="L-35"><a href="#L-35"><span class="linenos"> 35</span></a> <span class="n">maybe_parse</span> <span class="k">as</span> <span class="n">maybe_parse</span><span class="p">,</span> </span><span id="L-35"><a href="#L-35"><span class="linenos"> 35</span></a> <span class="n">intersect</span> <span class="k">as</span> <span class="n">intersect</span><span class="p">,</span>
</span><span id="L-36"><a href="#L-36"><span class="linenos"> 36</span></a> <span class="n">merge</span> <span class="k">as</span> <span class="n">merge</span><span class="p">,</span> </span><span id="L-36"><a href="#L-36"><span class="linenos"> 36</span></a> <span class="n">maybe_parse</span> <span class="k">as</span> <span class="n">maybe_parse</span><span class="p">,</span>
</span><span id="L-37"><a href="#L-37"><span class="linenos"> 37</span></a> <span class="n">not_</span> <span class="k">as</span> <span class="n">not_</span><span class="p">,</span> </span><span id="L-37"><a href="#L-37"><span class="linenos"> 37</span></a> <span class="n">merge</span> <span class="k">as</span> <span class="n">merge</span><span class="p">,</span>
</span><span id="L-38"><a href="#L-38"><span class="linenos"> 38</span></a> <span class="n">or_</span> <span class="k">as</span> <span class="n">or_</span><span class="p">,</span> </span><span id="L-38"><a href="#L-38"><span class="linenos"> 38</span></a> <span class="n">not_</span> <span class="k">as</span> <span class="n">not_</span><span class="p">,</span>
</span><span id="L-39"><a href="#L-39"><span class="linenos"> 39</span></a> <span class="n">select</span> <span class="k">as</span> <span class="n">select</span><span class="p">,</span> </span><span id="L-39"><a href="#L-39"><span class="linenos"> 39</span></a> <span class="n">or_</span> <span class="k">as</span> <span class="n">or_</span><span class="p">,</span>
</span><span id="L-40"><a href="#L-40"><span class="linenos"> 40</span></a> <span class="n">subquery</span> <span class="k">as</span> <span class="n">subquery</span><span class="p">,</span> </span><span id="L-40"><a href="#L-40"><span class="linenos"> 40</span></a> <span class="n">select</span> <span class="k">as</span> <span class="n">select</span><span class="p">,</span>
</span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a> <span class="n">table_</span> <span class="k">as</span> <span class="n">table</span><span class="p">,</span> </span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a> <span class="n">subquery</span> <span class="k">as</span> <span class="n">subquery</span><span class="p">,</span>
</span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a> <span class="n">to_column</span> <span class="k">as</span> <span class="n">to_column</span><span class="p">,</span> </span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a> <span class="n">table_</span> <span class="k">as</span> <span class="n">table</span><span class="p">,</span>
</span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a> <span class="n">to_identifier</span> <span class="k">as</span> <span class="n">to_identifier</span><span class="p">,</span> </span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a> <span class="n">to_column</span> <span class="k">as</span> <span class="n">to_column</span><span class="p">,</span>
</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a> <span class="n">to_table</span> <span class="k">as</span> <span class="n">to_table</span><span class="p">,</span> </span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a> <span class="n">to_identifier</span> <span class="k">as</span> <span class="n">to_identifier</span><span class="p">,</span>
</span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a> <span class="n">union</span> <span class="k">as</span> <span class="n">union</span><span class="p">,</span> </span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a> <span class="n">to_table</span> <span class="k">as</span> <span class="n">to_table</span><span class="p">,</span>
</span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a><span class="p">)</span> </span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a> <span class="n">union</span> <span class="k">as</span> <span class="n">union</span><span class="p">,</span>
</span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a><span class="kn">from</span> <span class="nn">sqlglot.generator</span> <span class="kn">import</span> <span class="n">Generator</span> <span class="k">as</span> <span class="n">Generator</span> </span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a><span class="p">)</span>
</span><span id="L-48"><a href="#L-48"><span class="linenos"> 48</span></a><span class="kn">from</span> <span class="nn">sqlglot.parser</span> <span class="kn">import</span> <span class="n">Parser</span> <span class="k">as</span> <span class="n">Parser</span> </span><span id="L-48"><a href="#L-48"><span class="linenos"> 48</span></a><span class="kn">from</span> <span class="nn">sqlglot.generator</span> <span class="kn">import</span> <span class="n">Generator</span> <span class="k">as</span> <span class="n">Generator</span>
</span><span id="L-49"><a href="#L-49"><span class="linenos"> 49</span></a><span class="kn">from</span> <span class="nn">sqlglot.schema</span> <span class="kn">import</span> <span class="n">MappingSchema</span> <span class="k">as</span> <span class="n">MappingSchema</span><span class="p">,</span> <span class="n">Schema</span> <span class="k">as</span> <span class="n">Schema</span> </span><span id="L-49"><a href="#L-49"><span class="linenos"> 49</span></a><span class="kn">from</span> <span class="nn">sqlglot.parser</span> <span class="kn">import</span> <span class="n">Parser</span> <span class="k">as</span> <span class="n">Parser</span>
</span><span id="L-50"><a href="#L-50"><span class="linenos"> 50</span></a><span class="kn">from</span> <span class="nn">sqlglot.tokens</span> <span class="kn">import</span> <span class="n">Token</span> <span class="k">as</span> <span class="n">Token</span><span class="p">,</span> <span class="n">Tokenizer</span> <span class="k">as</span> <span class="n">Tokenizer</span><span class="p">,</span> <span class="n">TokenType</span> <span class="k">as</span> <span class="n">TokenType</span> </span><span id="L-50"><a href="#L-50"><span class="linenos"> 50</span></a><span class="kn">from</span> <span class="nn">sqlglot.schema</span> <span class="kn">import</span> <span class="n">MappingSchema</span> <span class="k">as</span> <span class="n">MappingSchema</span><span class="p">,</span> <span class="n">Schema</span> <span class="k">as</span> <span class="n">Schema</span>
</span><span id="L-51"><a href="#L-51"><span class="linenos"> 51</span></a> </span><span id="L-51"><a href="#L-51"><span class="linenos"> 51</span></a><span class="kn">from</span> <span class="nn">sqlglot.tokens</span> <span class="kn">import</span> <span class="n">Token</span> <span class="k">as</span> <span class="n">Token</span><span class="p">,</span> <span class="n">Tokenizer</span> <span class="k">as</span> <span class="n">Tokenizer</span><span class="p">,</span> <span class="n">TokenType</span> <span class="k">as</span> <span class="n">TokenType</span>
</span><span id="L-52"><a href="#L-52"><span class="linenos"> 52</span></a><span class="k">if</span> <span class="n">t</span><span class="o">.</span><span class="n">TYPE_CHECKING</span><span class="p">:</span> </span><span id="L-52"><a href="#L-52"><span class="linenos"> 52</span></a>
</span><span id="L-53"><a href="#L-53"><span class="linenos"> 53</span></a> <span class="kn">from</span> <span class="nn">sqlglot._typing</span> <span class="kn">import</span> <span class="n">E</span> </span><span id="L-53"><a href="#L-53"><span class="linenos"> 53</span></a><span class="k">if</span> <span class="n">t</span><span class="o">.</span><span class="n">TYPE_CHECKING</span><span class="p">:</span>
</span><span id="L-54"><a href="#L-54"><span class="linenos"> 54</span></a> <span class="kn">from</span> <span class="nn">sqlglot.dialects.dialect</span> <span class="kn">import</span> <span class="n">DialectType</span> <span class="k">as</span> <span class="n">DialectType</span> </span><span id="L-54"><a href="#L-54"><span class="linenos"> 54</span></a> <span class="kn">from</span> <span class="nn">sqlglot._typing</span> <span class="kn">import</span> <span class="n">E</span>
</span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a> </span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a> <span class="kn">from</span> <span class="nn">sqlglot.dialects.dialect</span> <span class="kn">import</span> <span class="n">DialectType</span> <span class="k">as</span> <span class="n">DialectType</span>
</span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s2">&quot;sqlglot&quot;</span><span class="p">)</span> </span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a>
</span><span id="L-57"><a href="#L-57"><span class="linenos"> 57</span></a> </span><span id="L-57"><a href="#L-57"><span class="linenos"> 57</span></a><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s2">&quot;sqlglot&quot;</span><span class="p">)</span>
</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a> </span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a>
</span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a><span class="k">try</span><span class="p">:</span> </span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a>
</span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a> <span class="kn">from</span> <span class="nn">sqlglot._version</span> <span class="kn">import</span> <span class="n">__version__</span><span class="p">,</span> <span class="n">__version_tuple__</span> </span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a><span class="k">try</span><span class="p">:</span>
</span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a><span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span> </span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a> <span class="kn">from</span> <span class="nn">sqlglot._version</span> <span class="kn">import</span> <span class="n">__version__</span><span class="p">,</span> <span class="n">__version_tuple__</span>
</span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a> <span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span> </span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a><span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
</span><span id="L-63"><a href="#L-63"><span class="linenos"> 63</span></a> <span class="s2">&quot;Unable to set __version__, run `pip install -e .` or `python setup.py develop` first.&quot;</span> </span><span id="L-63"><a href="#L-63"><span class="linenos"> 63</span></a> <span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span>
</span><span id="L-64"><a href="#L-64"><span class="linenos"> 64</span></a> <span class="p">)</span> </span><span id="L-64"><a href="#L-64"><span class="linenos"> 64</span></a> <span class="s2">&quot;Unable to set __version__, run `pip install -e .` or `python setup.py develop` first.&quot;</span>
</span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a> </span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a> <span class="p">)</span>
</span><span id="L-66"><a href="#L-66"><span class="linenos"> 66</span></a> </span><span id="L-66"><a href="#L-66"><span class="linenos"> 66</span></a>
</span><span id="L-67"><a href="#L-67"><span class="linenos"> 67</span></a><span class="n">pretty</span> <span class="o">=</span> <span class="kc">False</span> </span><span id="L-67"><a href="#L-67"><span class="linenos"> 67</span></a>
</span><span id="L-68"><a href="#L-68"><span class="linenos"> 68</span></a><span class="sd">&quot;&quot;&quot;Whether to format generated SQL by default.&quot;&quot;&quot;</span> </span><span id="L-68"><a href="#L-68"><span class="linenos"> 68</span></a><span class="n">pretty</span> <span class="o">=</span> <span class="kc">False</span>
</span><span id="L-69"><a href="#L-69"><span class="linenos"> 69</span></a> </span><span id="L-69"><a href="#L-69"><span class="linenos"> 69</span></a><span class="sd">&quot;&quot;&quot;Whether to format generated SQL by default.&quot;&quot;&quot;</span>
</span><span id="L-70"><a href="#L-70"><span class="linenos"> 70</span></a> </span><span id="L-70"><a href="#L-70"><span class="linenos"> 70</span></a>
</span><span id="L-71"><a href="#L-71"><span class="linenos"> 71</span></a><span class="k">def</span> <span class="nf">tokenize</span><span class="p">(</span><span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Token</span><span class="p">]:</span> </span><span id="L-71"><a href="#L-71"><span class="linenos"> 71</span></a>
</span><span id="L-72"><a href="#L-72"><span class="linenos"> 72</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> </span><span id="L-72"><a href="#L-72"><span class="linenos"> 72</span></a><span class="k">def</span> <span class="nf">tokenize</span><span class="p">(</span><span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Token</span><span class="p">]:</span>
</span><span id="L-73"><a href="#L-73"><span class="linenos"> 73</span></a><span class="sd"> Tokenizes the given SQL string.</span> </span><span id="L-73"><a href="#L-73"><span class="linenos"> 73</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a> </span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a><span class="sd"> Tokenizes the given SQL string.</span>
</span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a><span class="sd"> Args:</span> </span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a>
</span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a><span class="sd"> sql: the SQL code string to tokenize.</span> </span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a><span class="sd"> Args:</span>
</span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a><span class="sd"> read: the SQL dialect to apply during tokenizing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span> </span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a><span class="sd"> sql: the SQL code string to tokenize.</span>
</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a><span class="sd"> dialect: the SQL dialect (alias for read).</span> </span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a><span class="sd"> read: the SQL dialect to apply during tokenizing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span>
</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a> </span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a><span class="sd"> dialect: the SQL dialect (alias for read).</span>
</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a><span class="sd"> Returns:</span> </span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a>
</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a><span class="sd"> The resulting list of tokens.</span> </span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a><span class="sd"> Returns:</span>
</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a><span class="sd"> &quot;&quot;&quot;</span> </span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a><span class="sd"> The resulting list of tokens.</span>
</span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a> <span class="k">return</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span><span class="o">.</span><span class="n">tokenize</span><span class="p">(</span><span class="n">sql</span><span class="p">)</span> </span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a> </span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a> <span class="k">return</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span><span class="o">.</span><span class="n">tokenize</span><span class="p">(</span><span class="n">sql</span><span class="p">)</span>
</span><span id="L-85"><a href="#L-85"><span class="linenos"> 85</span></a> </span><span id="L-85"><a href="#L-85"><span class="linenos"> 85</span></a>
</span><span id="L-86"><a href="#L-86"><span class="linenos"> 86</span></a><span class="k">def</span> <span class="nf">parse</span><span class="p">(</span> </span><span id="L-86"><a href="#L-86"><span class="linenos"> 86</span></a>
</span><span id="L-87"><a href="#L-87"><span class="linenos"> 87</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span> </span><span id="L-87"><a href="#L-87"><span class="linenos"> 87</span></a><span class="k">def</span> <span class="nf">parse</span><span class="p">(</span>
</span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">Expression</span><span class="p">]]:</span> </span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span>
</span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> </span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">Expression</span><span class="p">]]:</span>
</span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a><span class="sd"> Parses the given SQL string into a collection of syntax trees, one per parsed SQL statement.</span> </span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</span></a> </span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</span></a><span class="sd"> Parses the given SQL string into a collection of syntax trees, one per parsed SQL statement.</span>
</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a><span class="sd"> Args:</span> </span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a>
</span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a><span class="sd"> sql: the SQL code string to parse.</span> </span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a><span class="sd"> Args:</span>
</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a><span class="sd"> read: the SQL dialect to apply during parsing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span> </span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a><span class="sd"> sql: the SQL code string to parse.</span>
</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a><span class="sd"> dialect: the SQL dialect (alias for read).</span> </span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a><span class="sd"> read: the SQL dialect to apply during parsing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span>
</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span> </span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a><span class="sd"> dialect: the SQL dialect (alias for read).</span>
</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a> </span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span>
</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a><span class="sd"> Returns:</span> </span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a>
</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a><span class="sd"> The resulting syntax tree collection.</span> </span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a><span class="sd"> Returns:</span>
</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a><span class="sd"> &quot;&quot;&quot;</span> </span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a><span class="sd"> The resulting syntax tree collection.</span>
</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a> <span class="k">return</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span> </span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a> </span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a> <span class="k">return</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span>
</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a> </span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a>
</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a><span class="nd">@t</span><span class="o">.</span><span class="n">overload</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="k">def</span> <span class="nf">parse_one</span><span class="p">(</span><span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">into</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Type</span><span class="p">[</span><span class="n">E</span><span class="p">],</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">E</span><span class="p">:</span> <span class="o">...</span> </span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a><span class="nd">@t</span><span class="o">.</span><span class="n">overload</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">def</span> <span class="nf">parse_one</span><span class="p">(</span><span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">into</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Type</span><span class="p">[</span><span class="n">E</span><span class="p">],</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">E</span><span class="p">:</span> <span class="o">...</span>
</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a> </span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a>
</span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a><span class="nd">@t</span><span class="o">.</span><span class="n">overload</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="k">def</span> <span class="nf">parse_one</span><span class="p">(</span><span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Expression</span><span class="p">:</span> <span class="o">...</span> </span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a><span class="nd">@t</span><span class="o">.</span><span class="n">overload</span>
</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a> </span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a><span class="k">def</span> <span class="nf">parse_one</span><span class="p">(</span><span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Expression</span><span class="p">:</span> <span class="o">...</span>
</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a> </span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a>
</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a><span class="k">def</span> <span class="nf">parse_one</span><span class="p">(</span> </span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a>
</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> </span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a><span class="k">def</span> <span class="nf">parse_one</span><span class="p">(</span>
</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a> <span class="n">into</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">exp</span><span class="o">.</span><span class="n">IntoType</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span> </span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a> <span class="n">into</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">exp</span><span class="o">.</span><span class="n">IntoType</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Expression</span><span class="p">:</span> </span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> </span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Expression</span><span class="p">:</span>
</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a><span class="sd"> Parses the given SQL string and returns a syntax tree for the first parsed SQL statement.</span> </span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a> </span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a><span class="sd"> Parses the given SQL string and returns a syntax tree for the first parsed SQL statement.</span>
</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a><span class="sd"> Args:</span> </span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a>
</span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a><span class="sd"> sql: the SQL code string to parse.</span> </span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a><span class="sd"> Args:</span>
</span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a><span class="sd"> read: the SQL dialect to apply during parsing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span> </span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a><span class="sd"> sql: the SQL code string to parse.</span>
</span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a><span class="sd"> dialect: the SQL dialect (alias for read)</span> </span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a><span class="sd"> read: the SQL dialect to apply during parsing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span>
</span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a><span class="sd"> into: the SQLGlot Expression to parse into.</span> </span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a><span class="sd"> dialect: the SQL dialect (alias for read)</span>
</span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span> </span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a><span class="sd"> into: the SQLGlot Expression to parse into.</span>
</span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a> </span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span>
</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a><span class="sd"> Returns:</span> </span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a>
</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a><span class="sd"> The syntax tree for the first parsed statement.</span> </span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a><span class="sd"> Returns:</span>
</span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a><span class="sd"> &quot;&quot;&quot;</span> </span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a><span class="sd"> The syntax tree for the first parsed statement.</span>
</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a> </span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a> <span class="n">dialect</span> <span class="o">=</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span> </span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a>
</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a> </span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a> <span class="n">dialect</span> <span class="o">=</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span>
</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a> <span class="k">if</span> <span class="n">into</span><span class="p">:</span> </span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a>
</span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a> <span class="n">result</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">parse_into</span><span class="p">(</span><span class="n">into</span><span class="p">,</span> <span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span> </span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a> <span class="k">if</span> <span class="n">into</span><span class="p">:</span>
</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a> <span class="k">else</span><span class="p">:</span> </span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a> <span class="n">result</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">parse_into</span><span class="p">(</span><span class="n">into</span><span class="p">,</span> <span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span>
</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a> <span class="n">result</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span> </span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a> </span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a> <span class="n">result</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span>
</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a> <span class="k">for</span> <span class="n">expression</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span> </span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a>
</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">expression</span><span class="p">:</span> </span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a> <span class="k">for</span> <span class="n">expression</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a> <span class="k">raise</span> <span class="n">ParseError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No expression was parsed from &#39;</span><span class="si">{</span><span class="n">sql</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span> </span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">expression</span><span class="p">:</span>
</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a> <span class="k">return</span> <span class="n">expression</span> </span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a> <span class="k">raise</span> <span class="n">ParseError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No expression was parsed from &#39;</span><span class="si">{</span><span class="n">sql</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span>
</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a> <span class="k">else</span><span class="p">:</span> </span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a> <span class="k">return</span> <span class="n">expression</span>
</span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a> <span class="k">raise</span> <span class="n">ParseError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No expression was parsed from &#39;</span><span class="si">{</span><span class="n">sql</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span> </span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a> <span class="k">else</span><span class="p">:</span>
</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">raise</span> <span class="n">ParseError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No expression was parsed from &#39;</span><span class="si">{</span><span class="n">sql</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span>
</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a> </span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a>
</span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a><span class="k">def</span> <span class="nf">transpile</span><span class="p">(</span> </span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a>
</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> </span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a><span class="k">def</span> <span class="nf">transpile</span><span class="p">(</span>
</span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a> <span class="n">write</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a> <span class="n">identity</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span> </span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a> <span class="n">write</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a> <span class="n">error_level</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">ErrorLevel</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a> <span class="n">identity</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span> </span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a> <span class="n">error_level</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">ErrorLevel</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span> </span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> </span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a><span class="sd"> Parses the given SQL string in accordance with the source dialect and returns a list of SQL strings transformed</span> </span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a><span class="sd"> to conform to the target dialect. Each string in the returned list represents a single transformed SQL statement.</span> </span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a><span class="sd"> Parses the given SQL string in accordance with the source dialect and returns a list of SQL strings transformed</span>
</span><span id="L-159"><a href="#L-159"><span class="linenos">159</span></a> </span><span id="L-159"><a href="#L-159"><span class="linenos">159</span></a><span class="sd"> to conform to the target dialect. Each string in the returned list represents a single transformed SQL statement.</span>
</span><span id="L-160"><a href="#L-160"><span class="linenos">160</span></a><span class="sd"> Args:</span> </span><span id="L-160"><a href="#L-160"><span class="linenos">160</span></a>
</span><span id="L-161"><a href="#L-161"><span class="linenos">161</span></a><span class="sd"> sql: the SQL code string to transpile.</span> </span><span id="L-161"><a href="#L-161"><span class="linenos">161</span></a><span class="sd"> Args:</span>
</span><span id="L-162"><a href="#L-162"><span class="linenos">162</span></a><span class="sd"> read: the source dialect used to parse the input string (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span> </span><span id="L-162"><a href="#L-162"><span class="linenos">162</span></a><span class="sd"> sql: the SQL code string to transpile.</span>
</span><span id="L-163"><a href="#L-163"><span class="linenos">163</span></a><span class="sd"> write: the target dialect into which the input should be transformed (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span> </span><span id="L-163"><a href="#L-163"><span class="linenos">163</span></a><span class="sd"> read: the source dialect used to parse the input string (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span>
</span><span id="L-164"><a href="#L-164"><span class="linenos">164</span></a><span class="sd"> identity: if set to `True` and if the target dialect is not specified the source dialect will be used as both:</span> </span><span id="L-164"><a href="#L-164"><span class="linenos">164</span></a><span class="sd"> write: the target dialect into which the input should be transformed (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span>
</span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a><span class="sd"> the source and the target dialect.</span> </span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a><span class="sd"> identity: if set to `True` and if the target dialect is not specified the source dialect will be used as both:</span>
</span><span id="L-166"><a href="#L-166"><span class="linenos">166</span></a><span class="sd"> error_level: the desired error level of the parser.</span> </span><span id="L-166"><a href="#L-166"><span class="linenos">166</span></a><span class="sd"> the source and the target dialect.</span>
</span><span id="L-167"><a href="#L-167"><span class="linenos">167</span></a><span class="sd"> **opts: other `sqlglot.generator.Generator` options.</span> </span><span id="L-167"><a href="#L-167"><span class="linenos">167</span></a><span class="sd"> error_level: the desired error level of the parser.</span>
</span><span id="L-168"><a href="#L-168"><span class="linenos">168</span></a> </span><span id="L-168"><a href="#L-168"><span class="linenos">168</span></a><span class="sd"> **opts: other `sqlglot.generator.Generator` options.</span>
</span><span id="L-169"><a href="#L-169"><span class="linenos">169</span></a><span class="sd"> Returns:</span> </span><span id="L-169"><a href="#L-169"><span class="linenos">169</span></a>
</span><span id="L-170"><a href="#L-170"><span class="linenos">170</span></a><span class="sd"> The list of transpiled SQL statements.</span> </span><span id="L-170"><a href="#L-170"><span class="linenos">170</span></a><span class="sd"> Returns:</span>
</span><span id="L-171"><a href="#L-171"><span class="linenos">171</span></a><span class="sd"> &quot;&quot;&quot;</span> </span><span id="L-171"><a href="#L-171"><span class="linenos">171</span></a><span class="sd"> The list of transpiled SQL statements.</span>
</span><span id="L-172"><a href="#L-172"><span class="linenos">172</span></a> <span class="n">write</span> <span class="o">=</span> <span class="p">(</span><span class="n">read</span> <span class="k">if</span> <span class="n">write</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">write</span><span class="p">)</span> <span class="k">if</span> <span class="n">identity</span> <span class="k">else</span> <span class="n">write</span> </span><span id="L-172"><a href="#L-172"><span class="linenos">172</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-173"><a href="#L-173"><span class="linenos">173</span></a> <span class="n">write</span> <span class="o">=</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">write</span><span class="p">)</span> </span><span id="L-173"><a href="#L-173"><span class="linenos">173</span></a> <span class="n">write</span> <span class="o">=</span> <span class="p">(</span><span class="n">read</span> <span class="k">if</span> <span class="n">write</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">write</span><span class="p">)</span> <span class="k">if</span> <span class="n">identity</span> <span class="k">else</span> <span class="n">write</span>
</span><span id="L-174"><a href="#L-174"><span class="linenos">174</span></a> <span class="k">return</span> <span class="p">[</span> </span><span id="L-174"><a href="#L-174"><span class="linenos">174</span></a> <span class="n">write</span> <span class="o">=</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">write</span><span class="p">)</span>
</span><span id="L-175"><a href="#L-175"><span class="linenos">175</span></a> <span class="n">write</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="n">expression</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="o">**</span><span class="n">opts</span><span class="p">)</span> <span class="k">if</span> <span class="n">expression</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span> </span><span id="L-175"><a href="#L-175"><span class="linenos">175</span></a> <span class="k">return</span> <span class="p">[</span>
</span><span id="L-176"><a href="#L-176"><span class="linenos">176</span></a> <span class="k">for</span> <span class="n">expression</span> <span class="ow">in</span> <span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="n">read</span><span class="p">,</span> <span class="n">error_level</span><span class="o">=</span><span class="n">error_level</span><span class="p">)</span> </span><span id="L-176"><a href="#L-176"><span class="linenos">176</span></a> <span class="n">write</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="n">expression</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="o">**</span><span class="n">opts</span><span class="p">)</span> <span class="k">if</span> <span class="n">expression</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
</span><span id="L-177"><a href="#L-177"><span class="linenos">177</span></a> <span class="p">]</span> </span><span id="L-177"><a href="#L-177"><span class="linenos">177</span></a> <span class="k">for</span> <span class="n">expression</span> <span class="ow">in</span> <span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="n">read</span><span class="p">,</span> <span class="n">error_level</span><span class="o">=</span><span class="n">error_level</span><span class="p">)</span>
</span><span id="L-178"><a href="#L-178"><span class="linenos">178</span></a> <span class="p">]</span>
</span></pre></div> </span></pre></div>
@ -957,19 +958,19 @@ make check # Full test suite &amp; linter checks
</div> </div>
<a class="headerlink" href="#tokenize"></a> <a class="headerlink" href="#tokenize"></a>
<div class="pdoc-code codehilite"><pre><span></span><span id="tokenize-72"><a href="#tokenize-72"><span class="linenos">72</span></a><span class="k">def</span> <span class="nf">tokenize</span><span class="p">(</span><span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Token</span><span class="p">]:</span> <div class="pdoc-code codehilite"><pre><span></span><span id="tokenize-73"><a href="#tokenize-73"><span class="linenos">73</span></a><span class="k">def</span> <span class="nf">tokenize</span><span class="p">(</span><span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">Token</span><span class="p">]:</span>
</span><span id="tokenize-73"><a href="#tokenize-73"><span class="linenos">73</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> </span><span id="tokenize-74"><a href="#tokenize-74"><span class="linenos">74</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="tokenize-74"><a href="#tokenize-74"><span class="linenos">74</span></a><span class="sd"> Tokenizes the given SQL string.</span> </span><span id="tokenize-75"><a href="#tokenize-75"><span class="linenos">75</span></a><span class="sd"> Tokenizes the given SQL string.</span>
</span><span id="tokenize-75"><a href="#tokenize-75"><span class="linenos">75</span></a> </span><span id="tokenize-76"><a href="#tokenize-76"><span class="linenos">76</span></a>
</span><span id="tokenize-76"><a href="#tokenize-76"><span class="linenos">76</span></a><span class="sd"> Args:</span> </span><span id="tokenize-77"><a href="#tokenize-77"><span class="linenos">77</span></a><span class="sd"> Args:</span>
</span><span id="tokenize-77"><a href="#tokenize-77"><span class="linenos">77</span></a><span class="sd"> sql: the SQL code string to tokenize.</span> </span><span id="tokenize-78"><a href="#tokenize-78"><span class="linenos">78</span></a><span class="sd"> sql: the SQL code string to tokenize.</span>
</span><span id="tokenize-78"><a href="#tokenize-78"><span class="linenos">78</span></a><span class="sd"> read: the SQL dialect to apply during tokenizing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span> </span><span id="tokenize-79"><a href="#tokenize-79"><span class="linenos">79</span></a><span class="sd"> read: the SQL dialect to apply during tokenizing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span>
</span><span id="tokenize-79"><a href="#tokenize-79"><span class="linenos">79</span></a><span class="sd"> dialect: the SQL dialect (alias for read).</span> </span><span id="tokenize-80"><a href="#tokenize-80"><span class="linenos">80</span></a><span class="sd"> dialect: the SQL dialect (alias for read).</span>
</span><span id="tokenize-80"><a href="#tokenize-80"><span class="linenos">80</span></a> </span><span id="tokenize-81"><a href="#tokenize-81"><span class="linenos">81</span></a>
</span><span id="tokenize-81"><a href="#tokenize-81"><span class="linenos">81</span></a><span class="sd"> Returns:</span> </span><span id="tokenize-82"><a href="#tokenize-82"><span class="linenos">82</span></a><span class="sd"> Returns:</span>
</span><span id="tokenize-82"><a href="#tokenize-82"><span class="linenos">82</span></a><span class="sd"> The resulting list of tokens.</span> </span><span id="tokenize-83"><a href="#tokenize-83"><span class="linenos">83</span></a><span class="sd"> The resulting list of tokens.</span>
</span><span id="tokenize-83"><a href="#tokenize-83"><span class="linenos">83</span></a><span class="sd"> &quot;&quot;&quot;</span> </span><span id="tokenize-84"><a href="#tokenize-84"><span class="linenos">84</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="tokenize-84"><a href="#tokenize-84"><span class="linenos">84</span></a> <span class="k">return</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span><span class="o">.</span><span class="n">tokenize</span><span class="p">(</span><span class="n">sql</span><span class="p">)</span> </span><span id="tokenize-85"><a href="#tokenize-85"><span class="linenos">85</span></a> <span class="k">return</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span><span class="o">.</span><span class="n">tokenize</span><span class="p">(</span><span class="n">sql</span><span class="p">)</span>
</span></pre></div> </span></pre></div>
@ -1003,22 +1004,22 @@ make check # Full test suite &amp; linter checks
</div> </div>
<a class="headerlink" href="#parse"></a> <a class="headerlink" href="#parse"></a>
<div class="pdoc-code codehilite"><pre><span></span><span id="parse-87"><a href="#parse-87"><span class="linenos"> 87</span></a><span class="k">def</span> <span class="nf">parse</span><span class="p">(</span> <div class="pdoc-code codehilite"><pre><span></span><span id="parse-88"><a href="#parse-88"><span class="linenos"> 88</span></a><span class="k">def</span> <span class="nf">parse</span><span class="p">(</span>
</span><span id="parse-88"><a href="#parse-88"><span class="linenos"> 88</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span> </span><span id="parse-89"><a href="#parse-89"><span class="linenos"> 89</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span>
</span><span id="parse-89"><a href="#parse-89"><span class="linenos"> 89</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">Expression</span><span class="p">]]:</span> </span><span id="parse-90"><a href="#parse-90"><span class="linenos"> 90</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">Expression</span><span class="p">]]:</span>
</span><span id="parse-90"><a href="#parse-90"><span class="linenos"> 90</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> </span><span id="parse-91"><a href="#parse-91"><span class="linenos"> 91</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="parse-91"><a href="#parse-91"><span class="linenos"> 91</span></a><span class="sd"> Parses the given SQL string into a collection of syntax trees, one per parsed SQL statement.</span> </span><span id="parse-92"><a href="#parse-92"><span class="linenos"> 92</span></a><span class="sd"> Parses the given SQL string into a collection of syntax trees, one per parsed SQL statement.</span>
</span><span id="parse-92"><a href="#parse-92"><span class="linenos"> 92</span></a> </span><span id="parse-93"><a href="#parse-93"><span class="linenos"> 93</span></a>
</span><span id="parse-93"><a href="#parse-93"><span class="linenos"> 93</span></a><span class="sd"> Args:</span> </span><span id="parse-94"><a href="#parse-94"><span class="linenos"> 94</span></a><span class="sd"> Args:</span>
</span><span id="parse-94"><a href="#parse-94"><span class="linenos"> 94</span></a><span class="sd"> sql: the SQL code string to parse.</span> </span><span id="parse-95"><a href="#parse-95"><span class="linenos"> 95</span></a><span class="sd"> sql: the SQL code string to parse.</span>
</span><span id="parse-95"><a href="#parse-95"><span class="linenos"> 95</span></a><span class="sd"> read: the SQL dialect to apply during parsing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span> </span><span id="parse-96"><a href="#parse-96"><span class="linenos"> 96</span></a><span class="sd"> read: the SQL dialect to apply during parsing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span>
</span><span id="parse-96"><a href="#parse-96"><span class="linenos"> 96</span></a><span class="sd"> dialect: the SQL dialect (alias for read).</span> </span><span id="parse-97"><a href="#parse-97"><span class="linenos"> 97</span></a><span class="sd"> dialect: the SQL dialect (alias for read).</span>
</span><span id="parse-97"><a href="#parse-97"><span class="linenos"> 97</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span> </span><span id="parse-98"><a href="#parse-98"><span class="linenos"> 98</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span>
</span><span id="parse-98"><a href="#parse-98"><span class="linenos"> 98</span></a> </span><span id="parse-99"><a href="#parse-99"><span class="linenos"> 99</span></a>
</span><span id="parse-99"><a href="#parse-99"><span class="linenos"> 99</span></a><span class="sd"> Returns:</span> </span><span id="parse-100"><a href="#parse-100"><span class="linenos">100</span></a><span class="sd"> Returns:</span>
</span><span id="parse-100"><a href="#parse-100"><span class="linenos">100</span></a><span class="sd"> The resulting syntax tree collection.</span> </span><span id="parse-101"><a href="#parse-101"><span class="linenos">101</span></a><span class="sd"> The resulting syntax tree collection.</span>
</span><span id="parse-101"><a href="#parse-101"><span class="linenos">101</span></a><span class="sd"> &quot;&quot;&quot;</span> </span><span id="parse-102"><a href="#parse-102"><span class="linenos">102</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="parse-102"><a href="#parse-102"><span class="linenos">102</span></a> <span class="k">return</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span> </span><span id="parse-103"><a href="#parse-103"><span class="linenos">103</span></a> <span class="k">return</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span>
</span></pre></div> </span></pre></div>
@ -1053,40 +1054,40 @@ make check # Full test suite &amp; linter checks
</div> </div>
<a class="headerlink" href="#parse_one"></a> <a class="headerlink" href="#parse_one"></a>
<div class="pdoc-code codehilite"><pre><span></span><span id="parse_one-113"><a href="#parse_one-113"><span class="linenos">113</span></a><span class="k">def</span> <span class="nf">parse_one</span><span class="p">(</span> <div class="pdoc-code codehilite"><pre><span></span><span id="parse_one-114"><a href="#parse_one-114"><span class="linenos">114</span></a><span class="k">def</span> <span class="nf">parse_one</span><span class="p">(</span>
</span><span id="parse_one-114"><a href="#parse_one-114"><span class="linenos">114</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> </span><span id="parse_one-115"><a href="#parse_one-115"><span class="linenos">115</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span><span id="parse_one-115"><a href="#parse_one-115"><span class="linenos">115</span></a> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="parse_one-116"><a href="#parse_one-116"><span class="linenos">116</span></a> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="parse_one-116"><a href="#parse_one-116"><span class="linenos">116</span></a> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="parse_one-117"><a href="#parse_one-117"><span class="linenos">117</span></a> <span class="n">dialect</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="parse_one-117"><a href="#parse_one-117"><span class="linenos">117</span></a> <span class="n">into</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">exp</span><span class="o">.</span><span class="n">IntoType</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="parse_one-118"><a href="#parse_one-118"><span class="linenos">118</span></a> <span class="n">into</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">exp</span><span class="o">.</span><span class="n">IntoType</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="parse_one-118"><a href="#parse_one-118"><span class="linenos">118</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span> </span><span id="parse_one-119"><a href="#parse_one-119"><span class="linenos">119</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="parse_one-119"><a href="#parse_one-119"><span class="linenos">119</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Expression</span><span class="p">:</span> </span><span id="parse_one-120"><a href="#parse_one-120"><span class="linenos">120</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Expression</span><span class="p">:</span>
</span><span id="parse_one-120"><a href="#parse_one-120"><span class="linenos">120</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> </span><span id="parse_one-121"><a href="#parse_one-121"><span class="linenos">121</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="parse_one-121"><a href="#parse_one-121"><span class="linenos">121</span></a><span class="sd"> Parses the given SQL string and returns a syntax tree for the first parsed SQL statement.</span> </span><span id="parse_one-122"><a href="#parse_one-122"><span class="linenos">122</span></a><span class="sd"> Parses the given SQL string and returns a syntax tree for the first parsed SQL statement.</span>
</span><span id="parse_one-122"><a href="#parse_one-122"><span class="linenos">122</span></a> </span><span id="parse_one-123"><a href="#parse_one-123"><span class="linenos">123</span></a>
</span><span id="parse_one-123"><a href="#parse_one-123"><span class="linenos">123</span></a><span class="sd"> Args:</span> </span><span id="parse_one-124"><a href="#parse_one-124"><span class="linenos">124</span></a><span class="sd"> Args:</span>
</span><span id="parse_one-124"><a href="#parse_one-124"><span class="linenos">124</span></a><span class="sd"> sql: the SQL code string to parse.</span> </span><span id="parse_one-125"><a href="#parse_one-125"><span class="linenos">125</span></a><span class="sd"> sql: the SQL code string to parse.</span>
</span><span id="parse_one-125"><a href="#parse_one-125"><span class="linenos">125</span></a><span class="sd"> read: the SQL dialect to apply during parsing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span> </span><span id="parse_one-126"><a href="#parse_one-126"><span class="linenos">126</span></a><span class="sd"> read: the SQL dialect to apply during parsing (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span>
</span><span id="parse_one-126"><a href="#parse_one-126"><span class="linenos">126</span></a><span class="sd"> dialect: the SQL dialect (alias for read)</span> </span><span id="parse_one-127"><a href="#parse_one-127"><span class="linenos">127</span></a><span class="sd"> dialect: the SQL dialect (alias for read)</span>
</span><span id="parse_one-127"><a href="#parse_one-127"><span class="linenos">127</span></a><span class="sd"> into: the SQLGlot Expression to parse into.</span> </span><span id="parse_one-128"><a href="#parse_one-128"><span class="linenos">128</span></a><span class="sd"> into: the SQLGlot Expression to parse into.</span>
</span><span id="parse_one-128"><a href="#parse_one-128"><span class="linenos">128</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span> </span><span id="parse_one-129"><a href="#parse_one-129"><span class="linenos">129</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span>
</span><span id="parse_one-129"><a href="#parse_one-129"><span class="linenos">129</span></a> </span><span id="parse_one-130"><a href="#parse_one-130"><span class="linenos">130</span></a>
</span><span id="parse_one-130"><a href="#parse_one-130"><span class="linenos">130</span></a><span class="sd"> Returns:</span> </span><span id="parse_one-131"><a href="#parse_one-131"><span class="linenos">131</span></a><span class="sd"> Returns:</span>
</span><span id="parse_one-131"><a href="#parse_one-131"><span class="linenos">131</span></a><span class="sd"> The syntax tree for the first parsed statement.</span> </span><span id="parse_one-132"><a href="#parse_one-132"><span class="linenos">132</span></a><span class="sd"> The syntax tree for the first parsed statement.</span>
</span><span id="parse_one-132"><a href="#parse_one-132"><span class="linenos">132</span></a><span class="sd"> &quot;&quot;&quot;</span> </span><span id="parse_one-133"><a href="#parse_one-133"><span class="linenos">133</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="parse_one-133"><a href="#parse_one-133"><span class="linenos">133</span></a> </span><span id="parse_one-134"><a href="#parse_one-134"><span class="linenos">134</span></a>
</span><span id="parse_one-134"><a href="#parse_one-134"><span class="linenos">134</span></a> <span class="n">dialect</span> <span class="o">=</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span> </span><span id="parse_one-135"><a href="#parse_one-135"><span class="linenos">135</span></a> <span class="n">dialect</span> <span class="o">=</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">read</span> <span class="ow">or</span> <span class="n">dialect</span><span class="p">)</span>
</span><span id="parse_one-135"><a href="#parse_one-135"><span class="linenos">135</span></a> </span><span id="parse_one-136"><a href="#parse_one-136"><span class="linenos">136</span></a>
</span><span id="parse_one-136"><a href="#parse_one-136"><span class="linenos">136</span></a> <span class="k">if</span> <span class="n">into</span><span class="p">:</span> </span><span id="parse_one-137"><a href="#parse_one-137"><span class="linenos">137</span></a> <span class="k">if</span> <span class="n">into</span><span class="p">:</span>
</span><span id="parse_one-137"><a href="#parse_one-137"><span class="linenos">137</span></a> <span class="n">result</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">parse_into</span><span class="p">(</span><span class="n">into</span><span class="p">,</span> <span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span> </span><span id="parse_one-138"><a href="#parse_one-138"><span class="linenos">138</span></a> <span class="n">result</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">parse_into</span><span class="p">(</span><span class="n">into</span><span class="p">,</span> <span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span>
</span><span id="parse_one-138"><a href="#parse_one-138"><span class="linenos">138</span></a> <span class="k">else</span><span class="p">:</span> </span><span id="parse_one-139"><a href="#parse_one-139"><span class="linenos">139</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="parse_one-139"><a href="#parse_one-139"><span class="linenos">139</span></a> <span class="n">result</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span> </span><span id="parse_one-140"><a href="#parse_one-140"><span class="linenos">140</span></a> <span class="n">result</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span>
</span><span id="parse_one-140"><a href="#parse_one-140"><span class="linenos">140</span></a> </span><span id="parse_one-141"><a href="#parse_one-141"><span class="linenos">141</span></a>
</span><span id="parse_one-141"><a href="#parse_one-141"><span class="linenos">141</span></a> <span class="k">for</span> <span class="n">expression</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span> </span><span id="parse_one-142"><a href="#parse_one-142"><span class="linenos">142</span></a> <span class="k">for</span> <span class="n">expression</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
</span><span id="parse_one-142"><a href="#parse_one-142"><span class="linenos">142</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">expression</span><span class="p">:</span> </span><span id="parse_one-143"><a href="#parse_one-143"><span class="linenos">143</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">expression</span><span class="p">:</span>
</span><span id="parse_one-143"><a href="#parse_one-143"><span class="linenos">143</span></a> <span class="k">raise</span> <span class="n">ParseError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No expression was parsed from &#39;</span><span class="si">{</span><span class="n">sql</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span> </span><span id="parse_one-144"><a href="#parse_one-144"><span class="linenos">144</span></a> <span class="k">raise</span> <span class="n">ParseError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No expression was parsed from &#39;</span><span class="si">{</span><span class="n">sql</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span>
</span><span id="parse_one-144"><a href="#parse_one-144"><span class="linenos">144</span></a> <span class="k">return</span> <span class="n">expression</span> </span><span id="parse_one-145"><a href="#parse_one-145"><span class="linenos">145</span></a> <span class="k">return</span> <span class="n">expression</span>
</span><span id="parse_one-145"><a href="#parse_one-145"><span class="linenos">145</span></a> <span class="k">else</span><span class="p">:</span> </span><span id="parse_one-146"><a href="#parse_one-146"><span class="linenos">146</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="parse_one-146"><a href="#parse_one-146"><span class="linenos">146</span></a> <span class="k">raise</span> <span class="n">ParseError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No expression was parsed from &#39;</span><span class="si">{</span><span class="n">sql</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span> </span><span id="parse_one-147"><a href="#parse_one-147"><span class="linenos">147</span></a> <span class="k">raise</span> <span class="n">ParseError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No expression was parsed from &#39;</span><span class="si">{</span><span class="n">sql</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span>
</span></pre></div> </span></pre></div>
@ -1122,36 +1123,36 @@ make check # Full test suite &amp; linter checks
</div> </div>
<a class="headerlink" href="#transpile"></a> <a class="headerlink" href="#transpile"></a>
<div class="pdoc-code codehilite"><pre><span></span><span id="transpile-149"><a href="#transpile-149"><span class="linenos">149</span></a><span class="k">def</span> <span class="nf">transpile</span><span class="p">(</span> <div class="pdoc-code codehilite"><pre><span></span><span id="transpile-150"><a href="#transpile-150"><span class="linenos">150</span></a><span class="k">def</span> <span class="nf">transpile</span><span class="p">(</span>
</span><span id="transpile-150"><a href="#transpile-150"><span class="linenos">150</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> </span><span id="transpile-151"><a href="#transpile-151"><span class="linenos">151</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span><span id="transpile-151"><a href="#transpile-151"><span class="linenos">151</span></a> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="transpile-152"><a href="#transpile-152"><span class="linenos">152</span></a> <span class="n">read</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="transpile-152"><a href="#transpile-152"><span class="linenos">152</span></a> <span class="n">write</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="transpile-153"><a href="#transpile-153"><span class="linenos">153</span></a> <span class="n">write</span><span class="p">:</span> <span class="n">DialectType</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="transpile-153"><a href="#transpile-153"><span class="linenos">153</span></a> <span class="n">identity</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span> </span><span id="transpile-154"><a href="#transpile-154"><span class="linenos">154</span></a> <span class="n">identity</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
</span><span id="transpile-154"><a href="#transpile-154"><span class="linenos">154</span></a> <span class="n">error_level</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">ErrorLevel</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> </span><span id="transpile-155"><a href="#transpile-155"><span class="linenos">155</span></a> <span class="n">error_level</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Optional</span><span class="p">[</span><span class="n">ErrorLevel</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="transpile-155"><a href="#transpile-155"><span class="linenos">155</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span> </span><span id="transpile-156"><a href="#transpile-156"><span class="linenos">156</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="transpile-156"><a href="#transpile-156"><span class="linenos">156</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span> </span><span id="transpile-157"><a href="#transpile-157"><span class="linenos">157</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
</span><span id="transpile-157"><a href="#transpile-157"><span class="linenos">157</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span> </span><span id="transpile-158"><a href="#transpile-158"><span class="linenos">158</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="transpile-158"><a href="#transpile-158"><span class="linenos">158</span></a><span class="sd"> Parses the given SQL string in accordance with the source dialect and returns a list of SQL strings transformed</span> </span><span id="transpile-159"><a href="#transpile-159"><span class="linenos">159</span></a><span class="sd"> Parses the given SQL string in accordance with the source dialect and returns a list of SQL strings transformed</span>
</span><span id="transpile-159"><a href="#transpile-159"><span class="linenos">159</span></a><span class="sd"> to conform to the target dialect. Each string in the returned list represents a single transformed SQL statement.</span> </span><span id="transpile-160"><a href="#transpile-160"><span class="linenos">160</span></a><span class="sd"> to conform to the target dialect. Each string in the returned list represents a single transformed SQL statement.</span>
</span><span id="transpile-160"><a href="#transpile-160"><span class="linenos">160</span></a> </span><span id="transpile-161"><a href="#transpile-161"><span class="linenos">161</span></a>
</span><span id="transpile-161"><a href="#transpile-161"><span class="linenos">161</span></a><span class="sd"> Args:</span> </span><span id="transpile-162"><a href="#transpile-162"><span class="linenos">162</span></a><span class="sd"> Args:</span>
</span><span id="transpile-162"><a href="#transpile-162"><span class="linenos">162</span></a><span class="sd"> sql: the SQL code string to transpile.</span> </span><span id="transpile-163"><a href="#transpile-163"><span class="linenos">163</span></a><span class="sd"> sql: the SQL code string to transpile.</span>
</span><span id="transpile-163"><a href="#transpile-163"><span class="linenos">163</span></a><span class="sd"> read: the source dialect used to parse the input string (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span> </span><span id="transpile-164"><a href="#transpile-164"><span class="linenos">164</span></a><span class="sd"> read: the source dialect used to parse the input string (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span>
</span><span id="transpile-164"><a href="#transpile-164"><span class="linenos">164</span></a><span class="sd"> write: the target dialect into which the input should be transformed (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span> </span><span id="transpile-165"><a href="#transpile-165"><span class="linenos">165</span></a><span class="sd"> write: the target dialect into which the input should be transformed (eg. &quot;spark&quot;, &quot;hive&quot;, &quot;presto&quot;, &quot;mysql&quot;).</span>
</span><span id="transpile-165"><a href="#transpile-165"><span class="linenos">165</span></a><span class="sd"> identity: if set to `True` and if the target dialect is not specified the source dialect will be used as both:</span> </span><span id="transpile-166"><a href="#transpile-166"><span class="linenos">166</span></a><span class="sd"> identity: if set to `True` and if the target dialect is not specified the source dialect will be used as both:</span>
</span><span id="transpile-166"><a href="#transpile-166"><span class="linenos">166</span></a><span class="sd"> the source and the target dialect.</span> </span><span id="transpile-167"><a href="#transpile-167"><span class="linenos">167</span></a><span class="sd"> the source and the target dialect.</span>
</span><span id="transpile-167"><a href="#transpile-167"><span class="linenos">167</span></a><span class="sd"> error_level: the desired error level of the parser.</span> </span><span id="transpile-168"><a href="#transpile-168"><span class="linenos">168</span></a><span class="sd"> error_level: the desired error level of the parser.</span>
</span><span id="transpile-168"><a href="#transpile-168"><span class="linenos">168</span></a><span class="sd"> **opts: other `sqlglot.generator.Generator` options.</span> </span><span id="transpile-169"><a href="#transpile-169"><span class="linenos">169</span></a><span class="sd"> **opts: other `sqlglot.generator.Generator` options.</span>
</span><span id="transpile-169"><a href="#transpile-169"><span class="linenos">169</span></a> </span><span id="transpile-170"><a href="#transpile-170"><span class="linenos">170</span></a>
</span><span id="transpile-170"><a href="#transpile-170"><span class="linenos">170</span></a><span class="sd"> Returns:</span> </span><span id="transpile-171"><a href="#transpile-171"><span class="linenos">171</span></a><span class="sd"> Returns:</span>
</span><span id="transpile-171"><a href="#transpile-171"><span class="linenos">171</span></a><span class="sd"> The list of transpiled SQL statements.</span> </span><span id="transpile-172"><a href="#transpile-172"><span class="linenos">172</span></a><span class="sd"> The list of transpiled SQL statements.</span>
</span><span id="transpile-172"><a href="#transpile-172"><span class="linenos">172</span></a><span class="sd"> &quot;&quot;&quot;</span> </span><span id="transpile-173"><a href="#transpile-173"><span class="linenos">173</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="transpile-173"><a href="#transpile-173"><span class="linenos">173</span></a> <span class="n">write</span> <span class="o">=</span> <span class="p">(</span><span class="n">read</span> <span class="k">if</span> <span class="n">write</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">write</span><span class="p">)</span> <span class="k">if</span> <span class="n">identity</span> <span class="k">else</span> <span class="n">write</span> </span><span id="transpile-174"><a href="#transpile-174"><span class="linenos">174</span></a> <span class="n">write</span> <span class="o">=</span> <span class="p">(</span><span class="n">read</span> <span class="k">if</span> <span class="n">write</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">write</span><span class="p">)</span> <span class="k">if</span> <span class="n">identity</span> <span class="k">else</span> <span class="n">write</span>
</span><span id="transpile-174"><a href="#transpile-174"><span class="linenos">174</span></a> <span class="n">write</span> <span class="o">=</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">write</span><span class="p">)</span> </span><span id="transpile-175"><a href="#transpile-175"><span class="linenos">175</span></a> <span class="n">write</span> <span class="o">=</span> <span class="n">Dialect</span><span class="o">.</span><span class="n">get_or_raise</span><span class="p">(</span><span class="n">write</span><span class="p">)</span>
</span><span id="transpile-175"><a href="#transpile-175"><span class="linenos">175</span></a> <span class="k">return</span> <span class="p">[</span> </span><span id="transpile-176"><a href="#transpile-176"><span class="linenos">176</span></a> <span class="k">return</span> <span class="p">[</span>
</span><span id="transpile-176"><a href="#transpile-176"><span class="linenos">176</span></a> <span class="n">write</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="n">expression</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="o">**</span><span class="n">opts</span><span class="p">)</span> <span class="k">if</span> <span class="n">expression</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span> </span><span id="transpile-177"><a href="#transpile-177"><span class="linenos">177</span></a> <span class="n">write</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="n">expression</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="o">**</span><span class="n">opts</span><span class="p">)</span> <span class="k">if</span> <span class="n">expression</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
</span><span id="transpile-177"><a href="#transpile-177"><span class="linenos">177</span></a> <span class="k">for</span> <span class="n">expression</span> <span class="ow">in</span> <span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="n">read</span><span class="p">,</span> <span class="n">error_level</span><span class="o">=</span><span class="n">error_level</span><span class="p">)</span> </span><span id="transpile-178"><a href="#transpile-178"><span class="linenos">178</span></a> <span class="k">for</span> <span class="n">expression</span> <span class="ow">in</span> <span class="n">parse</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="n">read</span><span class="p">,</span> <span class="n">error_level</span><span class="o">=</span><span class="n">error_level</span><span class="p">)</span>
</span><span id="transpile-178"><a href="#transpile-178"><span class="linenos">178</span></a> <span class="p">]</span> </span><span id="transpile-179"><a href="#transpile-179"><span class="linenos">179</span></a> <span class="p">]</span>
</span></pre></div> </span></pre></div>

View file

@ -76,8 +76,8 @@
</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="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="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="p">:</span> <span class="n">VERSION_TUPLE</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;25.21.2&#39;</span> </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;25.23.2&#39;</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">25</span><span class="p">,</span> <span class="mi">21</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</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">25</span><span class="p">,</span> <span class="mi">23</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
</span></pre></div> </span></pre></div>
@ -97,7 +97,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;25.21.2&#39;</span> <span class="default_value">&#39;25.23.2&#39;</span>
</div> </div>
@ -109,7 +109,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">(25, 21, 2)</span> <span class="default_value">(25, 23, 2)</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 one or more lines are too long

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 one or more lines are too long

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 one or more lines are too long

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 one or more lines are too long

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 one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1098,6 +1098,10 @@ Default: True</li>
<dd id="RisingWave.Generator.oncondition_sql" class="function"><a href="../generator.html#Generator.oncondition_sql">oncondition_sql</a></dd> <dd id="RisingWave.Generator.oncondition_sql" class="function"><a href="../generator.html#Generator.oncondition_sql">oncondition_sql</a></dd>
<dd id="RisingWave.Generator.jsonexists_sql" class="function"><a href="../generator.html#Generator.jsonexists_sql">jsonexists_sql</a></dd> <dd id="RisingWave.Generator.jsonexists_sql" class="function"><a href="../generator.html#Generator.jsonexists_sql">jsonexists_sql</a></dd>
<dd id="RisingWave.Generator.arrayagg_sql" class="function"><a href="../generator.html#Generator.arrayagg_sql">arrayagg_sql</a></dd> <dd id="RisingWave.Generator.arrayagg_sql" class="function"><a href="../generator.html#Generator.arrayagg_sql">arrayagg_sql</a></dd>
<dd id="RisingWave.Generator.apply_sql" class="function"><a href="../generator.html#Generator.apply_sql">apply_sql</a></dd>
<dd id="RisingWave.Generator.grant_sql" class="function"><a href="../generator.html#Generator.grant_sql">grant_sql</a></dd>
<dd id="RisingWave.Generator.grantprivilege_sql" class="function"><a href="../generator.html#Generator.grantprivilege_sql">grantprivilege_sql</a></dd>
<dd id="RisingWave.Generator.grantprincipal_sql" class="function"><a href="../generator.html#Generator.grantprincipal_sql">grantprincipal_sql</a></dd>
</div> </div>
<div><dt><a href="postgres.html#Postgres.Generator">sqlglot.dialects.postgres.Postgres.Generator</a></dt> <div><dt><a href="postgres.html#Postgres.Generator">sqlglot.dialects.postgres.Postgres.Generator</a></dt>

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 one or more lines are too long

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 one or more lines are too long

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 one or more lines are too long

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

@ -1895,7 +1895,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;year&#39;, &#39;day&#39;, &#39;quarter&#39;, &#39;week&#39;, &#39;year_month&#39;, &#39;month&#39;}</span> <span class="default_value">{&#39;week&#39;, &#39;year_month&#39;, &#39;day&#39;, &#39;quarter&#39;, &#39;year&#39;, &#39;month&#39;}</span>
</div> </div>

View file

@ -586,7 +586,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#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#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;}</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#JSONPathSubscript">sqlglot.expressions.JSONPathSubscript</a>&#39;&gt;, &lt;class &#39;<a href="expressions.html#JSONPathUnion">sqlglot.expressions.JSONPathUnion</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#JSONPathWildcard">sqlglot.expressions.JSONPathWildcard</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#JSONPathFilter">sqlglot.expressions.JSONPathFilter</a>&#39;&gt;}</span>
</div> </div>

File diff suppressed because one or more lines are too long

View file

@ -586,7 +586,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;prewhere&#39;, &#39;windows&#39;, &#39;offset&#39;, &#39;distribute&#39;, &#39;sample&#39;, &#39;cluster&#39;, &#39;locks&#39;, &#39;connect&#39;, &#39;settings&#39;, &#39;group&#39;, &#39;kind&#39;, &#39;format&#39;, &#39;options&#39;, &#39;laterals&#39;, &#39;match&#39;, &#39;distinct&#39;, &#39;into&#39;, &#39;limit&#39;, &#39;having&#39;, &#39;qualify&#39;, &#39;pivots&#39;, &#39;with&#39;, &#39;sort&#39;}</span> <label class="view-value-button pdoc-button" for="UNMERGABLE_ARGS-view-value"></label><span class="default_value">{&#39;into&#39;, &#39;qualify&#39;, &#39;offset&#39;, &#39;having&#39;, &#39;locks&#39;, &#39;windows&#39;, &#39;distinct&#39;, &#39;settings&#39;, &#39;match&#39;, &#39;cluster&#39;, &#39;sample&#39;, &#39;limit&#39;, &#39;pivots&#39;, &#39;distribute&#39;, &#39;sort&#39;, &#39;format&#39;, &#39;connect&#39;, &#39;laterals&#39;, &#39;options&#39;, &#39;group&#39;, &#39;prewhere&#39;, &#39;with&#39;, &#39;kind&#39;}</span>
</div> </div>

File diff suppressed because it is too large Load diff

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 one or more lines are too long

View file

@ -27,6 +27,7 @@ from sqlglot.expressions import (
cast as cast, cast as cast,
column as column, column as column,
condition as condition, condition as condition,
delete as delete,
except_ as except_, except_ as except_,
from_ as from_, from_ as from_,
func as func, func as func,

View file

@ -20,12 +20,40 @@ def _generate_as_hive(expression: exp.Expression) -> bool:
else: else:
return expression.kind != "VIEW" # CREATE VIEW is never Hive but CREATE SCHEMA etc is return expression.kind != "VIEW" # CREATE VIEW is never Hive but CREATE SCHEMA etc is
elif isinstance(expression, exp.Alter) or isinstance(expression, exp.Drop): # https://docs.aws.amazon.com/athena/latest/ug/ddl-reference.html
return True # all ALTER and DROP statements are Hive elif isinstance(expression, (exp.Alter, exp.Drop, exp.Describe)):
if isinstance(expression, exp.Drop) and expression.kind == "VIEW":
# DROP VIEW is Trino (I guess because CREATE VIEW is)
return False
# Everything else is Hive
return True
return False return False
def _location_property_sql(self: Athena.Generator, e: exp.LocationProperty):
# If table_type='iceberg', the LocationProperty is called 'location'
# Otherwise, it's called 'external_location'
# ref: https://docs.aws.amazon.com/athena/latest/ug/create-table-as.html
prop_name = "external_location"
if isinstance(e.parent, exp.Properties):
table_type_property = next(
(
p
for p in e.parent.expressions
if isinstance(p, exp.Property) and p.name == "table_type"
),
None,
)
if table_type_property and table_type_property.text("value") == "iceberg":
prop_name = "location"
return f"{prop_name}={self.sql(e, 'this')}"
class Athena(Trino): class Athena(Trino):
""" """
Over the years, it looks like AWS has taken various execution engines, bolted on AWS-specific modifications and then Over the years, it looks like AWS has taken various execution engines, bolted on AWS-specific modifications and then
@ -48,7 +76,7 @@ class Athena(Trino):
Trino: Trino:
- Uses double quotes to quote identifiers - Uses double quotes to quote identifiers
- Used for DDL operations that involve SELECT queries, eg: - Used for DDL operations that involve SELECT queries, eg:
- CREATE VIEW - CREATE VIEW / DROP VIEW
- CREATE TABLE... AS SELECT - CREATE TABLE... AS SELECT
- Used for DML operations - Used for DML operations
- SELECT, INSERT, UPDATE, DELETE, MERGE - SELECT, INSERT, UPDATE, DELETE, MERGE
@ -79,19 +107,32 @@ class Athena(Trino):
TokenType.USING: lambda self: self._parse_as_command(self._prev), TokenType.USING: lambda self: self._parse_as_command(self._prev),
} }
class _HiveGenerator(Hive.Generator):
def alter_sql(self, expression: exp.Alter) -> str:
# package any ALTER TABLE ADD actions into a Schema object
# so it gets generated as `ALTER TABLE .. ADD COLUMNS(...)`
# instead of `ALTER TABLE ... ADD COLUMN` which is invalid syntax on Athena
if isinstance(expression, exp.Alter) and expression.kind == "TABLE":
if expression.actions and isinstance(expression.actions[0], exp.ColumnDef):
new_actions = exp.Schema(expressions=expression.actions)
expression.set("actions", [new_actions])
return super().alter_sql(expression)
class Generator(Trino.Generator): class Generator(Trino.Generator):
""" """
Generate queries for the Athena Trino execution engine Generate queries for the Athena Trino execution engine
""" """
TYPE_MAPPING = { PROPERTIES_LOCATION = {
**Trino.Generator.TYPE_MAPPING, **Trino.Generator.PROPERTIES_LOCATION,
exp.DataType.Type.TEXT: "STRING", exp.LocationProperty: exp.Properties.Location.POST_WITH,
} }
TRANSFORMS = { TRANSFORMS = {
**Trino.Generator.TRANSFORMS, **Trino.Generator.TRANSFORMS,
exp.FileFormatProperty: lambda self, e: f"'FORMAT'={self.sql(e, 'this')}", exp.FileFormatProperty: lambda self, e: f"format={self.sql(e, 'this')}",
exp.LocationProperty: _location_property_sql,
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -99,7 +140,7 @@ class Athena(Trino):
hive_kwargs = {**kwargs, "dialect": "hive"} hive_kwargs = {**kwargs, "dialect": "hive"}
self._hive_generator = Hive.Generator(*args, **hive_kwargs) self._hive_generator = Athena._HiveGenerator(*args, **hive_kwargs)
def generate(self, expression: exp.Expression, copy: bool = True) -> str: def generate(self, expression: exp.Expression, copy: bool = True) -> str:
if _generate_as_hive(expression): if _generate_as_hive(expression):

View file

@ -214,6 +214,21 @@ def _build_datetime(args: t.List) -> exp.Func:
return exp.TimestampFromParts.from_arg_list(args) return exp.TimestampFromParts.from_arg_list(args)
def _build_regexp_extract(args: t.List) -> exp.RegexpExtract:
try:
group = re.compile(args[1].name).groups == 1
except re.error:
group = False
return exp.RegexpExtract(
this=seq_get(args, 0),
expression=seq_get(args, 1),
position=seq_get(args, 2),
occurrence=seq_get(args, 3),
group=exp.Literal.number(1) if group else None,
)
def _str_to_datetime_sql( def _str_to_datetime_sql(
self: BigQuery.Generator, expression: exp.StrToDate | exp.StrToTime self: BigQuery.Generator, expression: exp.StrToDate | exp.StrToTime
) -> str: ) -> str:
@ -377,13 +392,7 @@ class BigQuery(Dialect):
), ),
"PARSE_TIMESTAMP": _build_parse_timestamp, "PARSE_TIMESTAMP": _build_parse_timestamp,
"REGEXP_CONTAINS": exp.RegexpLike.from_arg_list, "REGEXP_CONTAINS": exp.RegexpLike.from_arg_list,
"REGEXP_EXTRACT": lambda args: exp.RegexpExtract( "REGEXP_EXTRACT": _build_regexp_extract,
this=seq_get(args, 0),
expression=seq_get(args, 1),
position=seq_get(args, 2),
occurrence=seq_get(args, 3),
group=exp.Literal.number(1) if re.compile(args[1].name).groups == 1 else None,
),
"SHA256": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(256)), "SHA256": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(256)),
"SHA512": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(512)), "SHA512": lambda args: exp.SHA2(this=seq_get(args, 0), length=exp.Literal.number(512)),
"SPLIT": lambda args: exp.Split( "SPLIT": lambda args: exp.Split(
@ -471,7 +480,7 @@ class BigQuery(Dialect):
table_name = this.name table_name = this.name
while self._match(TokenType.DASH, advance=False) and self._next: while self._match(TokenType.DASH, advance=False) and self._next:
text = "" text = ""
while self._curr and self._curr.token_type != TokenType.DOT: while self._is_connected() and self._curr.token_type != TokenType.DOT:
self._advance() self._advance()
text += self._prev.text text += self._prev.text
table_name += text table_name += text

View file

@ -396,6 +396,7 @@ class ClickHouse(Dialect):
**parser.Parser.FUNCTION_PARSERS, **parser.Parser.FUNCTION_PARSERS,
"ARRAYJOIN": lambda self: self.expression(exp.Explode, this=self._parse_expression()), "ARRAYJOIN": lambda self: self.expression(exp.Explode, this=self._parse_expression()),
"QUANTILE": lambda self: self._parse_quantile(), "QUANTILE": lambda self: self._parse_quantile(),
"COLUMNS": lambda self: self._parse_columns(),
} }
FUNCTION_PARSERS.pop("MATCH") FUNCTION_PARSERS.pop("MATCH")
@ -756,6 +757,34 @@ class ClickHouse(Dialect):
def _parse_constraint(self) -> t.Optional[exp.Expression]: def _parse_constraint(self) -> t.Optional[exp.Expression]:
return super()._parse_constraint() or self._parse_projection_def() return super()._parse_constraint() or self._parse_projection_def()
def _parse_alias(
self, this: t.Optional[exp.Expression], explicit: bool = False
) -> t.Optional[exp.Expression]:
# In clickhouse "SELECT <expr> APPLY(...)" is a query modifier,
# so "APPLY" shouldn't be parsed as <expr>'s alias. However, "SELECT <expr> apply" is a valid alias
if self._match_pair(TokenType.APPLY, TokenType.L_PAREN, advance=False):
return this
return super()._parse_alias(this=this, explicit=explicit)
def _parse_expression(self) -> t.Optional[exp.Expression]:
this = super()._parse_expression()
# Clickhouse allows "SELECT <expr> [APPLY(func)] [...]]" modifier
while self._match_pair(TokenType.APPLY, TokenType.L_PAREN):
this = exp.Apply(this=this, expression=self._parse_var(any_token=True))
self._match(TokenType.R_PAREN)
return this
def _parse_columns(self) -> exp.Expression:
this: exp.Expression = self.expression(exp.Columns, this=self._parse_lambda())
while self._next and self._match_text_seq(")", "APPLY", "("):
self._match(TokenType.R_PAREN)
this = exp.Apply(this=this, expression=self._parse_var(any_token=True))
return this
class Generator(generator.Generator): class Generator(generator.Generator):
QUERY_HINTS = False QUERY_HINTS = False
STRUCT_DELIMITER = ("(", ")") STRUCT_DELIMITER = ("(", ")")
@ -898,9 +927,10 @@ class ClickHouse(Dialect):
PROPERTIES_LOCATION = { PROPERTIES_LOCATION = {
**generator.Generator.PROPERTIES_LOCATION, **generator.Generator.PROPERTIES_LOCATION,
exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
exp.OnCluster: exp.Properties.Location.POST_NAME, exp.OnCluster: exp.Properties.Location.POST_NAME,
exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA,
exp.ToTableProperty: exp.Properties.Location.POST_NAME,
exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
} }
# There's no list in docs, but it can be found in Clickhouse code # There's no list in docs, but it can be found in Clickhouse code
@ -1069,7 +1099,9 @@ class ClickHouse(Dialect):
[self.sql(prop) for prop in locations[exp.Properties.Location.POST_NAME]] [self.sql(prop) for prop in locations[exp.Properties.Location.POST_NAME]]
) )
this_schema = self.schema_columns_sql(expression.this) this_schema = self.schema_columns_sql(expression.this)
return f"{this_name}{self.sep()}{this_properties}{self.sep()}{this_schema}" this_schema = f"{self.sep()}{this_schema}" if this_schema else ""
return f"{this_name}{self.sep()}{this_properties}{this_schema}"
return super().createable_sql(expression, locations) return super().createable_sql(expression, locations)

View file

@ -546,7 +546,7 @@ class Hive(Dialect):
exp.SchemaCommentProperty: lambda self, e: self.naked_property(e), exp.SchemaCommentProperty: lambda self, e: self.naked_property(e),
exp.ArrayUniqueAgg: rename_func("COLLECT_SET"), exp.ArrayUniqueAgg: rename_func("COLLECT_SET"),
exp.Split: lambda self, e: self.func( exp.Split: lambda self, e: self.func(
"SPLIT", e.this, self.func("CONCAT", "'\\\\Q'", e.expression) "SPLIT", e.this, self.func("CONCAT", "'\\\\Q'", e.expression, "'\\\\E'")
), ),
exp.Select: transforms.preprocess( exp.Select: transforms.preprocess(
[ [

View file

@ -62,6 +62,7 @@ def diff(
source: exp.Expression, source: exp.Expression,
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,
**kwargs: t.Any, **kwargs: t.Any,
) -> t.List[Edit]: ) -> t.List[Edit]:
""" """
@ -89,6 +90,8 @@ def diff(
heuristics produce better results for subtrees that are known by a caller to be matching. heuristics produce better results for subtrees that are known by a caller to be matching.
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 source / target trees. referenced in source / target trees.
delta_only: excludes all `Keep` nodes from the diff.
kwargs: additional arguments to pass to the ChangeDistiller instance.
Returns: Returns:
the list of Insert, Remove, Move, Update and Keep objects for each node in the source and the the list of Insert, Remove, Move, Update and Keep objects for each node in the source and the
@ -116,7 +119,12 @@ def diff(
} }
matchings_copy = [(node_mappings[id(s)], node_mappings[id(t)]) for s, t in matchings] matchings_copy = [(node_mappings[id(s)], node_mappings[id(t)]) for s, t in matchings]
return ChangeDistiller(**kwargs).diff(source_copy, target_copy, matchings=matchings_copy) return ChangeDistiller(**kwargs).diff(
source_copy,
target_copy,
matchings=matchings_copy,
delta_only=delta_only,
)
# The expression types for which Update edits are allowed. # The expression types for which Update edits are allowed.
@ -149,6 +157,7 @@ class ChangeDistiller:
source: exp.Expression, source: exp.Expression,
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,
) -> 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}
@ -168,9 +177,13 @@ class ChangeDistiller:
self._bigram_histo_cache: t.Dict[int, t.DefaultDict[str, int]] = {} self._bigram_histo_cache: t.Dict[int, t.DefaultDict[str, int]] = {}
matching_set = self._compute_matching_set() | {(s, t) for s, t in pre_matched_nodes.items()} matching_set = self._compute_matching_set() | {(s, t) for s, t in pre_matched_nodes.items()}
return self._generate_edit_script(matching_set) return self._generate_edit_script(matching_set, delta_only)
def _generate_edit_script(self, matching_set: t.Set[t.Tuple[int, int]]) -> t.List[Edit]: def _generate_edit_script(
self,
matching_set: t.Set[t.Tuple[int, int]],
delta_only: bool,
) -> t.List[Edit]:
edit_script: t.List[Edit] = [] edit_script: t.List[Edit] = []
for removed_node_id in self._unmatched_source_nodes: for removed_node_id in self._unmatched_source_nodes:
edit_script.append(Remove(self._source_index[removed_node_id])) edit_script.append(Remove(self._source_index[removed_node_id]))
@ -186,7 +199,8 @@ class ChangeDistiller:
edit_script.extend( edit_script.extend(
self._generate_move_edits(source_node, target_node, matching_set) self._generate_move_edits(source_node, target_node, matching_set)
) )
edit_script.append(Keep(source_node, target_node)) if not delta_only:
edit_script.append(Keep(source_node, target_node))
else: else:
edit_script.append(Update(source_node, target_node)) edit_script.append(Update(source_node, target_node))

View file

@ -11,7 +11,6 @@ SQL expressions, such as `sqlglot.expressions.select`.
""" """
from __future__ import annotations from __future__ import annotations
import datetime import datetime
import math import math
import numbers import numbers
@ -36,6 +35,7 @@ from sqlglot.helper import (
from sqlglot.tokens import Token, TokenError from sqlglot.tokens import Token, TokenError
if t.TYPE_CHECKING: if t.TYPE_CHECKING:
from typing_extensions import Self
from sqlglot._typing import E, Lit from sqlglot._typing import E, Lit
from sqlglot.dialects.dialect import DialectType from sqlglot.dialects.dialect import DialectType
@ -1368,7 +1368,7 @@ class DML(Expression):
dialect: DialectType = None, dialect: DialectType = None,
copy: bool = True, copy: bool = True,
**opts, **opts,
) -> DML: ) -> "Self":
""" """
Set the RETURNING expression. Not supported by all dialects. Set the RETURNING expression. Not supported by all dialects.
@ -2314,6 +2314,16 @@ class Fetch(Expression):
} }
class Grant(Expression):
arg_types = {
"privileges": True,
"kind": False,
"securable": True,
"principals": True,
"grant_option": False,
}
class Group(Expression): class Group(Expression):
arg_types = { arg_types = {
"expressions": False, "expressions": False,
@ -2570,6 +2580,14 @@ class Property(Expression):
arg_types = {"this": True, "value": True} arg_types = {"this": True, "value": True}
class GrantPrivilege(Expression):
arg_types = {"this": True, "expressions": False}
class GrantPrincipal(Expression):
arg_types = {"this": True, "kind": False}
class AllowedValuesProperty(Expression): class AllowedValuesProperty(Expression):
arg_types = {"expressions": True} arg_types = {"expressions": True}
@ -4123,6 +4141,7 @@ class DataType(Expression):
NUMRANGE = auto() NUMRANGE = auto()
NVARCHAR = auto() NVARCHAR = auto()
OBJECT = auto() OBJECT = auto()
RANGE = auto()
ROWVERSION = auto() ROWVERSION = auto()
SERIAL = auto() SERIAL = auto()
SET = auto() SET = auto()
@ -4154,6 +4173,7 @@ class DataType(Expression):
UINT256 = auto() UINT256 = auto()
UMEDIUMINT = auto() UMEDIUMINT = auto()
UDECIMAL = auto() UDECIMAL = auto()
UNION = auto()
UNIQUEIDENTIFIER = auto() UNIQUEIDENTIFIER = auto()
UNKNOWN = auto() # Sentinel value, useful for type annotation UNKNOWN = auto() # Sentinel value, useful for type annotation
USERDEFINED = "USER-DEFINED" USERDEFINED = "USER-DEFINED"
@ -4172,6 +4192,7 @@ class DataType(Expression):
Type.NESTED, Type.NESTED,
Type.OBJECT, Type.OBJECT,
Type.STRUCT, Type.STRUCT,
Type.UNION,
} }
ARRAY_TYPES = { ARRAY_TYPES = {
@ -4396,6 +4417,15 @@ class Alter(Expression):
"not_valid": False, "not_valid": False,
} }
@property
def kind(self) -> t.Optional[str]:
kind = self.args.get("kind")
return kind and kind.upper()
@property
def actions(self) -> t.List[Expression]:
return self.args.get("actions") or []
class AddConstraint(Expression): class AddConstraint(Expression):
arg_types = {"expressions": True} arg_types = {"expressions": True}
@ -4911,6 +4941,10 @@ class ApproxDistinct(AggFunc):
_sql_names = ["APPROX_DISTINCT", "APPROX_COUNT_DISTINCT"] _sql_names = ["APPROX_DISTINCT", "APPROX_COUNT_DISTINCT"]
class Apply(Func):
arg_types = {"this": True, "expression": True}
class Array(Func): class Array(Func):
arg_types = {"expressions": False, "bracket_notation": False} arg_types = {"expressions": False, "bracket_notation": False}
is_var_len_args = True is_var_len_args = True
@ -4950,6 +4984,10 @@ class ToNumber(Func):
} }
class Columns(Func):
arg_types = {"this": True, "unpack": False}
# https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver16#syntax # https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver16#syntax
class Convert(Func): class Convert(Func):
arg_types = {"this": True, "expression": True, "style": False} arg_types = {"this": True, "expression": True, "style": False}
@ -5875,6 +5913,10 @@ class Normalize(Func):
arg_types = {"this": True, "form": False} arg_types = {"this": True, "form": False}
class Overlay(Func):
arg_types = {"this": True, "expression": True, "from": True, "for": False}
# https://cloud.google.com/bigquery/docs/reference/standard-sql/bigqueryml-syntax-predict#mlpredict_function # https://cloud.google.com/bigquery/docs/reference/standard-sql/bigqueryml-syntax-predict#mlpredict_function
class Predict(Func): class Predict(Func):
arg_types = {"this": True, "expression": True, "params_struct": False} arg_types = {"this": True, "expression": True, "params_struct": False}
@ -6007,6 +6049,7 @@ class Split(Func):
# Start may be omitted in the case of postgres # Start may be omitted in the case of postgres
# https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6 # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
class Substring(Func): class Substring(Func):
_sql_names = ["SUBSTRING", "SUBSTR"]
arg_types = {"this": True, "start": False, "length": False} arg_types = {"this": True, "start": False, "length": False}
@ -6209,10 +6252,6 @@ class UnixToTimeStr(Func):
pass pass
class UnpackColumns(Func):
pass
class Uuid(Func): class Uuid(Func):
_sql_names = ["UUID", "GEN_RANDOM_UUID", "GENERATE_UUID", "UUID_STRING"] _sql_names = ["UUID", "GEN_RANDOM_UUID", "GENERATE_UUID", "UUID_STRING"]
@ -6274,7 +6313,7 @@ class Use(Expression):
arg_types = {"this": True, "kind": False} arg_types = {"this": True, "kind": False}
class Merge(Expression): class Merge(DML):
arg_types = { arg_types = {
"this": True, "this": True,
"using": True, "using": True,
@ -6838,9 +6877,7 @@ def delete(
if where: if where:
delete_expr = delete_expr.where(where, dialect=dialect, copy=False, **opts) delete_expr = delete_expr.where(where, dialect=dialect, copy=False, **opts)
if returning: if returning:
delete_expr = t.cast( delete_expr = delete_expr.returning(returning, dialect=dialect, copy=False, **opts)
Delete, delete_expr.returning(returning, dialect=dialect, copy=False, **opts)
)
return delete_expr return delete_expr
@ -6883,7 +6920,7 @@ def insert(
insert = Insert(this=this, expression=expr, overwrite=overwrite) insert = Insert(this=this, expression=expr, overwrite=overwrite)
if returning: if returning:
insert = t.cast(Insert, insert.returning(returning, dialect=dialect, copy=False, **opts)) insert = insert.returning(returning, dialect=dialect, copy=False, **opts)
return insert return insert
@ -6893,6 +6930,7 @@ def merge(
into: ExpOrStr, into: ExpOrStr,
using: ExpOrStr, using: ExpOrStr,
on: ExpOrStr, on: ExpOrStr,
returning: t.Optional[ExpOrStr] = None,
dialect: DialectType = None, dialect: DialectType = None,
copy: bool = True, copy: bool = True,
**opts, **opts,
@ -6913,6 +6951,7 @@ def merge(
into: The target table to merge data into. into: The target table to merge data into.
using: The source table to merge data from. using: The source table to merge data from.
on: The join condition for the merge. on: The join condition for the merge.
returning: The columns to return from the merge.
dialect: The dialect used to parse the input expressions. dialect: The dialect used to parse the input expressions.
copy: Whether to copy the expression. copy: Whether to copy the expression.
**opts: Other options to use to parse the input expressions. **opts: Other options to use to parse the input expressions.
@ -6920,7 +6959,7 @@ def merge(
Returns: Returns:
Merge: The syntax tree for the MERGE statement. Merge: The syntax tree for the MERGE statement.
""" """
return Merge( merge = Merge(
this=maybe_parse(into, dialect=dialect, copy=copy, **opts), this=maybe_parse(into, dialect=dialect, copy=copy, **opts),
using=maybe_parse(using, dialect=dialect, copy=copy, **opts), using=maybe_parse(using, dialect=dialect, copy=copy, **opts),
on=maybe_parse(on, dialect=dialect, copy=copy, **opts), on=maybe_parse(on, dialect=dialect, copy=copy, **opts),
@ -6929,6 +6968,10 @@ def merge(
for when_expr in when_exprs for when_expr in when_exprs
], ],
) )
if returning:
merge = merge.returning(returning, dialect=dialect, copy=False, **opts)
return merge
def condition( def condition(

View file

@ -192,7 +192,6 @@ class Generator(metaclass=_Generator):
exp.TransientProperty: lambda *_: "TRANSIENT", exp.TransientProperty: lambda *_: "TRANSIENT",
exp.Union: lambda self, e: self.set_operations(e), exp.Union: lambda self, e: self.set_operations(e),
exp.UnloggedProperty: lambda *_: "UNLOGGED", exp.UnloggedProperty: lambda *_: "UNLOGGED",
exp.UnpackColumns: lambda self, e: f"*{self.sql(e.this)}",
exp.Uuid: lambda *_: "UUID()", exp.Uuid: lambda *_: "UUID()",
exp.UppercaseColumnConstraint: lambda *_: "UPPERCASE", exp.UppercaseColumnConstraint: lambda *_: "UPPERCASE",
exp.VarMap: lambda self, e: self.func("MAP", e.args["keys"], e.args["values"]), exp.VarMap: lambda self, e: self.func("MAP", e.args["keys"], e.args["values"]),
@ -2002,7 +2001,8 @@ class Generator(metaclass=_Generator):
values = f"VALUES{self.seg('')}{args}" values = f"VALUES{self.seg('')}{args}"
values = ( values = (
f"({values})" f"({values})"
if self.WRAP_DERIVED_VALUES and (alias or isinstance(expression.parent, exp.From)) if self.WRAP_DERIVED_VALUES
and (alias or isinstance(expression.parent, (exp.From, exp.Table)))
else values else values
) )
return f"{values} AS {alias}" if alias else values return f"{values} AS {alias}" if alias else values
@ -3625,13 +3625,15 @@ class Generator(metaclass=_Generator):
using = f"USING {self.sql(expression, 'using')}" using = f"USING {self.sql(expression, 'using')}"
on = f"ON {self.sql(expression, 'on')}" on = f"ON {self.sql(expression, 'on')}"
expressions = self.expressions(expression, sep=" ", indent=False) expressions = self.expressions(expression, sep=" ", indent=False)
returning = self.sql(expression, "returning")
if returning:
expressions = f"{expressions}{returning}"
sep = self.sep() sep = self.sep()
returning = self.expressions(expression, key="returning", indent=False)
returning = f"RETURNING {returning}" if returning else ""
return self.prepend_ctes( return self.prepend_ctes(
expression, expression,
f"MERGE INTO {this}{table_alias}{sep}{using}{sep}{on}{sep}{expressions}{sep}{returning}", f"MERGE INTO {this}{table_alias}{sep}{using}{sep}{on}{sep}{expressions}",
) )
@unsupported_args("format") @unsupported_args("format")
@ -4323,6 +4325,65 @@ class Generator(metaclass=_Generator):
parent_cond = parent.expression.this parent_cond = parent.expression.this
parent_cond.replace(parent_cond.and_(expression.this.is_(exp.null()).not_())) parent_cond.replace(parent_cond.and_(expression.this.is_(exp.null()).not_()))
else: else:
array_agg = f"{array_agg} FILTER(WHERE {self.sql(expression, 'this')} IS NOT NULL)" # DISTINCT is already present in the agg function, do not propagate it to FILTER as well
this = expression.this
this_sql = (
self.expressions(this)
if isinstance(this, exp.Distinct)
else self.sql(expression, "this")
)
array_agg = f"{array_agg} FILTER(WHERE {this_sql} IS NOT NULL)"
return array_agg return array_agg
def apply_sql(self, expression: exp.Apply) -> str:
this = self.sql(expression, "this")
expr = self.sql(expression, "expression")
return f"{this} APPLY({expr})"
def grant_sql(self, expression: exp.Grant) -> str:
privileges_sql = self.expressions(expression, key="privileges", flat=True)
kind = self.sql(expression, "kind")
kind = f" {kind}" if kind else ""
securable = self.sql(expression, "securable")
securable = f" {securable}" if securable else ""
principals = self.expressions(expression, key="principals", flat=True)
grant_option = " WITH GRANT OPTION" if expression.args.get("grant_option") else ""
return f"GRANT {privileges_sql} ON{kind}{securable} TO {principals}{grant_option}"
def grantprivilege_sql(self, expression: exp.GrantPrivilege):
this = self.sql(expression, "this")
columns = self.expressions(expression, flat=True)
columns = f"({columns})" if columns else ""
return f"{this}{columns}"
def grantprincipal_sql(self, expression: exp.GrantPrincipal):
this = self.sql(expression, "this")
kind = self.sql(expression, "kind")
kind = f"{kind} " if kind else ""
return f"{kind}{this}"
def columns_sql(self, expression: exp.Columns):
func = self.function_fallback_sql(expression)
if expression.args.get("unpack"):
func = f"*{func}"
return func
def overlay_sql(self, expression: exp.Overlay):
this = self.sql(expression, "this")
expr = self.sql(expression, "expression")
from_sql = self.sql(expression, "from")
for_sql = self.sql(expression, "for")
for_sql = f" FOR {for_sql}" if for_sql else ""
return f"OVERLAY({this} PLACING {expr} FROM {from_sql}{for_sql})"

View file

@ -1070,7 +1070,11 @@ def sort_comparison(expression: exp.Expression) -> exp.Expression:
l_const = _is_constant(l) l_const = _is_constant(l)
r_const = _is_constant(r) r_const = _is_constant(r)
if (l_column and not r_column) or (r_const and not l_const): if (
(l_column and not r_column)
or (r_const and not l_const)
or isinstance(r, exp.SubqueryPredicate)
):
return expression return expression
if (r_column and not l_column) or (l_const and not r_const) or (gen(l) > gen(r)): if (r_column and not l_column) or (l_const and not r_const) or (gen(l) > gen(r)):
return INVERSE_COMPARISONS.get(expression.__class__, expression.__class__)( return INVERSE_COMPARISONS.get(expression.__class__, expression.__class__)(

View file

@ -260,6 +260,7 @@ class Parser(metaclass=_Parser):
TokenType.NESTED, TokenType.NESTED,
TokenType.OBJECT, TokenType.OBJECT,
TokenType.STRUCT, TokenType.STRUCT,
TokenType.UNION,
} }
NESTED_TYPE_TOKENS = { NESTED_TYPE_TOKENS = {
@ -268,6 +269,7 @@ class Parser(metaclass=_Parser):
TokenType.LOWCARDINALITY, TokenType.LOWCARDINALITY,
TokenType.MAP, TokenType.MAP,
TokenType.NULLABLE, TokenType.NULLABLE,
TokenType.RANGE,
*STRUCT_TYPE_TOKENS, *STRUCT_TYPE_TOKENS,
} }
@ -522,6 +524,7 @@ class Parser(metaclass=_Parser):
*TYPE_TOKENS, *TYPE_TOKENS,
*NO_PAREN_FUNCTIONS, *NO_PAREN_FUNCTIONS,
} }
ID_VAR_TOKENS.remove(TokenType.UNION)
INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END} INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
@ -777,6 +780,7 @@ class Parser(metaclass=_Parser):
TokenType.DESC: lambda self: self._parse_describe(), TokenType.DESC: lambda self: self._parse_describe(),
TokenType.DESCRIBE: lambda self: self._parse_describe(), TokenType.DESCRIBE: lambda self: self._parse_describe(),
TokenType.DROP: lambda self: self._parse_drop(), TokenType.DROP: lambda self: self._parse_drop(),
TokenType.GRANT: lambda self: self._parse_grant(),
TokenType.INSERT: lambda self: self._parse_insert(), TokenType.INSERT: lambda self: self._parse_insert(),
TokenType.KILL: lambda self: self._parse_kill(), TokenType.KILL: lambda self: self._parse_kill(),
TokenType.LOAD: lambda self: self._parse_load(), TokenType.LOAD: lambda self: self._parse_load(),
@ -1103,6 +1107,7 @@ class Parser(metaclass=_Parser):
"MATCH": lambda self: self._parse_match_against(), "MATCH": lambda self: self._parse_match_against(),
"NORMALIZE": lambda self: self._parse_normalize(), "NORMALIZE": lambda self: self._parse_normalize(),
"OPENJSON": lambda self: self._parse_open_json(), "OPENJSON": lambda self: self._parse_open_json(),
"OVERLAY": lambda self: self._parse_overlay(),
"POSITION": lambda self: self._parse_position(), "POSITION": lambda self: self._parse_position(),
"PREDICT": lambda self: self._parse_predict(), "PREDICT": lambda self: self._parse_predict(),
"SAFE_CAST": lambda self: self._parse_cast(False, safe=True), "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
@ -1276,6 +1281,8 @@ class Parser(metaclass=_Parser):
ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"} ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"}
PRIVILEGE_FOLLOW_TOKENS = {TokenType.ON, TokenType.COMMA, TokenType.L_PAREN}
STRICT_CAST = True STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False PREFIXED_PIVOT_COLUMNS = False
@ -2982,6 +2989,13 @@ class Parser(metaclass=_Parser):
if table if table
else self._parse_select(nested=True, parse_set_operation=False) else self._parse_select(nested=True, parse_set_operation=False)
) )
# Transform exp.Values into a exp.Table to pass through parse_query_modifiers
# in case a modifier (e.g. join) is following
if table and isinstance(this, exp.Values) and this.alias:
alias = this.args["alias"].pop()
this = exp.Table(this=this, alias=alias)
this = self._parse_query_modifiers(self._parse_set_operations(this)) this = self._parse_query_modifiers(self._parse_set_operations(this))
self._match_r_paren() self._match_r_paren()
@ -4341,6 +4355,9 @@ class Parser(metaclass=_Parser):
) )
while self._match_set(self.ASSIGNMENT): while self._match_set(self.ASSIGNMENT):
if isinstance(this, exp.Column) and len(this.parts) == 1:
this = this.this
this = self.expression( this = self.expression(
self.ASSIGNMENT[self._prev.token_type], self.ASSIGNMENT[self._prev.token_type],
this=this, this=this,
@ -5034,7 +5051,7 @@ class Parser(metaclass=_Parser):
if not field: if not field:
self.raise_error("Expected type") self.raise_error("Expected type")
elif op and self._curr: elif op and self._curr:
field = self._parse_column_reference() field = self._parse_column_reference() or self._parse_bracket()
else: else:
field = self._parse_field(any_token=True, anonymous_func=True) field = self._parse_field(any_token=True, anonymous_func=True)
@ -6841,7 +6858,7 @@ class Parser(metaclass=_Parser):
using=using, using=using,
on=on, on=on,
expressions=self._parse_when_matched(), expressions=self._parse_when_matched(),
returning=self._match(TokenType.RETURNING) and self._parse_csv(self._parse_bitwise), returning=self._parse_returning(),
) )
def _parse_when_matched(self) -> t.List[exp.When]: def _parse_when_matched(self) -> t.List[exp.When]:
@ -7384,9 +7401,12 @@ class Parser(metaclass=_Parser):
form=self._match(TokenType.COMMA) and self._parse_var(), form=self._match(TokenType.COMMA) and self._parse_var(),
) )
def _parse_star_ops(self) -> exp.Star | exp.UnpackColumns: def _parse_star_ops(self) -> t.Optional[exp.Expression]:
if self._match_text_seq("COLUMNS", "(", advance=False): if self._match_text_seq("COLUMNS", "(", advance=False):
return exp.UnpackColumns(this=self._parse_function()) this = self._parse_function()
if isinstance(this, exp.Columns):
this.set("unpack", True)
return this
return self.expression( return self.expression(
exp.Star, exp.Star,
@ -7396,3 +7416,72 @@ class Parser(metaclass=_Parser):
"rename": self._parse_star_op("RENAME"), "rename": self._parse_star_op("RENAME"),
}, },
) )
def _parse_grant_privilege(self) -> t.Optional[exp.GrantPrivilege]:
privilege_parts = []
# Keep consuming consecutive keywords until comma (end of this privilege) or ON
# (end of privilege list) or L_PAREN (start of column list) are met
while self._curr and not self._match_set(self.PRIVILEGE_FOLLOW_TOKENS, advance=False):
privilege_parts.append(self._curr.text.upper())
self._advance()
this = exp.var(" ".join(privilege_parts))
expressions = (
self._parse_wrapped_csv(self._parse_column)
if self._match(TokenType.L_PAREN, advance=False)
else None
)
return self.expression(exp.GrantPrivilege, this=this, expressions=expressions)
def _parse_grant_principal(self) -> t.Optional[exp.GrantPrincipal]:
kind = self._match_texts(("ROLE", "GROUP")) and self._prev.text.upper()
principal = self._parse_id_var()
if not principal:
return None
return self.expression(exp.GrantPrincipal, this=principal, kind=kind)
def _parse_grant(self) -> exp.Grant | exp.Command:
start = self._prev
privileges = self._parse_csv(self._parse_grant_privilege)
self._match(TokenType.ON)
kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
# Attempt to parse the securable e.g. MySQL allows names
# such as "foo.*", "*.*" which are not easily parseable yet
securable = self._try_parse(self._parse_table_parts)
if not securable or not self._match_text_seq("TO"):
return self._parse_as_command(start)
principals = self._parse_csv(self._parse_grant_principal)
grant_option = self._match_text_seq("WITH", "GRANT", "OPTION")
if self._curr:
return self._parse_as_command(start)
return self.expression(
exp.Grant,
privileges=privileges,
kind=kind,
securable=securable,
principals=principals,
grant_option=grant_option,
)
def _parse_overlay(self) -> exp.Overlay:
return self.expression(
exp.Overlay,
**{ # type: ignore
"this": self._parse_bitwise(),
"expression": self._match_text_seq("PLACING") and self._parse_bitwise(),
"from": self._match_text_seq("FROM") and self._parse_bitwise(),
"for": self._match_text_seq("FOR") and self._parse_bitwise(),
},
)

View file

@ -270,6 +270,7 @@ class TokenType(AutoName):
FUNCTION = auto() FUNCTION = auto()
GLOB = auto() GLOB = auto()
GLOBAL = auto() GLOBAL = auto()
GRANT = auto()
GROUP_BY = auto() GROUP_BY = auto()
GROUPING_SETS = auto() GROUPING_SETS = auto()
HAVING = auto() HAVING = auto()
@ -903,7 +904,7 @@ class Tokenizer(metaclass=_Tokenizer):
"CALL": TokenType.COMMAND, "CALL": TokenType.COMMAND,
"COMMENT": TokenType.COMMENT, "COMMENT": TokenType.COMMENT,
"EXPLAIN": TokenType.COMMAND, "EXPLAIN": TokenType.COMMAND,
"GRANT": TokenType.COMMAND, "GRANT": TokenType.GRANT,
"OPTIMIZE": TokenType.COMMAND, "OPTIMIZE": TokenType.COMMAND,
"PREPARE": TokenType.COMMAND, "PREPARE": TokenType.COMMAND,
"VACUUM": TokenType.COMMAND, "VACUUM": TokenType.COMMAND,

View file

@ -1,3 +1,4 @@
from sqlglot import exp
from tests.dialects.test_dialect import Validator from tests.dialects.test_dialect import Validator
@ -68,6 +69,23 @@ class TestAthena(Validator):
"CREATE TABLE foo AS WITH foo AS (SELECT a, b FROM bar) SELECT * FROM foo" "CREATE TABLE foo AS WITH foo AS (SELECT a, b FROM bar) SELECT * FROM foo"
) )
# ALTER TABLE ADD COLUMN not supported, it needs to be generated as ALTER TABLE ADD COLUMNS
self.validate_identity(
"ALTER TABLE `foo`.`bar` ADD COLUMN `end_ts` BIGINT",
write_sql="ALTER TABLE `foo`.`bar` ADD COLUMNS (`end_ts` BIGINT)",
)
def test_dml(self):
self.validate_all(
"SELECT CAST(ds AS VARCHAR) AS ds FROM (VALUES ('2022-01-01')) AS t(ds)",
read={"": "SELECT CAST(ds AS STRING) AS ds FROM (VALUES ('2022-01-01')) AS t(ds)"},
write={
"hive": "SELECT CAST(ds AS STRING) AS ds FROM (VALUES ('2022-01-01')) AS t(ds)",
"trino": "SELECT CAST(ds AS VARCHAR) AS ds FROM (VALUES ('2022-01-01')) AS t(ds)",
"athena": "SELECT CAST(ds AS VARCHAR) AS ds FROM (VALUES ('2022-01-01')) AS t(ds)",
},
)
def test_ddl_quoting(self): def test_ddl_quoting(self):
self.validate_identity("CREATE SCHEMA `foo`") self.validate_identity("CREATE SCHEMA `foo`")
self.validate_identity("CREATE SCHEMA foo") self.validate_identity("CREATE SCHEMA foo")
@ -111,6 +129,10 @@ class TestAthena(Validator):
'CREATE VIEW `foo` AS SELECT "id" FROM `tbl`', 'CREATE VIEW `foo` AS SELECT "id" FROM `tbl`',
write_sql='CREATE VIEW "foo" AS SELECT "id" FROM "tbl"', write_sql='CREATE VIEW "foo" AS SELECT "id" FROM "tbl"',
) )
self.validate_identity(
"DROP VIEW IF EXISTS `foo`.`bar`",
write_sql='DROP VIEW IF EXISTS "foo"."bar"',
)
self.validate_identity( self.validate_identity(
'ALTER TABLE "foo" ADD COLUMNS ("id" STRING)', 'ALTER TABLE "foo" ADD COLUMNS ("id" STRING)',
@ -128,6 +150,8 @@ class TestAthena(Validator):
write_sql='CREATE TABLE "foo" AS WITH "foo" AS (SELECT "a", "b" FROM "bar") SELECT * FROM "foo"', write_sql='CREATE TABLE "foo" AS WITH "foo" AS (SELECT "a", "b" FROM "bar") SELECT * FROM "foo"',
) )
self.validate_identity("DESCRIBE foo.bar", write_sql="DESCRIBE `foo`.`bar`", identify=True)
def test_dml_quoting(self): def test_dml_quoting(self):
self.validate_identity("SELECT a AS foo FROM tbl") self.validate_identity("SELECT a AS foo FROM tbl")
self.validate_identity('SELECT "a" AS "foo" FROM "tbl"') self.validate_identity('SELECT "a" AS "foo" FROM "tbl"')
@ -167,3 +191,39 @@ class TestAthena(Validator):
write_sql='WITH "foo" AS (SELECT "a", "b" FROM "bar") SELECT * FROM "foo"', write_sql='WITH "foo" AS (SELECT "a", "b" FROM "bar") SELECT * FROM "foo"',
identify=True, identify=True,
) )
def test_ctas(self):
# Hive tables use 'external_location' to specify the table location, Iceberg tables use 'location' to specify the table location
# The 'table_type' property is used to determine if it's a Hive or an Iceberg table
# ref: https://docs.aws.amazon.com/athena/latest/ug/create-table-as.html#ctas-table-properties
ctas_hive = exp.Create(
this=exp.to_table("foo.bar"),
kind="TABLE",
properties=exp.Properties(
expressions=[
exp.FileFormatProperty(this=exp.Literal.string("parquet")),
exp.LocationProperty(this=exp.Literal.string("s3://foo")),
]
),
expression=exp.select("1"),
)
self.assertEqual(
ctas_hive.sql(dialect=self.dialect, identify=True),
"CREATE TABLE \"foo\".\"bar\" WITH (format='parquet', external_location='s3://foo') AS SELECT 1",
)
ctas_iceberg = exp.Create(
this=exp.to_table("foo.bar"),
kind="TABLE",
properties=exp.Properties(
expressions=[
exp.Property(this=exp.var("table_type"), value=exp.Literal.string("iceberg")),
exp.LocationProperty(this=exp.Literal.string("s3://foo")),
]
),
expression=exp.select("1"),
)
self.assertEqual(
ctas_iceberg.sql(dialect=self.dialect, identify=True),
"CREATE TABLE \"foo\".\"bar\" WITH (table_type='iceberg', location='s3://foo') AS SELECT 1",
)

View file

@ -22,6 +22,8 @@ class TestBigQuery(Validator):
maxDiff = None maxDiff = None
def test_bigquery(self): def test_bigquery(self):
self.validate_identity("REGEXP_EXTRACT(x, '(?<)')")
self.validate_all( self.validate_all(
"EXTRACT(HOUR FROM DATETIME(2008, 12, 25, 15, 30, 00))", "EXTRACT(HOUR FROM DATETIME(2008, 12, 25, 15, 30, 00))",
write={ write={
@ -1502,6 +1504,8 @@ WHERE
}, },
) )
self.validate_identity("SELECT * FROM a-b c", "SELECT * FROM a-b AS c")
def test_errors(self): def test_errors(self):
with self.assertRaises(TokenError): with self.assertRaises(TokenError):
transpile("'\\'", read="bigquery") transpile("'\\'", read="bigquery")
@ -1958,3 +1962,26 @@ OPTIONS (
"duckdb": "WITH Races AS (SELECT '800M' AS race) SELECT race, participant FROM Races AS r CROSS JOIN (SELECT UNNEST([{'name': 'Rudisha', 'laps': [23.4, 26.3, 26.4, 26.1]}], max_depth => 2)) AS participant", "duckdb": "WITH Races AS (SELECT '800M' AS race) SELECT race, participant FROM Races AS r CROSS JOIN (SELECT UNNEST([{'name': 'Rudisha', 'laps': [23.4, 26.3, 26.4, 26.1]}], max_depth => 2)) AS participant",
}, },
) )
def test_range_type(self):
for type, value in (
("RANGE<DATE>", "'[2020-01-01, 2020-12-31)'"),
("RANGE<DATE>", "'[UNBOUNDED, 2020-12-31)'"),
("RANGE<DATETIME>", "'[2020-01-01 12:00:00, 2020-12-31 12:00:00)'"),
("RANGE<TIMESTAMP>", "'[2020-10-01 12:00:00+08, 2020-12-31 12:00:00+08)'"),
):
with self.subTest(f"Testing BigQuery's RANGE<T> type: {type} {value}"):
self.validate_identity(f"SELECT {type} {value}", f"SELECT CAST({value} AS {type})")
self.assertEqual(self.parse_one(type), exp.DataType.build(type, dialect="bigquery"))
self.validate_identity(
"SELECT RANGE(CAST('2022-12-01' AS DATE), CAST('2022-12-31' AS DATE))"
)
self.validate_identity("SELECT RANGE(NULL, CAST('2022-12-31' AS DATE))")
self.validate_identity(
"SELECT RANGE(CAST('2022-10-01 14:53:27' AS DATETIME), CAST('2022-10-01 16:00:00' AS DATETIME))"
)
self.validate_identity(
"SELECT RANGE(CAST('2022-10-01 14:53:27 America/Los_Angeles' AS TIMESTAMP), CAST('2022-10-01 16:00:00 America/Los_Angeles' AS TIMESTAMP))"
)

View file

@ -139,10 +139,10 @@ class TestClickhouse(Validator):
"CREATE MATERIALIZED VIEW test_view ON CLUSTER cl1 (id UInt8) ENGINE=AggregatingMergeTree() ORDER BY tuple() AS SELECT * FROM test_data" "CREATE MATERIALIZED VIEW test_view ON CLUSTER cl1 (id UInt8) ENGINE=AggregatingMergeTree() ORDER BY tuple() AS SELECT * FROM test_data"
) )
self.validate_identity( self.validate_identity(
"CREATE MATERIALIZED VIEW test_view ON CLUSTER cl1 (id UInt8) TO table1 AS SELECT * FROM test_data" "CREATE MATERIALIZED VIEW test_view ON CLUSTER cl1 TO table1 AS SELECT * FROM test_data"
) )
self.validate_identity( self.validate_identity(
"CREATE MATERIALIZED VIEW test_view (id UInt8) TO db.table1 AS SELECT * FROM test_data" "CREATE MATERIALIZED VIEW test_view TO db.table1 (id UInt8) AS SELECT * FROM test_data"
) )
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)"
@ -519,6 +519,17 @@ class TestClickhouse(Validator):
self.validate_identity("SELECT TRIM(LEADING '(' FROM '( Hello, world! )')") self.validate_identity("SELECT TRIM(LEADING '(' FROM '( Hello, world! )')")
self.validate_identity("current_timestamp").assert_is(exp.Column) self.validate_identity("current_timestamp").assert_is(exp.Column)
self.validate_identity("SELECT * APPLY(sum) FROM columns_transformers")
self.validate_identity("SELECT COLUMNS('[jk]') APPLY(toString) FROM columns_transformers")
self.validate_identity(
"SELECT COLUMNS('[jk]') APPLY(toString) APPLY(length) APPLY(max) FROM columns_transformers"
)
self.validate_identity("SELECT * APPLY(sum), COLUMNS('col') APPLY(sum) APPLY(avg) FROM t")
self.validate_identity(
"SELECT * FROM ABC WHERE hasAny(COLUMNS('.*field') APPLY(toUInt64) APPLY(to), (SELECT groupUniqArray(toUInt64(field))))"
)
self.validate_identity("SELECT col apply", "SELECT col AS apply")
def test_clickhouse_values(self): def test_clickhouse_values(self):
values = exp.select("*").from_( values = exp.select("*").from_(
exp.values([exp.tuple_(1, 2, 3)], alias="subq", columns=["a", "b", "c"]) exp.values([exp.tuple_(1, 2, 3)], alias="subq", columns=["a", "b", "c"])
@ -670,6 +681,7 @@ class TestClickhouse(Validator):
"CREATE TABLE foo ENGINE=Memory AS (SELECT * FROM db.other_table) COMMENT 'foo'", "CREATE TABLE foo ENGINE=Memory AS (SELECT * FROM db.other_table) COMMENT 'foo'",
) )
self.validate_identity("CREATE MATERIALIZED VIEW a.b TO a.c (c Int32) AS SELECT * FROM a.d")
self.validate_identity("""CREATE TABLE ip_data (ip4 IPv4, ip6 IPv6) ENGINE=TinyLog()""") self.validate_identity("""CREATE TABLE ip_data (ip4 IPv4, ip6 IPv6) ENGINE=TinyLog()""")
self.validate_identity("""CREATE TABLE dates (dt1 Date32) ENGINE=TinyLog()""") self.validate_identity("""CREATE TABLE dates (dt1 Date32) ENGINE=TinyLog()""")
self.validate_identity("CREATE TABLE named_tuples (a Tuple(select String, i Int64))") self.validate_identity("CREATE TABLE named_tuples (a Tuple(select String, i Int64))")
@ -1084,3 +1096,7 @@ LIFETIME(MIN 0 MAX 0)""",
self.assertEqual( self.assertEqual(
convert(date(2020, 1, 1)).sql(dialect=self.dialect), "toDate('2020-01-01')" convert(date(2020, 1, 1)).sql(dialect=self.dialect), "toDate('2020-01-01')"
) )
def test_grant(self):
self.validate_identity("GRANT SELECT(x, y) ON db.table TO john WITH GRANT OPTION")
self.validate_identity("GRANT INSERT(x, y) ON db.table TO john")

View file

@ -271,3 +271,9 @@ class TestDatabricks(Validator):
self.validate_identity( self.validate_identity(
"CREATE OR REFRESH STREAMING TABLE csv_data (id INT, ts TIMESTAMP, event STRING) AS SELECT * FROM STREAM READ_FILES('s3://bucket/path', format => 'csv', schema => 'id int, ts timestamp, event string')" "CREATE OR REFRESH STREAMING TABLE csv_data (id INT, ts TIMESTAMP, event STRING) AS SELECT * FROM STREAM READ_FILES('s3://bucket/path', format => 'csv', schema => 'id int, ts timestamp, event string')"
) )
def test_grant(self):
self.validate_identity("GRANT CREATE ON SCHEMA my_schema TO `alf@melmak.et`")
self.validate_identity("GRANT SELECT ON TABLE sample_data TO `alf@melmak.et`")
self.validate_identity("GRANT ALL PRIVILEGES ON TABLE forecasts TO finance")
self.validate_identity("GRANT SELECT ON TABLE t TO `fab9e00e-ca35-11ec-9d64-0242ac120002`")

View file

@ -2221,9 +2221,9 @@ SELECT
self.validate_all( self.validate_all(
"SUBSTR('123456', 2, 3)", "SUBSTR('123456', 2, 3)",
write={ write={
"bigquery": "SUBSTR('123456', 2, 3)", "bigquery": "SUBSTRING('123456', 2, 3)",
"oracle": "SUBSTR('123456', 2, 3)", "oracle": "SUBSTR('123456', 2, 3)",
"postgres": "SUBSTR('123456', 2, 3)", "postgres": "SUBSTRING('123456' FROM 2 FOR 3)",
}, },
) )
self.validate_all( self.validate_all(

View file

@ -256,6 +256,7 @@ class TestDuckDB(Validator):
parse_one("a // b", read="duckdb").assert_is(exp.IntDiv).sql(dialect="duckdb"), "a // b" parse_one("a // b", read="duckdb").assert_is(exp.IntDiv).sql(dialect="duckdb"), "a // b"
) )
self.validate_identity("CREATE TABLE tbl1 (u UNION(num INT, str TEXT))")
self.validate_identity("INSERT INTO x BY NAME SELECT 1 AS y") self.validate_identity("INSERT INTO x BY NAME SELECT 1 AS y")
self.validate_identity("SELECT 1 AS x UNION ALL BY NAME SELECT 2 AS x") self.validate_identity("SELECT 1 AS x UNION ALL BY NAME SELECT 2 AS x")
self.validate_identity("SELECT SUM(x) FILTER (x = 1)", "SELECT SUM(x) FILTER(WHERE x = 1)") self.validate_identity("SELECT SUM(x) FILTER (x = 1)", "SELECT SUM(x) FILTER(WHERE x = 1)")
@ -294,6 +295,9 @@ class TestDuckDB(Validator):
self.validate_identity("SUMMARIZE tbl").assert_is(exp.Summarize) self.validate_identity("SUMMARIZE tbl").assert_is(exp.Summarize)
self.validate_identity("SUMMARIZE SELECT * FROM tbl").assert_is(exp.Summarize) self.validate_identity("SUMMARIZE SELECT * FROM tbl").assert_is(exp.Summarize)
self.validate_identity("CREATE TABLE tbl_summary AS SELECT * FROM (SUMMARIZE tbl)") self.validate_identity("CREATE TABLE tbl_summary AS SELECT * FROM (SUMMARIZE tbl)")
self.validate_identity("UNION_VALUE(k1 := 1)").find(exp.PropertyEQ).this.assert_is(
exp.Identifier
)
self.validate_identity( self.validate_identity(
"SELECT species, island, COUNT(*) FROM t GROUP BY GROUPING SETS (species), GROUPING SETS (island)" "SELECT species, island, COUNT(*) FROM t GROUP BY GROUPING SETS (species), GROUPING SETS (island)"
) )
@ -309,6 +313,13 @@ class TestDuckDB(Validator):
self.validate_identity( self.validate_identity(
"SELECT * FROM x LEFT JOIN UNNEST(y)", "SELECT * FROM x LEFT JOIN UNNEST(y) ON TRUE" "SELECT * FROM x LEFT JOIN UNNEST(y)", "SELECT * FROM x LEFT JOIN UNNEST(y) ON TRUE"
) )
self.validate_identity(
"""SELECT '{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }' ->> ['$.family', '$.species']""",
)
self.validate_identity(
"""SELECT JSON_EXTRACT_STRING('{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }', ['$.family', '$.species'])""",
"""SELECT '{ "family": "anatidae", "species": [ "duck", "goose", "swan", null ] }' ->> ['$.family', '$.species']""",
)
self.validate_identity( self.validate_identity(
"SELECT col FROM t WHERE JSON_EXTRACT_STRING(col, '$.id') NOT IN ('b')", "SELECT col FROM t WHERE JSON_EXTRACT_STRING(col, '$.id') NOT IN ('b')",
"SELECT col FROM t WHERE NOT (col ->> '$.id') IN ('b')", "SELECT col FROM t WHERE NOT (col ->> '$.id') IN ('b')",
@ -524,8 +535,8 @@ class TestDuckDB(Validator):
write={ write={
"duckdb": "STR_SPLIT(x, 'a')", "duckdb": "STR_SPLIT(x, 'a')",
"presto": "SPLIT(x, 'a')", "presto": "SPLIT(x, 'a')",
"hive": "SPLIT(x, CONCAT('\\\\Q', 'a'))", "hive": "SPLIT(x, CONCAT('\\\\Q', 'a', '\\\\E'))",
"spark": "SPLIT(x, CONCAT('\\\\Q', 'a'))", "spark": "SPLIT(x, CONCAT('\\\\Q', 'a', '\\\\E'))",
}, },
) )
self.validate_all( self.validate_all(
@ -533,8 +544,8 @@ class TestDuckDB(Validator):
write={ write={
"duckdb": "STR_SPLIT(x, 'a')", "duckdb": "STR_SPLIT(x, 'a')",
"presto": "SPLIT(x, 'a')", "presto": "SPLIT(x, 'a')",
"hive": "SPLIT(x, CONCAT('\\\\Q', 'a'))", "hive": "SPLIT(x, CONCAT('\\\\Q', 'a', '\\\\E'))",
"spark": "SPLIT(x, CONCAT('\\\\Q', 'a'))", "spark": "SPLIT(x, CONCAT('\\\\Q', 'a', '\\\\E'))",
}, },
) )
self.validate_all( self.validate_all(
@ -835,6 +846,18 @@ class TestDuckDB(Validator):
"SELECT id, STRUCT_PACK(*COLUMNS('m\\d')) AS measurements FROM many_measurements", "SELECT id, STRUCT_PACK(*COLUMNS('m\\d')) AS measurements FROM many_measurements",
"""SELECT id, {'_0': *COLUMNS('m\\d')} AS measurements FROM many_measurements""", """SELECT id, {'_0': *COLUMNS('m\\d')} AS measurements FROM many_measurements""",
) )
self.validate_identity("SELECT COLUMNS(c -> c LIKE '%num%') FROM numbers")
self.validate_identity(
"SELECT MIN(COLUMNS(* REPLACE (number + id AS number))), COUNT(COLUMNS(* EXCLUDE (number))) FROM numbers"
)
self.validate_identity("SELECT COLUMNS(*) + COLUMNS(*) FROM numbers")
self.validate_identity("SELECT COLUMNS('(id|numbers?)') FROM numbers")
self.validate_identity(
"SELECT COALESCE(COLUMNS(['a', 'b', 'c'])) AS result FROM (SELECT NULL AS a, 42 AS b, TRUE AS c)"
)
self.validate_identity(
"SELECT COALESCE(*COLUMNS(['a', 'b', 'c'])) AS result FROM (SELECT NULL AS a, 42 AS b, TRUE AS c)"
)
def test_array_index(self): def test_array_index(self):
with self.assertLogs(helper_logger) as cm: with self.assertLogs(helper_logger) as cm:

View file

@ -1278,3 +1278,18 @@ COMMENT='客户账户表'"""
self.validate_identity( self.validate_identity(
f"""SELECT JSON_VALUE({json_doc}, '$.price' RETURNING DECIMAL(4, 2) {on_option} ON EMPTY {on_option} ON ERROR) AS price""" f"""SELECT JSON_VALUE({json_doc}, '$.price' RETURNING DECIMAL(4, 2) {on_option} ON EMPTY {on_option} ON ERROR) AS price"""
) )
def test_grant(self):
grant_cmds = [
"GRANT 'role1', 'role2' TO 'user1'@'localhost', 'user2'@'localhost'",
"GRANT SELECT ON world.* TO 'role3'",
"GRANT SELECT ON db2.invoice TO 'jeffrey'@'localhost'",
"GRANT INSERT ON `d%`.* TO u",
"GRANT ALL ON test.* TO ''@'localhost'",
"GRANT SELECT (col1), INSERT (col1, col2) ON mydb.mytbl TO 'someuser'@'somehost'",
"GRANT SELECT, INSERT, UPDATE ON *.* TO u2",
]
for sql in grant_cmds:
with self.subTest(f"Testing MySQL's GRANT command statement: {sql}"):
self.validate_identity(sql, check_command_warning=True)

View file

@ -546,3 +546,21 @@ WHERE
self.validate_identity( self.validate_identity(
f"SELECT * FROM t WHERE JSON_EXISTS(name{format_json}, '$[1].middle'{passing}{on_cond})" f"SELECT * FROM t WHERE JSON_EXISTS(name{format_json}, '$[1].middle'{passing}{on_cond})"
) )
def test_grant(self):
grant_cmds = [
"GRANT purchases_reader_role TO george, maria",
"GRANT USAGE ON TYPE price TO finance_role",
"GRANT USAGE ON DERBY AGGREGATE types.maxPrice TO sales_role",
]
for sql in grant_cmds:
with self.subTest(f"Testing Oracles's GRANT command statement: {sql}"):
self.validate_identity(sql, check_command_warning=True)
self.validate_identity("GRANT SELECT ON TABLE t TO maria, harry")
self.validate_identity("GRANT SELECT ON TABLE s.v TO PUBLIC")
self.validate_identity("GRANT SELECT ON TABLE t TO purchases_reader_role")
self.validate_identity("GRANT UPDATE, TRIGGER ON TABLE t TO anita, zhi")
self.validate_identity("GRANT EXECUTE ON PROCEDURE p TO george")
self.validate_identity("GRANT USAGE ON SEQUENCE order_id TO sales_role")

View file

@ -797,6 +797,11 @@ class TestPostgres(Validator):
self.validate_identity( self.validate_identity(
"MERGE INTO target_table USING source_table AS source ON target.id = source.id WHEN MATCHED THEN DO NOTHING WHEN NOT MATCHED THEN DO NOTHING RETURNING MERGE_ACTION(), *" "MERGE INTO target_table USING source_table AS source ON target.id = source.id WHEN MATCHED THEN DO NOTHING WHEN NOT MATCHED THEN DO NOTHING RETURNING MERGE_ACTION(), *"
) )
self.validate_identity(
"SELECT 1 FROM ((VALUES (1)) AS vals(id) LEFT OUTER JOIN tbl ON vals.id = tbl.id)"
)
self.validate_identity("SELECT OVERLAY(a PLACING b FROM 1)")
self.validate_identity("SELECT OVERLAY(a PLACING b FROM 1 FOR 1)")
def test_ddl(self): def test_ddl(self):
# Checks that user-defined types are parsed into DataType instead of Identifier # Checks that user-defined types are parsed into DataType instead of Identifier

View file

@ -158,8 +158,8 @@ class TestPresto(Validator):
write={ write={
"duckdb": "STR_SPLIT(x, 'a.')", "duckdb": "STR_SPLIT(x, 'a.')",
"presto": "SPLIT(x, 'a.')", "presto": "SPLIT(x, 'a.')",
"hive": "SPLIT(x, CONCAT('\\\\Q', 'a.'))", "hive": "SPLIT(x, CONCAT('\\\\Q', 'a.', '\\\\E'))",
"spark": "SPLIT(x, CONCAT('\\\\Q', 'a.'))", "spark": "SPLIT(x, CONCAT('\\\\Q', 'a.', '\\\\E'))",
}, },
) )
self.validate_all( self.validate_all(
@ -276,10 +276,19 @@ class TestPresto(Validator):
self.validate_all( self.validate_all(
"DATE_PARSE(SUBSTR(x, 1, 10), '%Y-%m-%d')", "DATE_PARSE(SUBSTR(x, 1, 10), '%Y-%m-%d')",
write={ write={
"duckdb": "STRPTIME(SUBSTR(x, 1, 10), '%Y-%m-%d')", "duckdb": "STRPTIME(SUBSTRING(x, 1, 10), '%Y-%m-%d')",
"presto": "DATE_PARSE(SUBSTR(x, 1, 10), '%Y-%m-%d')", "presto": "DATE_PARSE(SUBSTRING(x, 1, 10), '%Y-%m-%d')",
"hive": "CAST(SUBSTR(x, 1, 10) AS TIMESTAMP)", "hive": "CAST(SUBSTRING(x, 1, 10) AS TIMESTAMP)",
"spark": "TO_TIMESTAMP(SUBSTR(x, 1, 10), 'yyyy-MM-dd')", "spark": "TO_TIMESTAMP(SUBSTRING(x, 1, 10), 'yyyy-MM-dd')",
},
)
self.validate_all(
"DATE_PARSE(SUBSTRING(x, 1, 10), '%Y-%m-%d')",
write={
"duckdb": "STRPTIME(SUBSTRING(x, 1, 10), '%Y-%m-%d')",
"presto": "DATE_PARSE(SUBSTRING(x, 1, 10), '%Y-%m-%d')",
"hive": "CAST(SUBSTRING(x, 1, 10) AS TIMESTAMP)",
"spark": "TO_TIMESTAMP(SUBSTRING(x, 1, 10), 'yyyy-MM-dd')",
}, },
) )
self.validate_all( self.validate_all(

View file

@ -626,3 +626,36 @@ FROM (
"TIME_TO_STR(a, '%Y-%m-%d %H:%M:%S.%f')", "TIME_TO_STR(a, '%Y-%m-%d %H:%M:%S.%f')",
write={"redshift": "TO_CHAR(a, 'YYYY-MM-DD HH24:MI:SS.US')"}, write={"redshift": "TO_CHAR(a, 'YYYY-MM-DD HH24:MI:SS.US')"},
) )
def test_grant(self):
grant_cmds = [
"GRANT SELECT ON ALL TABLES IN SCHEMA qa_tickit TO fred",
"GRANT USAGE ON DATASHARE salesshare TO NAMESPACE '13b8833d-17c6-4f16-8fe4-1a018f5ed00d'",
"GRANT USAGE FOR SCHEMAS IN DATABASE Sales_db TO ROLE Sales",
"GRANT EXECUTE FOR FUNCTIONS IN SCHEMA Sales_schema TO bob",
"GRANT SELECT FOR TABLES IN DATABASE Sales_db TO alice WITH GRANT OPTION",
"GRANT ALL FOR TABLES IN SCHEMA ShareSchema DATABASE ShareDb TO ROLE Sales",
"GRANT ASSUMEROLE ON 'arn:aws:iam::123456789012:role/Redshift-Exfunc' TO reg_user1 FOR EXTERNAL FUNCTION",
"GRANT ROLE sample_role1 TO ROLE sample_role2",
]
for sql in grant_cmds:
with self.subTest(f"Testing Redshift's GRANT command statement: {sql}"):
self.validate_identity(sql, check_command_warning=True)
self.validate_identity("GRANT SELECT ON TABLE sales TO fred")
self.validate_identity("GRANT ALL ON SCHEMA qa_tickit TO GROUP qa_users")
self.validate_identity("GRANT ALL ON TABLE qa_tickit.sales TO GROUP qa_users")
self.validate_identity(
"GRANT ALL ON TABLE qa_tickit.sales TO GROUP qa_users, GROUP ro_users"
)
self.validate_identity("GRANT ALL ON view_date TO view_user")
self.validate_identity(
"GRANT SELECT(cust_name, cust_phone), UPDATE(cust_contact_preference) ON cust_profile TO GROUP sales_group"
)
self.validate_identity(
"GRANT ALL(cust_name, cust_phone, cust_contact_preference) ON cust_profile TO GROUP sales_admin"
)
self.validate_identity("GRANT USAGE ON DATABASE sales_db TO Bob")
self.validate_identity("GRANT USAGE ON SCHEMA sales_schema TO ROLE Analyst_role")
self.validate_identity("GRANT SELECT ON sales_db.sales_schema.tickit_sales_redshift TO Bob")

View file

@ -755,6 +755,8 @@ WHERE
write={ write={
"spark": "SELECT COLLECT_LIST(DISTINCT a)", "spark": "SELECT COLLECT_LIST(DISTINCT a)",
"snowflake": "SELECT ARRAY_AGG(DISTINCT a)", "snowflake": "SELECT ARRAY_AGG(DISTINCT a)",
"duckdb": "SELECT ARRAY_AGG(DISTINCT a) FILTER(WHERE a IS NOT NULL)",
"presto": "SELECT ARRAY_AGG(DISTINCT a) FILTER(WHERE a IS NOT NULL)",
}, },
) )
self.validate_all( self.validate_all(
@ -2175,3 +2177,20 @@ SINGLE = TRUE""",
"""SELECT 1 FROM some_table CHANGES (INFORMATION => APPEND_ONLY) AT (TIMESTAMP => TO_TIMESTAMP_TZ('2024-07-01 00:00:00+00:00')) END (TIMESTAMP => TO_TIMESTAMP_TZ('2024-07-01 14:28:59.999999+00:00'))""", """SELECT 1 FROM some_table CHANGES (INFORMATION => APPEND_ONLY) AT (TIMESTAMP => TO_TIMESTAMP_TZ('2024-07-01 00:00:00+00:00')) END (TIMESTAMP => TO_TIMESTAMP_TZ('2024-07-01 14:28:59.999999+00:00'))""",
"""SELECT 1 FROM some_table CHANGES (INFORMATION => APPEND_ONLY) AT (TIMESTAMP => CAST('2024-07-01 00:00:00+00:00' AS TIMESTAMPTZ)) END (TIMESTAMP => CAST('2024-07-01 14:28:59.999999+00:00' AS TIMESTAMPTZ))""", """SELECT 1 FROM some_table CHANGES (INFORMATION => APPEND_ONLY) AT (TIMESTAMP => CAST('2024-07-01 00:00:00+00:00' AS TIMESTAMPTZ)) END (TIMESTAMP => CAST('2024-07-01 14:28:59.999999+00:00' AS TIMESTAMPTZ))""",
) )
def test_grant(self):
grant_cmds = [
"GRANT SELECT ON FUTURE TABLES IN DATABASE d1 TO ROLE r1",
"GRANT INSERT, DELETE ON FUTURE TABLES IN SCHEMA d1.s1 TO ROLE r2",
"GRANT SELECT ON ALL TABLES IN SCHEMA mydb.myschema to ROLE analyst",
"GRANT SELECT, INSERT ON FUTURE TABLES IN SCHEMA mydb.myschema TO ROLE role1",
"GRANT CREATE MATERIALIZED VIEW ON SCHEMA mydb.myschema TO DATABASE ROLE mydb.dr1",
]
for sql in grant_cmds:
with self.subTest(f"Testing Snowflake's GRANT command statement: {sql}"):
self.validate_identity(sql, check_command_warning=True)
self.validate_identity(
"GRANT ALL PRIVILEGES ON FUNCTION mydb.myschema.ADD5(number) TO ROLE analyst"
)

View file

@ -85,8 +85,8 @@ class TestStarrocks(Validator):
r"""SELECT id, t.type, t.scores FROM example_table, unnest(split(type, ";"), scores) AS t(type,scores)""", r"""SELECT id, t.type, t.scores FROM example_table, unnest(split(type, ";"), scores) AS t(type,scores)""",
write={ write={
"postgres": "SELECT id, t.type, t.scores FROM example_table, UNNEST(SPLIT(type, ';'), scores) AS t(type, scores)", "postgres": "SELECT id, t.type, t.scores FROM example_table, UNNEST(SPLIT(type, ';'), scores) AS t(type, scores)",
"spark": r"""SELECT id, t.type, t.scores FROM example_table LATERAL VIEW INLINE(ARRAYS_ZIP(SPLIT(type, CONCAT('\\Q', ';')), scores)) t AS type, scores""", "spark": r"""SELECT id, t.type, t.scores FROM example_table LATERAL VIEW INLINE(ARRAYS_ZIP(SPLIT(type, CONCAT('\\Q', ';', '\\E')), scores)) t AS type, scores""",
"databricks": r"""SELECT id, t.type, t.scores FROM example_table LATERAL VIEW INLINE(ARRAYS_ZIP(SPLIT(type, CONCAT('\\Q', ';')), scores)) t AS type, scores""", "databricks": r"""SELECT id, t.type, t.scores FROM example_table LATERAL VIEW INLINE(ARRAYS_ZIP(SPLIT(type, CONCAT('\\Q', ';', '\\E')), scores)) t AS type, scores""",
"starrocks": r"""SELECT id, t.type, t.scores FROM example_table, UNNEST(SPLIT(type, ';'), scores) AS t(type, scores)""", "starrocks": r"""SELECT id, t.type, t.scores FROM example_table, UNNEST(SPLIT(type, ';'), scores) AS t(type, scores)""",
"hive": UnsupportedError, "hive": UnsupportedError,
}, },
@ -95,7 +95,7 @@ class TestStarrocks(Validator):
self.validate_all( self.validate_all(
r"""SELECT id, t.type, t.scores FROM example_table_2 CROSS JOIN LATERAL unnest(split(type, ";"), scores) AS t(type,scores)""", r"""SELECT id, t.type, t.scores FROM example_table_2 CROSS JOIN LATERAL unnest(split(type, ";"), scores) AS t(type,scores)""",
write={ write={
"spark": r"""SELECT id, t.type, t.scores FROM example_table_2 LATERAL VIEW INLINE(ARRAYS_ZIP(SPLIT(type, CONCAT('\\Q', ';')), scores)) t AS type, scores""", "spark": r"""SELECT id, t.type, t.scores FROM example_table_2 LATERAL VIEW INLINE(ARRAYS_ZIP(SPLIT(type, CONCAT('\\Q', ';', '\\E')), scores)) t AS type, scores""",
"starrocks": r"""SELECT id, t.type, t.scores FROM example_table_2 CROSS JOIN LATERAL UNNEST(SPLIT(type, ';'), scores) AS t(type, scores)""", "starrocks": r"""SELECT id, t.type, t.scores FROM example_table_2 CROSS JOIN LATERAL UNNEST(SPLIT(type, ';'), scores) AS t(type, scores)""",
"hive": UnsupportedError, "hive": UnsupportedError,
}, },

View file

@ -1998,3 +1998,10 @@ FROM OPENJSON(@json) WITH (
"tsql": "SELECT COUNT(1) FROM x", "tsql": "SELECT COUNT(1) FROM x",
}, },
) )
def test_grant(self):
self.validate_identity("GRANT EXECUTE ON TestProc TO User2")
self.validate_identity("GRANT EXECUTE ON TestProc TO TesterRole WITH GRANT OPTION")
self.validate_identity(
"GRANT EXECUTE ON TestProc TO User2 AS TesterRole", check_command_warning=True
)

View file

@ -131,7 +131,7 @@ x[ORDINAL(1)][SAFE_OFFSET(2)]
x GLOB '??-*' x GLOB '??-*'
x GLOB y x GLOB y
ILIKE(x, 'z') ILIKE(x, 'z')
x LIKE SUBSTR('abc', 1, 1) x LIKE SUBSTRING('abc', 1, 1)
x LIKE y x LIKE y
x LIKE a.y x LIKE a.y
x LIKE '%y%' x LIKE '%y%'
@ -879,3 +879,8 @@ SELECT COUNT(DISTINCT "foo bar") FROM (SELECT 1 AS "foo bar") AS t
SELECT vector SELECT vector
WITH all AS (SELECT 1 AS count) SELECT all.count FROM all WITH all AS (SELECT 1 AS count) SELECT all.count FROM all
SELECT rename SELECT rename
GRANT SELECT ON TABLE tbl TO user
GRANT SELECT, INSERT ON FUNCTION tbl TO user
GRANT SELECT ON orders TO ROLE PUBLIC
GRANT SELECT ON nation TO alice WITH GRANT OPTION
GRANT DELETE ON SCHEMA finance TO bob

View file

@ -137,6 +137,9 @@ FALSE;
TRUE AND TRUE OR TRUE AND FALSE; TRUE AND TRUE OR TRUE AND FALSE;
TRUE; TRUE;
COALESCE(x, y) <> ALL (SELECT z FROM w);
COALESCE(x, y) <> ALL (SELECT z FROM w);
-------------------------------------- --------------------------------------
-- Absorption -- Absorption
-------------------------------------- --------------------------------------

View file

@ -991,9 +991,9 @@ FROM store_sales,
date_dim, date_dim,
store, store,
(SELECT ca_zip (SELECT ca_zip
FROM (SELECT Substr(ca_zip, 1, 5) ca_zip FROM (SELECT SUBSTRING(ca_zip, 1, 5) ca_zip
FROM customer_address FROM customer_address
WHERE Substr(ca_zip, 1, 5) IN ( '67436', '26121', '38443', WHERE SUBSTRING(ca_zip, 1, 5) IN ( '67436', '26121', '38443',
'63157', '63157',
'68856', '19485', '86425', '68856', '19485', '86425',
'26741', '26741',
@ -1195,7 +1195,7 @@ FROM store_sales,
'92564' ) '92564' )
INTERSECT INTERSECT
SELECT ca_zip SELECT ca_zip
FROM (SELECT Substr(ca_zip, 1, 5) ca_zip, FROM (SELECT SUBSTRING(ca_zip, 1, 5) ca_zip,
Count(*) cnt Count(*) cnt
FROM customer_address, FROM customer_address,
customer customer
@ -1207,13 +1207,13 @@ WHERE ss_store_sk = s_store_sk
AND ss_sold_date_sk = d_date_sk AND ss_sold_date_sk = d_date_sk
AND d_qoy = 2 AND d_qoy = 2
AND d_year = 2000 AND d_year = 2000
AND ( Substr(s_zip, 1, 2) = Substr(V1.ca_zip, 1, 2) ) AND ( SUBSTRING(s_zip, 1, 2) = SUBSTRING(V1.ca_zip, 1, 2) )
GROUP BY s_store_name GROUP BY s_store_name
ORDER BY s_store_name ORDER BY s_store_name
LIMIT 100; LIMIT 100;
WITH "a1" AS ( WITH "a1" AS (
SELECT SELECT
SUBSTR("customer_address"."ca_zip", 1, 5) AS "ca_zip" SUBSTRING("customer_address"."ca_zip", 1, 5) AS "ca_zip"
FROM "customer_address" AS "customer_address" FROM "customer_address" AS "customer_address"
JOIN "customer" AS "customer" JOIN "customer" AS "customer"
ON "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk" ON "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk"
@ -1224,10 +1224,10 @@ WITH "a1" AS (
COUNT(*) > 10 COUNT(*) > 10
), "a2" AS ( ), "a2" AS (
SELECT SELECT
SUBSTR("customer_address"."ca_zip", 1, 5) AS "ca_zip" SUBSTRING("customer_address"."ca_zip", 1, 5) AS "ca_zip"
FROM "customer_address" AS "customer_address" FROM "customer_address" AS "customer_address"
WHERE WHERE
SUBSTR("customer_address"."ca_zip", 1, 5) IN ('67436', '26121', '38443', '63157', '68856', '19485', '86425', '26741', '70991', '60899', '63573', '47556', '56193', '93314', '87827', '62017', '85067', '95390', '48091', '10261', '81845', '41790', '42853', '24675', '12840', '60065', '84430', '57451', '24021', '91735', '75335', '71935', '34482', '56943', '70695', '52147', '56251', '28411', '86653', '23005', '22478', '29031', '34398', '15365', '42460', '33337', '59433', '73943', '72477', '74081', '74430', '64605', '39006', '11226', '49057', '97308', '42663', '18187', '19768', '43454', '32147', '76637', '51975', '11181', '45630', '33129', '45995', '64386', '55522', '26697', '20963', '35154', '64587', '49752', '66386', '30586', '59286', '13177', '66646', '84195', '74316', '36853', '32927', '12469', '11904', '36269', '17724', '55346', '12595', '53988', '65439', '28015', '63268', '73590', '29216', '82575', '69267', '13805', '91678', '79460', '94152', '14961', '15419', '48277', '62588', '55493', '28360', '14152', '55225', '18007', '53705', '56573', '80245', '71769', '57348', '36845', '13039', '17270', '22363', '83474', '25294', '43269', '77666', '15488', '99146', '64441', '43338', '38736', '62754', '48556', '86057', '23090', '38114', '66061', '18910', '84385', '23600', '19975', '27883', '65719', '19933', '32085', '49731', '40473', '27190', '46192', '23949', '44738', '12436', '64794', '68741', '15333', '24282', '49085', '31844', '71156', '48441', '17100', '98207', '44982', '20277', '71496', '96299', '37583', '22206', '89174', '30589', '61924', '53079', '10976', '13104', '42794', '54772', '15809', '56434', '39975', '13874', '30753', '77598', '78229', '59478', '12345', '55547', '57422', '42600', '79444', '29074', '29752', '21676', '32096', '43044', '39383', '37296', '36295', '63077', '16572', '31275', '18701', '40197', '48242', '27219', '49865', '84175', '30446', '25165', '13807', '72142', '70499', '70464', '71429', '18111', '70857', '29545', '36425', '52706', '36194', '42963', '75068', '47921', '74763', '90990', '89456', '62073', '88397', '73963', '75885', '62657', '12530', '81146', '57434', '25099', '41429', '98441', '48713', '52552', '31667', '14072', '13903', '44709', '85429', '58017', '38295', '44875', '73541', '30091', '12707', '23762', '62258', '33247', '78722', '77431', '14510', '35656', '72428', '92082', '35267', '43759', '24354', '90952', '11512', '21242', '22579', '56114', '32339', '52282', '41791', '24484', '95020', '28408', '99710', '11899', '43344', '72915', '27644', '62708', '74479', '17177', '32619', '12351', '91339', '31169', '57081', '53522', '16712', '34419', '71779', '44187', '46206', '96099', '61910', '53664', '12295', '31837', '33096', '10813', '63048', '31732', '79118', '73084', '72783', '84952', '46965', '77956', '39815', '32311', '75329', '48156', '30826', '49661', '13736', '92076', '74865', '88149', '92397', '52777', '68453', '32012', '21222', '52721', '24626', '18210', '42177', '91791', '75251', '82075', '44372', '45542', '20609', '60115', '17362', '22750', '90434', '31852', '54071', '33762', '14705', '40718', '56433', '30996', '40657', '49056', '23585', '66455', '41021', '74736', '72151', '37007', '21729', '60177', '84558', '59027', '93855', '60022', '86443', '19541', '86886', '30532', '39062', '48532', '34713', '52077', '22564', '64638', '15273', '31677', '36138', '62367', '60261', '80213', '42818', '25113', '72378', '69802', '69096', '55443', '28820', '13848', '78258', '37490', '30556', '77380', '28447', '44550', '26791', '70609', '82182', '33306', '43224', '22322', '86959', '68519', '14308', '46501', '81131', '34056', '61991', '19896', '87804', '65774', '92564') SUBSTRING("customer_address"."ca_zip", 1, 5) IN ('67436', '26121', '38443', '63157', '68856', '19485', '86425', '26741', '70991', '60899', '63573', '47556', '56193', '93314', '87827', '62017', '85067', '95390', '48091', '10261', '81845', '41790', '42853', '24675', '12840', '60065', '84430', '57451', '24021', '91735', '75335', '71935', '34482', '56943', '70695', '52147', '56251', '28411', '86653', '23005', '22478', '29031', '34398', '15365', '42460', '33337', '59433', '73943', '72477', '74081', '74430', '64605', '39006', '11226', '49057', '97308', '42663', '18187', '19768', '43454', '32147', '76637', '51975', '11181', '45630', '33129', '45995', '64386', '55522', '26697', '20963', '35154', '64587', '49752', '66386', '30586', '59286', '13177', '66646', '84195', '74316', '36853', '32927', '12469', '11904', '36269', '17724', '55346', '12595', '53988', '65439', '28015', '63268', '73590', '29216', '82575', '69267', '13805', '91678', '79460', '94152', '14961', '15419', '48277', '62588', '55493', '28360', '14152', '55225', '18007', '53705', '56573', '80245', '71769', '57348', '36845', '13039', '17270', '22363', '83474', '25294', '43269', '77666', '15488', '99146', '64441', '43338', '38736', '62754', '48556', '86057', '23090', '38114', '66061', '18910', '84385', '23600', '19975', '27883', '65719', '19933', '32085', '49731', '40473', '27190', '46192', '23949', '44738', '12436', '64794', '68741', '15333', '24282', '49085', '31844', '71156', '48441', '17100', '98207', '44982', '20277', '71496', '96299', '37583', '22206', '89174', '30589', '61924', '53079', '10976', '13104', '42794', '54772', '15809', '56434', '39975', '13874', '30753', '77598', '78229', '59478', '12345', '55547', '57422', '42600', '79444', '29074', '29752', '21676', '32096', '43044', '39383', '37296', '36295', '63077', '16572', '31275', '18701', '40197', '48242', '27219', '49865', '84175', '30446', '25165', '13807', '72142', '70499', '70464', '71429', '18111', '70857', '29545', '36425', '52706', '36194', '42963', '75068', '47921', '74763', '90990', '89456', '62073', '88397', '73963', '75885', '62657', '12530', '81146', '57434', '25099', '41429', '98441', '48713', '52552', '31667', '14072', '13903', '44709', '85429', '58017', '38295', '44875', '73541', '30091', '12707', '23762', '62258', '33247', '78722', '77431', '14510', '35656', '72428', '92082', '35267', '43759', '24354', '90952', '11512', '21242', '22579', '56114', '32339', '52282', '41791', '24484', '95020', '28408', '99710', '11899', '43344', '72915', '27644', '62708', '74479', '17177', '32619', '12351', '91339', '31169', '57081', '53522', '16712', '34419', '71779', '44187', '46206', '96099', '61910', '53664', '12295', '31837', '33096', '10813', '63048', '31732', '79118', '73084', '72783', '84952', '46965', '77956', '39815', '32311', '75329', '48156', '30826', '49661', '13736', '92076', '74865', '88149', '92397', '52777', '68453', '32012', '21222', '52721', '24626', '18210', '42177', '91791', '75251', '82075', '44372', '45542', '20609', '60115', '17362', '22750', '90434', '31852', '54071', '33762', '14705', '40718', '56433', '30996', '40657', '49056', '23585', '66455', '41021', '74736', '72151', '37007', '21729', '60177', '84558', '59027', '93855', '60022', '86443', '19541', '86886', '30532', '39062', '48532', '34713', '52077', '22564', '64638', '15273', '31677', '36138', '62367', '60261', '80213', '42818', '25113', '72378', '69802', '69096', '55443', '28820', '13848', '78258', '37490', '30556', '77380', '28447', '44550', '26791', '70609', '82182', '33306', '43224', '22322', '86959', '68519', '14308', '46501', '81131', '34056', '61991', '19896', '87804', '65774', '92564')
INTERSECT INTERSECT
SELECT SELECT
"a1"."ca_zip" AS "ca_zip" "a1"."ca_zip" AS "ca_zip"
@ -1244,7 +1244,7 @@ JOIN "date_dim" AS "date_dim"
JOIN "store" AS "store" JOIN "store" AS "store"
ON "store"."s_store_sk" = "store_sales"."ss_store_sk" ON "store"."s_store_sk" = "store_sales"."ss_store_sk"
JOIN "a2" AS "a2" JOIN "a2" AS "a2"
ON SUBSTR("a2"."ca_zip", 1, 2) = SUBSTR("store"."s_zip", 1, 2) ON SUBSTRING("a2"."ca_zip", 1, 2) = SUBSTRING("store"."s_zip", 1, 2)
GROUP BY GROUP BY
"store"."s_store_name" "store"."s_store_name"
ORDER BY ORDER BY
@ -2319,7 +2319,7 @@ FROM catalog_sales,
date_dim date_dim
WHERE cs_bill_customer_sk = c_customer_sk WHERE cs_bill_customer_sk = c_customer_sk
AND c_current_addr_sk = ca_address_sk AND c_current_addr_sk = ca_address_sk
AND ( Substr(ca_zip, 1, 5) IN ( '85669', '86197', '88274', '83405', AND ( SUBSTRING(ca_zip, 1, 5) IN ( '85669', '86197', '88274', '83405',
'86475', '85392', '85460', '80348', '86475', '85392', '85460', '80348',
'81792' ) '81792' )
OR ca_state IN ( 'CA', 'WA', 'GA' ) OR ca_state IN ( 'CA', 'WA', 'GA' )
@ -2344,7 +2344,7 @@ JOIN "customer_address" AS "customer_address"
ON ( ON (
"catalog_sales"."cs_sales_price" > 500 "catalog_sales"."cs_sales_price" > 500
OR "customer_address"."ca_state" IN ('CA', 'WA', 'GA') OR "customer_address"."ca_state" IN ('CA', 'WA', 'GA')
OR SUBSTR("customer_address"."ca_zip", 1, 5) IN ('85669', '86197', '88274', '83405', '86475', '85392', '85460', '80348', '81792') OR SUBSTRING("customer_address"."ca_zip", 1, 5) IN ('85669', '86197', '88274', '83405', '86475', '85392', '85460', '80348', '81792')
) )
AND "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk" AND "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk"
GROUP BY GROUP BY
@ -2643,7 +2643,7 @@ WHERE d_date_sk = ss_sold_date_sk
AND d_year = 1998 AND d_year = 1998
AND ss_customer_sk = c_customer_sk AND ss_customer_sk = c_customer_sk
AND c_current_addr_sk = ca_address_sk AND c_current_addr_sk = ca_address_sk
AND Substr(ca_zip, 1, 5) <> Substr(s_zip, 1, 5) AND SUBSTRING(ca_zip, 1, 5) <> SUBSTRING(s_zip, 1, 5)
AND ss_store_sk = s_store_sk AND ss_store_sk = s_store_sk
GROUP BY i_brand, GROUP BY i_brand,
i_brand_id, i_brand_id,
@ -2672,7 +2672,7 @@ JOIN "customer_address" AS "customer_address"
ON "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk" ON "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk"
JOIN "store" AS "store" JOIN "store" AS "store"
ON "store"."s_store_sk" = "store_sales"."ss_store_sk" ON "store"."s_store_sk" = "store_sales"."ss_store_sk"
AND SUBSTR("customer_address"."ca_zip", 1, 5) <> SUBSTR("store"."s_zip", 1, 5) AND SUBSTRING("customer_address"."ca_zip", 1, 5) <> SUBSTRING("store"."s_zip", 1, 5)
WHERE WHERE
"date_dim"."d_moy" = 12 AND "date_dim"."d_year" = 1998 "date_dim"."d_moy" = 12 AND "date_dim"."d_year" = 1998
GROUP BY GROUP BY
@ -2895,7 +2895,7 @@ LIMIT 100;
-------------------------------------- --------------------------------------
# execute: true # execute: true
WITH frequent_ss_items WITH frequent_ss_items
AS (SELECT Substr(i_item_desc, 1, 30) itemdesc, AS (SELECT SUBSTRING(i_item_desc, 1, 30) itemdesc,
i_item_sk item_sk, i_item_sk item_sk,
d_date solddate, d_date solddate,
Count(*) cnt Count(*) cnt
@ -2905,7 +2905,7 @@ WITH frequent_ss_items
WHERE ss_sold_date_sk = d_date_sk WHERE ss_sold_date_sk = d_date_sk
AND ss_item_sk = i_item_sk AND ss_item_sk = i_item_sk
AND d_year IN ( 1998, 1998 + 1, 1998 + 2, 1998 + 3 ) AND d_year IN ( 1998, 1998 + 1, 1998 + 2, 1998 + 3 )
GROUP BY Substr(i_item_desc, 1, 30), GROUP BY SUBSTRING(i_item_desc, 1, 30),
i_item_sk, i_item_sk,
d_date d_date
HAVING Count(*) > 4), HAVING Count(*) > 4),
@ -2962,7 +2962,7 @@ WITH "frequent_ss_items" AS (
JOIN "item" AS "item" JOIN "item" AS "item"
ON "item"."i_item_sk" = "store_sales"."ss_item_sk" ON "item"."i_item_sk" = "store_sales"."ss_item_sk"
GROUP BY GROUP BY
SUBSTR("item"."i_item_desc", 1, 30), SUBSTRING("item"."i_item_desc", 1, 30),
"item"."i_item_sk", "item"."i_item_sk",
"date_dim"."d_date" "date_dim"."d_date"
HAVING HAVING
@ -5296,7 +5296,7 @@ FROM web_sales,
WHERE ws_bill_customer_sk = c_customer_sk WHERE ws_bill_customer_sk = c_customer_sk
AND c_current_addr_sk = ca_address_sk AND c_current_addr_sk = ca_address_sk
AND ws_item_sk = i_item_sk AND ws_item_sk = i_item_sk
AND ( Substr(ca_zip, 1, 5) IN ( '85669', '86197', '88274', '83405', AND ( SUBSTRING(ca_zip, 1, 5) IN ( '85669', '86197', '88274', '83405',
'86475', '85392', '85460', '80348', '86475', '85392', '85460', '80348',
'81792' ) '81792' )
OR i_item_id IN (SELECT i_item_id OR i_item_id IN (SELECT i_item_id
@ -5340,7 +5340,7 @@ JOIN "customer_address" AS "customer_address"
ON "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk" ON "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk"
WHERE WHERE
NOT "_u_0"."i_item_id" IS NULL NOT "_u_0"."i_item_id" IS NULL
OR SUBSTR("customer_address"."ca_zip", 1, 5) IN ('85669', '86197', '88274', '83405', '86475', '85392', '85460', '80348', '81792') OR SUBSTRING("customer_address"."ca_zip", 1, 5) IN ('85669', '86197', '88274', '83405', '86475', '85392', '85460', '80348', '81792')
GROUP BY GROUP BY
"customer_address"."ca_zip", "customer_address"."ca_zip",
"customer_address"."ca_state" "customer_address"."ca_state"
@ -7585,7 +7585,7 @@ LIMIT 100;
-- TPC-DS 62 -- TPC-DS 62
-------------------------------------- --------------------------------------
# execute: true # execute: true
SELECT Substr(w_warehouse_name, 1, 20) AS "_col_0", SELECT SUBSTRING(w_warehouse_name, 1, 20) AS "_col_0",
sm_type, sm_type,
web_name, web_name,
Sum(CASE Sum(CASE
@ -7622,15 +7622,15 @@ WHERE d_month_seq BETWEEN 1222 AND 1222 + 11
AND ws_warehouse_sk = w_warehouse_sk AND ws_warehouse_sk = w_warehouse_sk
AND ws_ship_mode_sk = sm_ship_mode_sk AND ws_ship_mode_sk = sm_ship_mode_sk
AND ws_web_site_sk = web_site_sk AND ws_web_site_sk = web_site_sk
GROUP BY Substr(w_warehouse_name, 1, 20), GROUP BY SUBSTRING(w_warehouse_name, 1, 20),
sm_type, sm_type,
web_name web_name
ORDER BY Substr(w_warehouse_name, 1, 20), ORDER BY SUBSTRING(w_warehouse_name, 1, 20),
sm_type, sm_type,
web_name web_name
LIMIT 100; LIMIT 100;
SELECT SELECT
SUBSTR("warehouse"."w_warehouse_name", 1, 20) AS "_col_0", SUBSTRING("warehouse"."w_warehouse_name", 1, 20) AS "_col_0",
"ship_mode"."sm_type" AS "sm_type", "ship_mode"."sm_type" AS "sm_type",
"web_site"."web_name" AS "web_name", "web_site"."web_name" AS "web_name",
SUM( SUM(
@ -7683,7 +7683,7 @@ JOIN "warehouse" AS "warehouse"
JOIN "web_site" AS "web_site" JOIN "web_site" AS "web_site"
ON "web_sales"."ws_web_site_sk" = "web_site"."web_site_sk" ON "web_sales"."ws_web_site_sk" = "web_site"."web_site_sk"
GROUP BY GROUP BY
SUBSTR("warehouse"."w_warehouse_name", 1, 20), SUBSTRING("warehouse"."w_warehouse_name", 1, 20),
"ship_mode"."sm_type", "ship_mode"."sm_type",
"web_site"."web_name" "web_site"."web_name"
ORDER BY ORDER BY
@ -10638,7 +10638,7 @@ LIMIT 100;
# execute: true # execute: true
SELECT c_last_name, SELECT c_last_name,
c_first_name, c_first_name,
Substr(s_city, 1, 30) AS "_col_2", SUBSTRING(s_city, 1, 30) AS "_col_2",
ss_ticket_number, ss_ticket_number,
amt, amt,
profit profit
@ -10667,7 +10667,7 @@ FROM (SELECT ss_ticket_number,
WHERE ss_customer_sk = c_customer_sk WHERE ss_customer_sk = c_customer_sk
ORDER BY c_last_name, ORDER BY c_last_name,
c_first_name, c_first_name,
Substr(s_city, 1, 30), SUBSTRING(s_city, 1, 30),
profit profit
LIMIT 100; LIMIT 100;
WITH "ms" AS ( WITH "ms" AS (
@ -10701,7 +10701,7 @@ WITH "ms" AS (
SELECT SELECT
"customer"."c_last_name" AS "c_last_name", "customer"."c_last_name" AS "c_last_name",
"customer"."c_first_name" AS "c_first_name", "customer"."c_first_name" AS "c_first_name",
SUBSTR("ms"."s_city", 1, 30) AS "_col_2", SUBSTRING("ms"."s_city", 1, 30) AS "_col_2",
"ms"."ss_ticket_number" AS "ss_ticket_number", "ms"."ss_ticket_number" AS "ss_ticket_number",
"ms"."amt" AS "amt", "ms"."amt" AS "amt",
"ms"."profit" AS "profit" "ms"."profit" AS "profit"
@ -10711,7 +10711,7 @@ JOIN "customer" AS "customer"
ORDER BY ORDER BY
"c_last_name", "c_last_name",
"c_first_name", "c_first_name",
SUBSTR("ms"."s_city", 1, 30), SUBSTRING("ms"."s_city", 1, 30),
"profit" "profit"
LIMIT 100; LIMIT 100;
@ -11371,7 +11371,7 @@ LIMIT 100;
-- TPC-DS 85 -- TPC-DS 85
-------------------------------------- --------------------------------------
# execute: true # execute: true
SELECT Substr(r_reason_desc, 1, 20) AS "_col_0", SELECT SUBSTRING(r_reason_desc, 1, 20) AS "_col_0",
Avg(ws_quantity) AS "_col_1", Avg(ws_quantity) AS "_col_1",
Avg(wr_refunded_cash) AS "_col_2", Avg(wr_refunded_cash) AS "_col_2",
Avg(wr_fee) AS "_col_3" Avg(wr_fee) AS "_col_3"
@ -11417,13 +11417,13 @@ WHERE ws_web_page_sk = wp_web_page_sk
AND ca_state IN ( 'FL', 'WI', 'KS' ) AND ca_state IN ( 'FL', 'WI', 'KS' )
AND ws_net_profit BETWEEN 50 AND 250 ) ) AND ws_net_profit BETWEEN 50 AND 250 ) )
GROUP BY r_reason_desc GROUP BY r_reason_desc
ORDER BY Substr(r_reason_desc, 1, 20), ORDER BY SUBSTRING(r_reason_desc, 1, 20),
Avg(ws_quantity), Avg(ws_quantity),
Avg(wr_refunded_cash), Avg(wr_refunded_cash),
Avg(wr_fee) Avg(wr_fee)
LIMIT 100; LIMIT 100;
SELECT SELECT
SUBSTR("reason"."r_reason_desc", 1, 20) AS "_col_0", SUBSTRING("reason"."r_reason_desc", 1, 20) AS "_col_0",
AVG("web_sales"."ws_quantity") AS "_col_1", AVG("web_sales"."ws_quantity") AS "_col_1",
AVG("web_returns"."wr_refunded_cash") AS "_col_2", AVG("web_returns"."wr_refunded_cash") AS "_col_2",
AVG("web_returns"."wr_fee") AS "_col_3" AVG("web_returns"."wr_fee") AS "_col_3"
@ -12617,7 +12617,7 @@ ORDER BY
-- TPC-DS 99 -- TPC-DS 99
-------------------------------------- --------------------------------------
# execute: true # execute: true
SELECT Substr(w_warehouse_name, 1, 20) AS "_col_0", SELECT SUBSTRING(w_warehouse_name, 1, 20) AS "_col_0",
sm_type, sm_type,
cc_name, cc_name,
Sum(CASE Sum(CASE
@ -12654,15 +12654,15 @@ WHERE d_month_seq BETWEEN 1200 AND 1200 + 11
AND cs_warehouse_sk = w_warehouse_sk AND cs_warehouse_sk = w_warehouse_sk
AND cs_ship_mode_sk = sm_ship_mode_sk AND cs_ship_mode_sk = sm_ship_mode_sk
AND cs_call_center_sk = cc_call_center_sk AND cs_call_center_sk = cc_call_center_sk
GROUP BY Substr(w_warehouse_name, 1, 20), GROUP BY SUBSTRING(w_warehouse_name, 1, 20),
sm_type, sm_type,
cc_name cc_name
ORDER BY Substr(w_warehouse_name, 1, 20), ORDER BY SUBSTRING(w_warehouse_name, 1, 20),
sm_type, sm_type,
cc_name cc_name
LIMIT 100; LIMIT 100;
SELECT SELECT
SUBSTR("warehouse"."w_warehouse_name", 1, 20) AS "_col_0", SUBSTRING("warehouse"."w_warehouse_name", 1, 20) AS "_col_0",
"ship_mode"."sm_type" AS "sm_type", "ship_mode"."sm_type" AS "sm_type",
"call_center"."cc_name" AS "cc_name", "call_center"."cc_name" AS "cc_name",
SUM( SUM(
@ -12715,7 +12715,7 @@ JOIN "ship_mode" AS "ship_mode"
JOIN "warehouse" AS "warehouse" JOIN "warehouse" AS "warehouse"
ON "catalog_sales"."cs_warehouse_sk" = "warehouse"."w_warehouse_sk" ON "catalog_sales"."cs_warehouse_sk" = "warehouse"."w_warehouse_sk"
GROUP BY GROUP BY
SUBSTR("warehouse"."w_warehouse_name", 1, 20), SUBSTRING("warehouse"."w_warehouse_name", 1, 20),
"ship_mode"."sm_type", "ship_mode"."sm_type",
"call_center"."cc_name" "call_center"."cc_name"
ORDER BY ORDER BY

View file

@ -761,6 +761,16 @@ class TestBuild(unittest.TestCase):
), ),
"MERGE INTO target_table AS target USING source_table AS source ON target.id = source.id WHEN MATCHED THEN UPDATE SET target.name = source.name", "MERGE INTO target_table AS target USING source_table AS source ON target.id = source.id WHEN MATCHED THEN UPDATE SET target.name = source.name",
), ),
(
lambda: exp.merge(
"WHEN MATCHED THEN UPDATE SET target.name = source.name",
into=exp.table_("target_table").as_("target"),
using=exp.table_("source_table").as_("source"),
on="target.id = source.id",
returning="target.*",
),
"MERGE INTO target_table AS target USING source_table AS source ON target.id = source.id WHEN MATCHED THEN UPDATE SET target.name = source.name RETURNING target.*",
),
]: ]:
with self.subTest(sql): with self.subTest(sql):
self.assertEqual(expression().sql(dialect[0] if dialect else None), sql) self.assertEqual(expression().sql(dialect[0] if dialect else None), sql)

View file

@ -1,14 +1,18 @@
import unittest import unittest
from sqlglot import exp, parse_one from sqlglot import exp, parse_one
from sqlglot.diff import Insert, Keep, Move, Remove, Update, diff from sqlglot.diff import Insert, Move, Remove, Update, diff
from sqlglot.expressions import Join, to_table from sqlglot.expressions import Join, to_table
def diff_delta_only(source, target, matchings=None, **kwargs):
return diff(source, target, matchings=matchings, delta_only=True, **kwargs)
class TestDiff(unittest.TestCase): class TestDiff(unittest.TestCase):
def test_simple(self): def test_simple(self):
self._validate_delta_only( self._validate_delta_only(
diff(parse_one("SELECT a + b"), parse_one("SELECT a - b")), diff_delta_only(parse_one("SELECT a + b"), parse_one("SELECT a - b")),
[ [
Remove(parse_one("a + b")), # the Add node Remove(parse_one("a + b")), # the Add node
Insert(parse_one("a - b")), # the Sub node Insert(parse_one("a - b")), # the Sub node
@ -16,21 +20,21 @@ class TestDiff(unittest.TestCase):
) )
self._validate_delta_only( self._validate_delta_only(
diff(parse_one("SELECT a, b, c"), parse_one("SELECT a, c")), diff_delta_only(parse_one("SELECT a, b, c"), parse_one("SELECT a, c")),
[ [
Remove(parse_one("b")), # the Column node Remove(parse_one("b")), # the Column node
], ],
) )
self._validate_delta_only( self._validate_delta_only(
diff(parse_one("SELECT a, b"), parse_one("SELECT a, b, c")), diff_delta_only(parse_one("SELECT a, b"), parse_one("SELECT a, b, c")),
[ [
Insert(parse_one("c")), # the Column node Insert(parse_one("c")), # the Column node
], ],
) )
self._validate_delta_only( self._validate_delta_only(
diff( diff_delta_only(
parse_one("SELECT a FROM table_one"), parse_one("SELECT a FROM table_one"),
parse_one("SELECT a FROM table_two"), parse_one("SELECT a FROM table_two"),
), ),
@ -44,7 +48,9 @@ class TestDiff(unittest.TestCase):
def test_lambda(self): def test_lambda(self):
self._validate_delta_only( self._validate_delta_only(
diff(parse_one("SELECT a, b, c, x(a -> a)"), parse_one("SELECT a, b, c, x(b -> b)")), diff_delta_only(
parse_one("SELECT a, b, c, x(a -> a)"), parse_one("SELECT a, b, c, x(b -> b)")
),
[ [
Update( Update(
exp.Lambda(this=exp.to_identifier("a"), expressions=[exp.to_identifier("a")]), exp.Lambda(this=exp.to_identifier("a"), expressions=[exp.to_identifier("a")]),
@ -55,14 +61,16 @@ class TestDiff(unittest.TestCase):
def test_udf(self): def test_udf(self):
self._validate_delta_only( self._validate_delta_only(
diff(parse_one('SELECT a, b, "my.udf1"()'), parse_one('SELECT a, b, "my.udf2"()')), diff_delta_only(
parse_one('SELECT a, b, "my.udf1"()'), parse_one('SELECT a, b, "my.udf2"()')
),
[ [
Insert(parse_one('"my.udf2"()')), Insert(parse_one('"my.udf2"()')),
Remove(parse_one('"my.udf1"()')), Remove(parse_one('"my.udf1"()')),
], ],
) )
self._validate_delta_only( self._validate_delta_only(
diff( diff_delta_only(
parse_one('SELECT a, b, "my.udf"(x, y, z)'), parse_one('SELECT a, b, "my.udf"(x, y, z)'),
parse_one('SELECT a, b, "my.udf"(x, y, w)'), parse_one('SELECT a, b, "my.udf"(x, y, w)'),
), ),
@ -74,28 +82,28 @@ class TestDiff(unittest.TestCase):
def test_node_position_changed(self): def test_node_position_changed(self):
self._validate_delta_only( self._validate_delta_only(
diff(parse_one("SELECT a, b, c"), parse_one("SELECT c, a, b")), diff_delta_only(parse_one("SELECT a, b, c"), parse_one("SELECT c, a, b")),
[ [
Move(parse_one("c")), # the Column node Move(parse_one("c")), # the Column node
], ],
) )
self._validate_delta_only( self._validate_delta_only(
diff(parse_one("SELECT a + b"), parse_one("SELECT b + a")), diff_delta_only(parse_one("SELECT a + b"), parse_one("SELECT b + a")),
[ [
Move(parse_one("a")), # the Column node Move(parse_one("a")), # the Column node
], ],
) )
self._validate_delta_only( self._validate_delta_only(
diff(parse_one("SELECT aaaa AND bbbb"), parse_one("SELECT bbbb AND aaaa")), diff_delta_only(parse_one("SELECT aaaa AND bbbb"), parse_one("SELECT bbbb AND aaaa")),
[ [
Move(parse_one("aaaa")), # the Column node Move(parse_one("aaaa")), # the Column node
], ],
) )
self._validate_delta_only( self._validate_delta_only(
diff( diff_delta_only(
parse_one("SELECT aaaa OR bbbb OR cccc"), parse_one("SELECT aaaa OR bbbb OR cccc"),
parse_one("SELECT cccc OR bbbb OR aaaa"), parse_one("SELECT cccc OR bbbb OR aaaa"),
), ),
@ -120,7 +128,7 @@ class TestDiff(unittest.TestCase):
""" """
self._validate_delta_only( self._validate_delta_only(
diff(parse_one(expr_src), parse_one(expr_tgt)), diff_delta_only(parse_one(expr_src), parse_one(expr_tgt)),
[ [
Remove(parse_one("LOWER(c) AS c")), # the Alias node Remove(parse_one("LOWER(c) AS c")), # the Alias node
Remove(parse_one("LOWER(c)")), # the Lower node Remove(parse_one("LOWER(c)")), # the Lower node
@ -133,8 +141,7 @@ class TestDiff(unittest.TestCase):
expr_src = "SELECT a, b FROM t1 LEFT JOIN t2 ON t1.key = t2.key" expr_src = "SELECT a, b FROM t1 LEFT JOIN t2 ON t1.key = t2.key"
expr_tgt = "SELECT a, b FROM t1 RIGHT JOIN t2 ON t1.key = t2.key" expr_tgt = "SELECT a, b FROM t1 RIGHT JOIN t2 ON t1.key = t2.key"
changes = diff(parse_one(expr_src), parse_one(expr_tgt)) changes = diff_delta_only(parse_one(expr_src), parse_one(expr_tgt))
changes = _delta_only(changes)
self.assertEqual(len(changes), 2) self.assertEqual(len(changes), 2)
self.assertTrue(isinstance(changes[0], Remove)) self.assertTrue(isinstance(changes[0], Remove))
@ -145,10 +152,10 @@ class TestDiff(unittest.TestCase):
expr_src = parse_one("SELECT ROW_NUMBER() OVER (PARTITION BY a ORDER BY b)") expr_src = parse_one("SELECT ROW_NUMBER() OVER (PARTITION BY a ORDER BY b)")
expr_tgt = parse_one("SELECT RANK() OVER (PARTITION BY a ORDER BY b)") expr_tgt = parse_one("SELECT RANK() OVER (PARTITION BY a ORDER BY b)")
self._validate_delta_only(diff(expr_src, expr_src), []) self._validate_delta_only(diff_delta_only(expr_src, expr_src), [])
self._validate_delta_only( self._validate_delta_only(
diff(expr_src, expr_tgt), diff_delta_only(expr_src, expr_tgt),
[ [
Remove(parse_one("ROW_NUMBER()")), # the Anonymous node Remove(parse_one("ROW_NUMBER()")), # the Anonymous node
Insert(parse_one("RANK()")), # the Anonymous node Insert(parse_one("RANK()")), # the Anonymous node
@ -160,7 +167,7 @@ class TestDiff(unittest.TestCase):
expr_tgt = parse_one("SELECT 1, 2, 3, 4") expr_tgt = parse_one("SELECT 1, 2, 3, 4")
self._validate_delta_only( self._validate_delta_only(
diff(expr_src, expr_tgt), diff_delta_only(expr_src, expr_tgt),
[ [
Remove(expr_src), Remove(expr_src),
Insert(expr_tgt), Insert(expr_tgt),
@ -171,7 +178,7 @@ class TestDiff(unittest.TestCase):
) )
self._validate_delta_only( self._validate_delta_only(
diff(expr_src, expr_tgt, matchings=[(expr_src, expr_tgt)]), diff_delta_only(expr_src, expr_tgt, matchings=[(expr_src, expr_tgt)]),
[ [
Insert(exp.Literal.number(2)), Insert(exp.Literal.number(2)),
Insert(exp.Literal.number(3)), Insert(exp.Literal.number(3)),
@ -180,23 +187,20 @@ class TestDiff(unittest.TestCase):
) )
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
diff(expr_src, expr_tgt, matchings=[(expr_src, expr_tgt), (expr_src, expr_tgt)]) diff_delta_only(
expr_src, expr_tgt, matchings=[(expr_src, expr_tgt), (expr_src, expr_tgt)]
)
def test_identifier(self): def test_identifier(self):
expr_src = parse_one("SELECT a FROM tbl") expr_src = parse_one("SELECT a FROM tbl")
expr_tgt = parse_one("SELECT a, tbl.b from tbl") expr_tgt = parse_one("SELECT a, tbl.b from tbl")
self._validate_delta_only( self._validate_delta_only(
diff(expr_src, expr_tgt), diff_delta_only(expr_src, expr_tgt),
[ [
Insert(expression=exp.to_column("tbl.b")), Insert(expression=exp.to_column("tbl.b")),
], ],
) )
def _validate_delta_only(self, actual_diff, expected_delta): def _validate_delta_only(self, actual_delta, expected_delta):
actual_delta = _delta_only(actual_diff)
self.assertEqual(set(actual_delta), set(expected_delta)) self.assertEqual(set(actual_delta), set(expected_delta))
def _delta_only(changes):
return [d for d in changes if not isinstance(d, Keep)]

View file

@ -674,6 +674,8 @@ class TestExpressions(unittest.TestCase):
self.assertIsInstance(parse_one("STR_POSITION(a, 'test')"), exp.StrPosition) self.assertIsInstance(parse_one("STR_POSITION(a, 'test')"), exp.StrPosition)
self.assertIsInstance(parse_one("STR_TO_UNIX(a, 'format')"), exp.StrToUnix) self.assertIsInstance(parse_one("STR_TO_UNIX(a, 'format')"), exp.StrToUnix)
self.assertIsInstance(parse_one("STRUCT_EXTRACT(a, 'test')"), exp.StructExtract) self.assertIsInstance(parse_one("STRUCT_EXTRACT(a, 'test')"), exp.StructExtract)
self.assertIsInstance(parse_one("SUBSTR('a', 1, 1)"), exp.Substring)
self.assertIsInstance(parse_one("SUBSTRING('a', 1, 1)"), exp.Substring)
self.assertIsInstance(parse_one("SUM(a)"), exp.Sum) self.assertIsInstance(parse_one("SUM(a)"), exp.Sum)
self.assertIsInstance(parse_one("SQRT(a)"), exp.Sqrt) self.assertIsInstance(parse_one("SQRT(a)"), exp.Sqrt)
self.assertIsInstance(parse_one("STDDEV(a)"), exp.Stddev) self.assertIsInstance(parse_one("STDDEV(a)"), exp.Stddev)

View file

@ -857,7 +857,6 @@ FROM x""",
"CREATE OR REPLACE STAGE", "CREATE OR REPLACE STAGE",
"EXECUTE statement", "EXECUTE statement",
"EXPLAIN SELECT * FROM x", "EXPLAIN SELECT * FROM x",
"GRANT INSERT ON foo TO bla",
"LOAD foo", "LOAD foo",
"OPTIMIZE TABLE y", "OPTIMIZE TABLE y",
"PREPARE statement", "PREPARE statement",