1
0
Fork 0

Merging 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:19 +01:00
parent a52cca819a
commit a43c78d8b5
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 }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- id: check_deploy
run: |
bash ./.github/workflows/should_deploy_sqlglotrs.sh
if [ $? -eq 0 ]; then echo "deploy=true" >> $GITHUB_OUTPUT; fi
bash ./.github/workflows/should_deploy_sqlglotrs.sh \
&& echo "deploy=true" >> $GITHUB_OUTPUT \
|| echo "deploy=false" >> $GITHUB_OUTPUT
build-rs:
needs: should-deploy-rs

View file

@ -1,6 +1,128 @@
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
### :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))*
@ -4754,3 +4876,8 @@ Changelog
[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.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 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.

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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-46"><a href="#L-46"><span class="linenos"> 46</span></a><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-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-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-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-51"><a href="#L-51"><span class="linenos"> 51</span></a>
</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-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-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-55"><a href="#L-55"><span class="linenos"> 55</span></a>
</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-57"><a href="#L-57"><span class="linenos"> 57</span></a>
</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">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">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">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">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">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">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">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">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">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">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">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">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_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_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">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="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="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.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.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.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 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><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._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 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><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-59"><a href="#L-59"><span class="linenos"> 59</span></a><span class="k">try</span><span class="p">:</span>
</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-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-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-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-64"><a href="#L-64"><span class="linenos"> 64</span></a> <span class="p">)</span>
</span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a>
</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="k">try</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="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="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="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 class="p">)</span>
</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-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-69"><a href="#L-69"><span class="linenos"> 69</span></a>
</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="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 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-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-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-73"><a href="#L-73"><span class="linenos"> 73</span></a><span class="sd"> Tokenizes the given SQL string.</span>
</span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a>
</span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a><span class="sd"> Args:</span>
</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-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-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-79"><a href="#L-79"><span class="linenos"> 79</span></a>
</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a><span class="sd"> Returns:</span>
</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-82"><a href="#L-82"><span class="linenos"> 82</span></a><span class="sd"> &quot;&quot;&quot;</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-84"><a href="#L-84"><span class="linenos"> 84</span></a>
</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="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="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 class="sd"> Tokenizes the given SQL string.</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"> Args:</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"> 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 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><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"> The resulting list of tokens.</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 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-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-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-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-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-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-91"><a href="#L-91"><span class="linenos"> 91</span></a>
</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a><span class="sd"> Args:</span>
</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-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-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-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-97"><a href="#L-97"><span class="linenos"> 97</span></a>
</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a><span class="sd"> Returns:</span>
</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-100"><a href="#L-100"><span class="linenos">100</span></a><span class="sd"> &quot;&quot;&quot;</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-102"><a href="#L-102"><span class="linenos">102</span></a>
</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="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="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="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="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 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><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"> 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"> 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"> dialect: the SQL dialect (alias for read).</span>
</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><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"> The resulting syntax tree collection.</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 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-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-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-106"><a href="#L-106"><span class="linenos">106</span></a>
</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="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 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-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-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-110"><a href="#L-110"><span class="linenos">110</span></a>
</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="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 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-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-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-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-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-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-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-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-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-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-121"><a href="#L-121"><span class="linenos">121</span></a>
</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a><span class="sd"> Args:</span>
</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-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-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-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-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-128"><a href="#L-128"><span class="linenos">128</span></a>
</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a><span class="sd"> Returns:</span>
</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-131"><a href="#L-131"><span class="linenos">131</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a>
</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-134"><a href="#L-134"><span class="linenos">134</span></a>
</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-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-137"><a href="#L-137"><span class="linenos">137</span></a> <span class="k">else</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-139"><a href="#L-139"><span class="linenos">139</span></a>
</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-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-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-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-144"><a href="#L-144"><span class="linenos">144</span></a> <span class="k">else</span><span class="p">:</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-146"><a href="#L-146"><span class="linenos">146</span></a>
</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="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">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">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">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="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="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="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="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 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><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"> 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"> 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"> 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"> into: the SQLGlot Expression to parse into.</span>
</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><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"> 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 class="sd"> &quot;&quot;&quot;</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 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><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="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="k">else</span><span class="p">:</span>
</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><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">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">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">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">else</span><span class="p">:</span>
</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-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-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-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-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-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-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-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-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-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-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-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-159"><a href="#L-159"><span class="linenos">159</span></a>
</span><span id="L-160"><a href="#L-160"><span class="linenos">160</span></a><span class="sd"> Args:</span>
</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-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-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-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-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-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-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-168"><a href="#L-168"><span class="linenos">168</span></a>
</span><span id="L-169"><a href="#L-169"><span class="linenos">169</span></a><span class="sd"> Returns:</span>
</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-171"><a href="#L-171"><span class="linenos">171</span></a><span class="sd"> &quot;&quot;&quot;</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-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-174"><a href="#L-174"><span class="linenos">174</span></a> <span class="k">return</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-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-177"><a href="#L-177"><span class="linenos">177</span></a> <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="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">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">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">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">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="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="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="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="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"> 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 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><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"> 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"> 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"> 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"> 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"> 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"> 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 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><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"> The list of transpiled SQL statements.</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="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="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="k">return</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="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>
@ -957,19 +958,19 @@ make check # Full test suite &amp; linter checks
</div>
<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>
</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="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 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"> 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><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"> 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="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>
<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-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-75"><a href="#tokenize-75"><span class="linenos">75</span></a><span class="sd"> Tokenizes the given SQL string.</span>
</span><span id="tokenize-76"><a href="#tokenize-76"><span class="linenos">76</span></a>
</span><span id="tokenize-77"><a href="#tokenize-77"><span class="linenos">77</span></a><span class="sd"> Args:</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-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-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-81"><a href="#tokenize-81"><span class="linenos">81</span></a>
</span><span id="tokenize-82"><a href="#tokenize-82"><span class="linenos">82</span></a><span class="sd"> Returns:</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-84"><a href="#tokenize-84"><span class="linenos">84</span></a><span class="sd"> &quot;&quot;&quot;</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>
@ -1003,22 +1004,22 @@ make check # Full test suite &amp; linter checks
</div>
<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>
</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="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="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 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"> 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"> **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 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"> &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>
<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-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-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-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-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-93"><a href="#parse-93"><span class="linenos"> 93</span></a>
</span><span id="parse-94"><a href="#parse-94"><span class="linenos"> 94</span></a><span class="sd"> Args:</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-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-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-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-99"><a href="#parse-99"><span class="linenos"> 99</span></a>
</span><span id="parse-100"><a href="#parse-100"><span class="linenos">100</span></a><span class="sd"> Returns:</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-102"><a href="#parse-102"><span class="linenos">102</span></a><span class="sd"> &quot;&quot;&quot;</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>
@ -1053,40 +1054,40 @@ make check # Full test suite &amp; linter checks
</div>
<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>
</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">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">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="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="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 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"> 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"> 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><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"> 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><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><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="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="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 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">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">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>
<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-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-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-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-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-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-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-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-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-123"><a href="#parse_one-123"><span class="linenos">123</span></a>
</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-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-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-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-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-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-130"><a href="#parse_one-130"><span class="linenos">130</span></a>
</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-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-133"><a href="#parse_one-133"><span class="linenos">133</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="parse_one-134"><a href="#parse_one-134"><span class="linenos">134</span></a>
</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-136"><a href="#parse_one-136"><span class="linenos">136</span></a>
</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-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-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-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-141"><a href="#parse_one-141"><span class="linenos">141</span></a>
</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-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-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-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-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-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>
@ -1122,36 +1123,36 @@ make check # Full test suite &amp; linter checks
</div>
<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>
</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">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">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="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="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"> 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 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"> 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"> 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"> 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><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"> 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="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="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="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>
<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-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-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-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-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-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-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-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-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-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-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-161"><a href="#transpile-161"><span class="linenos">161</span></a>
</span><span id="transpile-162"><a href="#transpile-162"><span class="linenos">162</span></a><span class="sd"> Args:</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-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-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-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-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-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-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-170"><a href="#transpile-170"><span class="linenos">170</span></a>
</span><span id="transpile-171"><a href="#transpile-171"><span class="linenos">171</span></a><span class="sd"> Returns:</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-173"><a href="#transpile-173"><span class="linenos">173</span></a><span class="sd"> &quot;&quot;&quot;</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-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-176"><a href="#transpile-176"><span class="linenos">176</span></a> <span class="k">return</span> <span class="p">[</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-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-179"><a href="#transpile-179"><span class="linenos">179</span></a> <span class="p">]</span>
</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-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-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-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-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">23</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
</span></pre></div>
@ -97,7 +97,7 @@
<section id="version">
<div class="attr variable">
<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>
@ -109,7 +109,7 @@
<section id="version_tuple">
<div class="attr variable">
<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>

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.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.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><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">
<div class="attr variable">
<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>

View file

@ -586,7 +586,7 @@
<div class="attr variable">
<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">
<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>

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">
<span class="name">UNMERGABLE_ARGS</span> =
<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>

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,
column as column,
condition as condition,
delete as delete,
except_ as except_,
from_ as from_,
func as func,

View file

@ -20,12 +20,40 @@ def _generate_as_hive(expression: exp.Expression) -> bool:
else:
return expression.kind != "VIEW" # CREATE VIEW is never Hive but CREATE SCHEMA etc is
elif isinstance(expression, exp.Alter) or isinstance(expression, exp.Drop):
return True # all ALTER and DROP statements are Hive
# https://docs.aws.amazon.com/athena/latest/ug/ddl-reference.html
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
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):
"""
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:
- Uses double quotes to quote identifiers
- Used for DDL operations that involve SELECT queries, eg:
- CREATE VIEW
- CREATE VIEW / DROP VIEW
- CREATE TABLE... AS SELECT
- Used for DML operations
- SELECT, INSERT, UPDATE, DELETE, MERGE
@ -79,19 +107,32 @@ class Athena(Trino):
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):
"""
Generate queries for the Athena Trino execution engine
"""
TYPE_MAPPING = {
**Trino.Generator.TYPE_MAPPING,
exp.DataType.Type.TEXT: "STRING",
PROPERTIES_LOCATION = {
**Trino.Generator.PROPERTIES_LOCATION,
exp.LocationProperty: exp.Properties.Location.POST_WITH,
}
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):
@ -99,7 +140,7 @@ class Athena(Trino):
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:
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)
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(
self: BigQuery.Generator, expression: exp.StrToDate | exp.StrToTime
) -> str:
@ -377,13 +392,7 @@ class BigQuery(Dialect):
),
"PARSE_TIMESTAMP": _build_parse_timestamp,
"REGEXP_CONTAINS": exp.RegexpLike.from_arg_list,
"REGEXP_EXTRACT": lambda args: 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 re.compile(args[1].name).groups == 1 else None,
),
"REGEXP_EXTRACT": _build_regexp_extract,
"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)),
"SPLIT": lambda args: exp.Split(
@ -471,7 +480,7 @@ class BigQuery(Dialect):
table_name = this.name
while self._match(TokenType.DASH, advance=False) and self._next:
text = ""
while self._curr and self._curr.token_type != TokenType.DOT:
while self._is_connected() and self._curr.token_type != TokenType.DOT:
self._advance()
text += self._prev.text
table_name += text

View file

@ -396,6 +396,7 @@ class ClickHouse(Dialect):
**parser.Parser.FUNCTION_PARSERS,
"ARRAYJOIN": lambda self: self.expression(exp.Explode, this=self._parse_expression()),
"QUANTILE": lambda self: self._parse_quantile(),
"COLUMNS": lambda self: self._parse_columns(),
}
FUNCTION_PARSERS.pop("MATCH")
@ -756,6 +757,34 @@ class ClickHouse(Dialect):
def _parse_constraint(self) -> t.Optional[exp.Expression]:
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):
QUERY_HINTS = False
STRUCT_DELIMITER = ("(", ")")
@ -898,9 +927,10 @@ class ClickHouse(Dialect):
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.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
@ -1069,7 +1099,9 @@ class ClickHouse(Dialect):
[self.sql(prop) for prop in locations[exp.Properties.Location.POST_NAME]]
)
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)

View file

@ -546,7 +546,7 @@ class Hive(Dialect):
exp.SchemaCommentProperty: lambda self, e: self.naked_property(e),
exp.ArrayUniqueAgg: rename_func("COLLECT_SET"),
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(
[

View file

@ -62,6 +62,7 @@ def diff(
source: exp.Expression,
target: exp.Expression,
matchings: t.List[t.Tuple[exp.Expression, exp.Expression]] | None = None,
delta_only: bool = False,
**kwargs: t.Any,
) -> t.List[Edit]:
"""
@ -89,6 +90,8 @@ def diff(
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
referenced in source / target trees.
delta_only: excludes all `Keep` nodes from the diff.
kwargs: additional arguments to pass to the ChangeDistiller instance.
Returns:
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]
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.
@ -149,6 +157,7 @@ class ChangeDistiller:
source: exp.Expression,
target: exp.Expression,
matchings: t.List[t.Tuple[exp.Expression, exp.Expression]] | None = None,
delta_only: bool = False,
) -> t.List[Edit]:
matchings = matchings or []
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]] = {}
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] = []
for removed_node_id in self._unmatched_source_nodes:
edit_script.append(Remove(self._source_index[removed_node_id]))
@ -186,6 +199,7 @@ class ChangeDistiller:
edit_script.extend(
self._generate_move_edits(source_node, target_node, matching_set)
)
if not delta_only:
edit_script.append(Keep(source_node, target_node))
else:
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
import datetime
import math
import numbers
@ -36,6 +35,7 @@ from sqlglot.helper import (
from sqlglot.tokens import Token, TokenError
if t.TYPE_CHECKING:
from typing_extensions import Self
from sqlglot._typing import E, Lit
from sqlglot.dialects.dialect import DialectType
@ -1368,7 +1368,7 @@ class DML(Expression):
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> DML:
) -> "Self":
"""
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):
arg_types = {
"expressions": False,
@ -2570,6 +2580,14 @@ class Property(Expression):
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):
arg_types = {"expressions": True}
@ -4123,6 +4141,7 @@ class DataType(Expression):
NUMRANGE = auto()
NVARCHAR = auto()
OBJECT = auto()
RANGE = auto()
ROWVERSION = auto()
SERIAL = auto()
SET = auto()
@ -4154,6 +4173,7 @@ class DataType(Expression):
UINT256 = auto()
UMEDIUMINT = auto()
UDECIMAL = auto()
UNION = auto()
UNIQUEIDENTIFIER = auto()
UNKNOWN = auto() # Sentinel value, useful for type annotation
USERDEFINED = "USER-DEFINED"
@ -4172,6 +4192,7 @@ class DataType(Expression):
Type.NESTED,
Type.OBJECT,
Type.STRUCT,
Type.UNION,
}
ARRAY_TYPES = {
@ -4396,6 +4417,15 @@ class Alter(Expression):
"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):
arg_types = {"expressions": True}
@ -4911,6 +4941,10 @@ class ApproxDistinct(AggFunc):
_sql_names = ["APPROX_DISTINCT", "APPROX_COUNT_DISTINCT"]
class Apply(Func):
arg_types = {"this": True, "expression": True}
class Array(Func):
arg_types = {"expressions": False, "bracket_notation": False}
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
class Convert(Func):
arg_types = {"this": True, "expression": True, "style": False}
@ -5875,6 +5913,10 @@ class Normalize(Func):
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
class Predict(Func):
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
# https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
class Substring(Func):
_sql_names = ["SUBSTRING", "SUBSTR"]
arg_types = {"this": True, "start": False, "length": False}
@ -6209,10 +6252,6 @@ class UnixToTimeStr(Func):
pass
class UnpackColumns(Func):
pass
class Uuid(Func):
_sql_names = ["UUID", "GEN_RANDOM_UUID", "GENERATE_UUID", "UUID_STRING"]
@ -6274,7 +6313,7 @@ class Use(Expression):
arg_types = {"this": True, "kind": False}
class Merge(Expression):
class Merge(DML):
arg_types = {
"this": True,
"using": True,
@ -6838,9 +6877,7 @@ def delete(
if where:
delete_expr = delete_expr.where(where, dialect=dialect, copy=False, **opts)
if returning:
delete_expr = t.cast(
Delete, delete_expr.returning(returning, dialect=dialect, copy=False, **opts)
)
delete_expr = delete_expr.returning(returning, dialect=dialect, copy=False, **opts)
return delete_expr
@ -6883,7 +6920,7 @@ def insert(
insert = Insert(this=this, expression=expr, overwrite=overwrite)
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
@ -6893,6 +6930,7 @@ def merge(
into: ExpOrStr,
using: ExpOrStr,
on: ExpOrStr,
returning: t.Optional[ExpOrStr] = None,
dialect: DialectType = None,
copy: bool = True,
**opts,
@ -6913,6 +6951,7 @@ def merge(
into: The target table to merge data into.
using: The source table to merge data from.
on: The join condition for the merge.
returning: The columns to return from the merge.
dialect: The dialect used to parse the input expressions.
copy: Whether to copy the expression.
**opts: Other options to use to parse the input expressions.
@ -6920,7 +6959,7 @@ def merge(
Returns:
Merge: The syntax tree for the MERGE statement.
"""
return Merge(
merge = Merge(
this=maybe_parse(into, dialect=dialect, copy=copy, **opts),
using=maybe_parse(using, 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
],
)
if returning:
merge = merge.returning(returning, dialect=dialect, copy=False, **opts)
return merge
def condition(

View file

@ -192,7 +192,6 @@ class Generator(metaclass=_Generator):
exp.TransientProperty: lambda *_: "TRANSIENT",
exp.Union: lambda self, e: self.set_operations(e),
exp.UnloggedProperty: lambda *_: "UNLOGGED",
exp.UnpackColumns: lambda self, e: f"*{self.sql(e.this)}",
exp.Uuid: lambda *_: "UUID()",
exp.UppercaseColumnConstraint: lambda *_: "UPPERCASE",
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})"
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
)
return f"{values} AS {alias}" if alias else values
@ -3625,13 +3625,15 @@ class Generator(metaclass=_Generator):
using = f"USING {self.sql(expression, 'using')}"
on = f"ON {self.sql(expression, 'on')}"
expressions = self.expressions(expression, sep=" ", indent=False)
returning = self.sql(expression, "returning")
if returning:
expressions = f"{expressions}{returning}"
sep = self.sep()
returning = self.expressions(expression, key="returning", indent=False)
returning = f"RETURNING {returning}" if returning else ""
return self.prepend_ctes(
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")
@ -4323,6 +4325,65 @@ class Generator(metaclass=_Generator):
parent_cond = parent.expression.this
parent_cond.replace(parent_cond.and_(expression.this.is_(exp.null()).not_()))
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
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)
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
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__)(

View file

@ -260,6 +260,7 @@ class Parser(metaclass=_Parser):
TokenType.NESTED,
TokenType.OBJECT,
TokenType.STRUCT,
TokenType.UNION,
}
NESTED_TYPE_TOKENS = {
@ -268,6 +269,7 @@ class Parser(metaclass=_Parser):
TokenType.LOWCARDINALITY,
TokenType.MAP,
TokenType.NULLABLE,
TokenType.RANGE,
*STRUCT_TYPE_TOKENS,
}
@ -522,6 +524,7 @@ class Parser(metaclass=_Parser):
*TYPE_TOKENS,
*NO_PAREN_FUNCTIONS,
}
ID_VAR_TOKENS.remove(TokenType.UNION)
INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
@ -777,6 +780,7 @@ class Parser(metaclass=_Parser):
TokenType.DESC: lambda self: self._parse_describe(),
TokenType.DESCRIBE: lambda self: self._parse_describe(),
TokenType.DROP: lambda self: self._parse_drop(),
TokenType.GRANT: lambda self: self._parse_grant(),
TokenType.INSERT: lambda self: self._parse_insert(),
TokenType.KILL: lambda self: self._parse_kill(),
TokenType.LOAD: lambda self: self._parse_load(),
@ -1103,6 +1107,7 @@ class Parser(metaclass=_Parser):
"MATCH": lambda self: self._parse_match_against(),
"NORMALIZE": lambda self: self._parse_normalize(),
"OPENJSON": lambda self: self._parse_open_json(),
"OVERLAY": lambda self: self._parse_overlay(),
"POSITION": lambda self: self._parse_position(),
"PREDICT": lambda self: self._parse_predict(),
"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"}
PRIVILEGE_FOLLOW_TOKENS = {TokenType.ON, TokenType.COMMA, TokenType.L_PAREN}
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
@ -2982,6 +2989,13 @@ class Parser(metaclass=_Parser):
if table
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))
self._match_r_paren()
@ -4341,6 +4355,9 @@ class Parser(metaclass=_Parser):
)
while self._match_set(self.ASSIGNMENT):
if isinstance(this, exp.Column) and len(this.parts) == 1:
this = this.this
this = self.expression(
self.ASSIGNMENT[self._prev.token_type],
this=this,
@ -5034,7 +5051,7 @@ class Parser(metaclass=_Parser):
if not field:
self.raise_error("Expected type")
elif op and self._curr:
field = self._parse_column_reference()
field = self._parse_column_reference() or self._parse_bracket()
else:
field = self._parse_field(any_token=True, anonymous_func=True)
@ -6841,7 +6858,7 @@ class Parser(metaclass=_Parser):
using=using,
on=on,
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]:
@ -7384,9 +7401,12 @@ class Parser(metaclass=_Parser):
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):
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(
exp.Star,
@ -7396,3 +7416,72 @@ class Parser(metaclass=_Parser):
"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()
GLOB = auto()
GLOBAL = auto()
GRANT = auto()
GROUP_BY = auto()
GROUPING_SETS = auto()
HAVING = auto()
@ -903,7 +904,7 @@ class Tokenizer(metaclass=_Tokenizer):
"CALL": TokenType.COMMAND,
"COMMENT": TokenType.COMMENT,
"EXPLAIN": TokenType.COMMAND,
"GRANT": TokenType.COMMAND,
"GRANT": TokenType.GRANT,
"OPTIMIZE": TokenType.COMMAND,
"PREPARE": TokenType.COMMAND,
"VACUUM": TokenType.COMMAND,

View file

@ -1,3 +1,4 @@
from sqlglot import exp
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"
)
# 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):
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`',
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(
'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"',
)
self.validate_identity("DESCRIBE foo.bar", write_sql="DESCRIBE `foo`.`bar`", identify=True)
def test_dml_quoting(self):
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"',
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
def test_bigquery(self):
self.validate_identity("REGEXP_EXTRACT(x, '(?<)')")
self.validate_all(
"EXTRACT(HOUR FROM DATETIME(2008, 12, 25, 15, 30, 00))",
write={
@ -1502,6 +1504,8 @@ WHERE
},
)
self.validate_identity("SELECT * FROM a-b c", "SELECT * FROM a-b AS c")
def test_errors(self):
with self.assertRaises(TokenError):
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",
},
)
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"
)
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(
"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(
"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("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):
values = exp.select("*").from_(
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'",
)
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 dates (dt1 Date32) ENGINE=TinyLog()""")
self.validate_identity("CREATE TABLE named_tuples (a Tuple(select String, i Int64))")
@ -1084,3 +1096,7 @@ LIFETIME(MIN 0 MAX 0)""",
self.assertEqual(
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(
"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(
"SUBSTR('123456', 2, 3)",
write={
"bigquery": "SUBSTR('123456', 2, 3)",
"bigquery": "SUBSTRING('123456', 2, 3)",
"oracle": "SUBSTR('123456', 2, 3)",
"postgres": "SUBSTR('123456', 2, 3)",
"postgres": "SUBSTRING('123456' FROM 2 FOR 3)",
},
)
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"
)
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("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)")
@ -294,6 +295,9 @@ class TestDuckDB(Validator):
self.validate_identity("SUMMARIZE 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("UNION_VALUE(k1 := 1)").find(exp.PropertyEQ).this.assert_is(
exp.Identifier
)
self.validate_identity(
"SELECT species, island, COUNT(*) FROM t GROUP BY GROUPING SETS (species), GROUPING SETS (island)"
)
@ -309,6 +313,13 @@ class TestDuckDB(Validator):
self.validate_identity(
"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(
"SELECT col FROM t WHERE JSON_EXTRACT_STRING(col, '$.id') NOT IN ('b')",
"SELECT col FROM t WHERE NOT (col ->> '$.id') IN ('b')",
@ -524,8 +535,8 @@ class TestDuckDB(Validator):
write={
"duckdb": "STR_SPLIT(x, 'a')",
"presto": "SPLIT(x, 'a')",
"hive": "SPLIT(x, CONCAT('\\\\Q', 'a'))",
"spark": "SPLIT(x, CONCAT('\\\\Q', 'a'))",
"hive": "SPLIT(x, CONCAT('\\\\Q', 'a', '\\\\E'))",
"spark": "SPLIT(x, CONCAT('\\\\Q', 'a', '\\\\E'))",
},
)
self.validate_all(
@ -533,8 +544,8 @@ class TestDuckDB(Validator):
write={
"duckdb": "STR_SPLIT(x, 'a')",
"presto": "SPLIT(x, 'a')",
"hive": "SPLIT(x, CONCAT('\\\\Q', 'a'))",
"spark": "SPLIT(x, CONCAT('\\\\Q', 'a'))",
"hive": "SPLIT(x, CONCAT('\\\\Q', 'a', '\\\\E'))",
"spark": "SPLIT(x, CONCAT('\\\\Q', 'a', '\\\\E'))",
},
)
self.validate_all(
@ -835,6 +846,18 @@ class TestDuckDB(Validator):
"SELECT id, STRUCT_PACK(*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):
with self.assertLogs(helper_logger) as cm:

View file

@ -1278,3 +1278,18 @@ COMMENT='客户账户表'"""
self.validate_identity(
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(
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(
"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):
# Checks that user-defined types are parsed into DataType instead of Identifier

View file

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

View file

@ -626,3 +626,36 @@ FROM (
"TIME_TO_STR(a, '%Y-%m-%d %H:%M:%S.%f')",
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={
"spark": "SELECT COLLECT_LIST(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(
@ -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 => 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)""",
write={
"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""",
"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""",
"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', ';', '\\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)""",
"hive": UnsupportedError,
},
@ -95,7 +95,7 @@ class TestStarrocks(Validator):
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)""",
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)""",
"hive": UnsupportedError,
},

View file

@ -1998,3 +1998,10 @@ FROM OPENJSON(@json) WITH (
"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 y
ILIKE(x, 'z')
x LIKE SUBSTR('abc', 1, 1)
x LIKE SUBSTRING('abc', 1, 1)
x LIKE y
x LIKE a.y
x LIKE '%y%'
@ -879,3 +879,8 @@ SELECT COUNT(DISTINCT "foo bar") FROM (SELECT 1 AS "foo bar") AS t
SELECT vector
WITH all AS (SELECT 1 AS count) SELECT all.count FROM all
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;
COALESCE(x, y) <> ALL (SELECT z FROM w);
COALESCE(x, y) <> ALL (SELECT z FROM w);
--------------------------------------
-- Absorption
--------------------------------------

View file

@ -991,9 +991,9 @@ FROM store_sales,
date_dim,
store,
(SELECT ca_zip
FROM (SELECT Substr(ca_zip, 1, 5) ca_zip
FROM (SELECT SUBSTRING(ca_zip, 1, 5) ca_zip
FROM customer_address
WHERE Substr(ca_zip, 1, 5) IN ( '67436', '26121', '38443',
WHERE SUBSTRING(ca_zip, 1, 5) IN ( '67436', '26121', '38443',
'63157',
'68856', '19485', '86425',
'26741',
@ -1195,7 +1195,7 @@ FROM store_sales,
'92564' )
INTERSECT
SELECT ca_zip
FROM (SELECT Substr(ca_zip, 1, 5) ca_zip,
FROM (SELECT SUBSTRING(ca_zip, 1, 5) ca_zip,
Count(*) cnt
FROM customer_address,
customer
@ -1207,13 +1207,13 @@ WHERE ss_store_sk = s_store_sk
AND ss_sold_date_sk = d_date_sk
AND d_qoy = 2
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
ORDER BY s_store_name
LIMIT 100;
WITH "a1" AS (
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"
JOIN "customer" AS "customer"
ON "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk"
@ -1224,10 +1224,10 @@ WITH "a1" AS (
COUNT(*) > 10
), "a2" AS (
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"
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
SELECT
"a1"."ca_zip" AS "ca_zip"
@ -1244,7 +1244,7 @@ JOIN "date_dim" AS "date_dim"
JOIN "store" AS "store"
ON "store"."s_store_sk" = "store_sales"."ss_store_sk"
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
"store"."s_store_name"
ORDER BY
@ -2319,7 +2319,7 @@ FROM catalog_sales,
date_dim
WHERE cs_bill_customer_sk = c_customer_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',
'81792' )
OR ca_state IN ( 'CA', 'WA', 'GA' )
@ -2344,7 +2344,7 @@ JOIN "customer_address" AS "customer_address"
ON (
"catalog_sales"."cs_sales_price" > 500
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"
GROUP BY
@ -2643,7 +2643,7 @@ WHERE d_date_sk = ss_sold_date_sk
AND d_year = 1998
AND ss_customer_sk = c_customer_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
GROUP BY i_brand,
i_brand_id,
@ -2672,7 +2672,7 @@ JOIN "customer_address" AS "customer_address"
ON "customer"."c_current_addr_sk" = "customer_address"."ca_address_sk"
JOIN "store" AS "store"
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
"date_dim"."d_moy" = 12 AND "date_dim"."d_year" = 1998
GROUP BY
@ -2895,7 +2895,7 @@ LIMIT 100;
--------------------------------------
# execute: true
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,
d_date solddate,
Count(*) cnt
@ -2905,7 +2905,7 @@ WITH frequent_ss_items
WHERE ss_sold_date_sk = d_date_sk
AND ss_item_sk = i_item_sk
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,
d_date
HAVING Count(*) > 4),
@ -2962,7 +2962,7 @@ WITH "frequent_ss_items" AS (
JOIN "item" AS "item"
ON "item"."i_item_sk" = "store_sales"."ss_item_sk"
GROUP BY
SUBSTR("item"."i_item_desc", 1, 30),
SUBSTRING("item"."i_item_desc", 1, 30),
"item"."i_item_sk",
"date_dim"."d_date"
HAVING
@ -5296,7 +5296,7 @@ FROM web_sales,
WHERE ws_bill_customer_sk = c_customer_sk
AND c_current_addr_sk = ca_address_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',
'81792' )
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"
WHERE
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
"customer_address"."ca_zip",
"customer_address"."ca_state"
@ -7585,7 +7585,7 @@ LIMIT 100;
-- TPC-DS 62
--------------------------------------
# execute: true
SELECT Substr(w_warehouse_name, 1, 20) AS "_col_0",
SELECT SUBSTRING(w_warehouse_name, 1, 20) AS "_col_0",
sm_type,
web_name,
Sum(CASE
@ -7622,15 +7622,15 @@ WHERE d_month_seq BETWEEN 1222 AND 1222 + 11
AND ws_warehouse_sk = w_warehouse_sk
AND ws_ship_mode_sk = sm_ship_mode_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,
web_name
ORDER BY Substr(w_warehouse_name, 1, 20),
ORDER BY SUBSTRING(w_warehouse_name, 1, 20),
sm_type,
web_name
LIMIT 100;
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",
"web_site"."web_name" AS "web_name",
SUM(
@ -7683,7 +7683,7 @@ JOIN "warehouse" AS "warehouse"
JOIN "web_site" AS "web_site"
ON "web_sales"."ws_web_site_sk" = "web_site"."web_site_sk"
GROUP BY
SUBSTR("warehouse"."w_warehouse_name", 1, 20),
SUBSTRING("warehouse"."w_warehouse_name", 1, 20),
"ship_mode"."sm_type",
"web_site"."web_name"
ORDER BY
@ -10638,7 +10638,7 @@ LIMIT 100;
# execute: true
SELECT c_last_name,
c_first_name,
Substr(s_city, 1, 30) AS "_col_2",
SUBSTRING(s_city, 1, 30) AS "_col_2",
ss_ticket_number,
amt,
profit
@ -10667,7 +10667,7 @@ FROM (SELECT ss_ticket_number,
WHERE ss_customer_sk = c_customer_sk
ORDER BY c_last_name,
c_first_name,
Substr(s_city, 1, 30),
SUBSTRING(s_city, 1, 30),
profit
LIMIT 100;
WITH "ms" AS (
@ -10701,7 +10701,7 @@ WITH "ms" AS (
SELECT
"customer"."c_last_name" AS "c_last_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"."amt" AS "amt",
"ms"."profit" AS "profit"
@ -10711,7 +10711,7 @@ JOIN "customer" AS "customer"
ORDER BY
"c_last_name",
"c_first_name",
SUBSTR("ms"."s_city", 1, 30),
SUBSTRING("ms"."s_city", 1, 30),
"profit"
LIMIT 100;
@ -11371,7 +11371,7 @@ LIMIT 100;
-- TPC-DS 85
--------------------------------------
# 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(wr_refunded_cash) AS "_col_2",
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 ws_net_profit BETWEEN 50 AND 250 ) )
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(wr_refunded_cash),
Avg(wr_fee)
LIMIT 100;
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_returns"."wr_refunded_cash") AS "_col_2",
AVG("web_returns"."wr_fee") AS "_col_3"
@ -12617,7 +12617,7 @@ ORDER BY
-- TPC-DS 99
--------------------------------------
# execute: true
SELECT Substr(w_warehouse_name, 1, 20) AS "_col_0",
SELECT SUBSTRING(w_warehouse_name, 1, 20) AS "_col_0",
sm_type,
cc_name,
Sum(CASE
@ -12654,15 +12654,15 @@ WHERE d_month_seq BETWEEN 1200 AND 1200 + 11
AND cs_warehouse_sk = w_warehouse_sk
AND cs_ship_mode_sk = sm_ship_mode_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,
cc_name
ORDER BY Substr(w_warehouse_name, 1, 20),
ORDER BY SUBSTRING(w_warehouse_name, 1, 20),
sm_type,
cc_name
LIMIT 100;
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",
"call_center"."cc_name" AS "cc_name",
SUM(
@ -12715,7 +12715,7 @@ JOIN "ship_mode" AS "ship_mode"
JOIN "warehouse" AS "warehouse"
ON "catalog_sales"."cs_warehouse_sk" = "warehouse"."w_warehouse_sk"
GROUP BY
SUBSTR("warehouse"."w_warehouse_name", 1, 20),
SUBSTRING("warehouse"."w_warehouse_name", 1, 20),
"ship_mode"."sm_type",
"call_center"."cc_name"
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",
),
(
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):
self.assertEqual(expression().sql(dialect[0] if dialect else None), sql)

View file

@ -1,14 +1,18 @@
import unittest
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
def diff_delta_only(source, target, matchings=None, **kwargs):
return diff(source, target, matchings=matchings, delta_only=True, **kwargs)
class TestDiff(unittest.TestCase):
def test_simple(self):
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
Insert(parse_one("a - b")), # the Sub node
@ -16,21 +20,21 @@ class TestDiff(unittest.TestCase):
)
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
],
)
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
],
)
self._validate_delta_only(
diff(
diff_delta_only(
parse_one("SELECT a FROM table_one"),
parse_one("SELECT a FROM table_two"),
),
@ -44,7 +48,9 @@ class TestDiff(unittest.TestCase):
def test_lambda(self):
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(
exp.Lambda(this=exp.to_identifier("a"), expressions=[exp.to_identifier("a")]),
@ -55,14 +61,16 @@ class TestDiff(unittest.TestCase):
def test_udf(self):
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"()')),
Remove(parse_one('"my.udf1"()')),
],
)
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, w)'),
),
@ -74,28 +82,28 @@ class TestDiff(unittest.TestCase):
def test_node_position_changed(self):
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
],
)
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
],
)
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
],
)
self._validate_delta_only(
diff(
diff_delta_only(
parse_one("SELECT aaaa OR bbbb OR cccc"),
parse_one("SELECT cccc OR bbbb OR aaaa"),
),
@ -120,7 +128,7 @@ class TestDiff(unittest.TestCase):
"""
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)")), # 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_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 = _delta_only(changes)
changes = diff_delta_only(parse_one(expr_src), parse_one(expr_tgt))
self.assertEqual(len(changes), 2)
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_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(
diff(expr_src, expr_tgt),
diff_delta_only(expr_src, expr_tgt),
[
Remove(parse_one("ROW_NUMBER()")), # 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")
self._validate_delta_only(
diff(expr_src, expr_tgt),
diff_delta_only(expr_src, expr_tgt),
[
Remove(expr_src),
Insert(expr_tgt),
@ -171,7 +178,7 @@ class TestDiff(unittest.TestCase):
)
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(3)),
@ -180,23 +187,20 @@ class TestDiff(unittest.TestCase):
)
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):
expr_src = parse_one("SELECT a FROM tbl")
expr_tgt = parse_one("SELECT a, tbl.b from tbl")
self._validate_delta_only(
diff(expr_src, expr_tgt),
diff_delta_only(expr_src, expr_tgt),
[
Insert(expression=exp.to_column("tbl.b")),
],
)
def _validate_delta_only(self, actual_diff, expected_delta):
actual_delta = _delta_only(actual_diff)
def _validate_delta_only(self, actual_delta, 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_TO_UNIX(a, 'format')"), exp.StrToUnix)
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("SQRT(a)"), exp.Sqrt)
self.assertIsInstance(parse_one("STDDEV(a)"), exp.Stddev)

View file

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